diff options
Diffstat (limited to 'platform/gl/gl.c')
| -rw-r--r-- | platform/gl/gl.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/platform/gl/gl.c b/platform/gl/gl.c new file mode 100644 index 0000000..915c37c --- /dev/null +++ b/platform/gl/gl.c @@ -0,0 +1,203 @@ +// The OpenGL platform. Uses GLFW for an interface with the OS. The code +// quality here is meh. Things could be organized more into functions, but as +// for now, it works fine, and isn't worth improving immediately. + +#include <GLFW/glfw3.h> +#include <glad/glad.h> + +#include "common.h" +#include "teensy.h" +#include "platform.h" + +static char vert[] = + "#version 330 core\n" + "layout (location = 0) in vec2 v_pos;\n" + "layout (location = 1) in vec2 v_uv;\n" + "\n" + "out vec2 f_uv;\n" + "\n" + "void main() {\n" + " gl_Position = vec4(v_pos, 0.0, 1.0);\n" + " f_uv = v_uv;\n" + "}\n" +; + +static char frag[] = + "#version 330 core\n" + "\n" + "in vec2 f_uv;\n" + "\n" + "out vec4 color;\n" + "\n" + "uniform sampler2D tex;\n" + "\n" + "void main() {\n" + " color = texture2D(tex, f_uv);\n" + "}\n" +; + +struct gl_platform { + GLFWwindow *win; + GLuint vao; + GLuint vbo; + GLuint program; + GLint uniform_tex_loc; + GLuint screen_handle; +}; + +struct gl_platform p; + +static +GLuint compile_shader(GLenum type, const char *src) +{ + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + + int ok; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + if (!ok) { + char msg[1024]; + glGetShaderInfoLog(shader, 1024, NULL, msg); + ty_log_fatal(TY_PLATFORM_ERR, "failed to compile shader: %s", msg); + } + + return shader; +} + +void ty_platform_init(struct ty_ctx *ctx) +{ + if (glfwInit() < 0) + ty_log_fatal(TY_PLATFORM_ERR, "Could not init GLFW"); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + p.win = glfwCreateWindow( + ctx->creation_hints.win_width, + ctx->creation_hints.win_height, + ctx->creation_hints.win_title, + NULL, + NULL + ); + + if (!p.win) + ty_log_fatal(TY_PLATFORM_ERR, "Could not init GLFW window"); + + glfwMakeContextCurrent(p.win); + + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + ty_log_fatal(TY_PLATFORM_ERR, "Could not init GLAD"); + + struct ty_vec2 vertices[] = { + ty_vec2(-1, -1), ty_vec2(0, 1), + ty_vec2( 1, -1), ty_vec2(1, 1), + ty_vec2( 1, 1), ty_vec2(1, 0), + + ty_vec2(-1, -1), ty_vec2(0, 1), + ty_vec2( 1, 1), ty_vec2(1, 0), + ty_vec2(-1, 1), ty_vec2(0, 0), + }; + + glGenTextures(1, &p.screen_handle); + glBindTexture(GL_TEXTURE_2D, p.screen_handle); + + glGenVertexArrays(1, &p.vao); + glGenBuffers(1, &p.vbo); + + glBindVertexArray(p.vao); + + glBindBuffer(GL_ARRAY_BUFFER, p.vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer( + 0, + 2, GL_FLOAT, + GL_FALSE, + sizeof(struct ty_vec2) * 2, (void*)0 + ); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 1, + 2, GL_FLOAT, + GL_FALSE, + sizeof(struct ty_vec2) * 2, (void*)sizeof(struct ty_vec2) + ); + glEnableVertexAttribArray(1); + + p.program = glCreateProgram(); + GLuint vert_sh = compile_shader(GL_VERTEX_SHADER, vert); + GLuint frag_sh = compile_shader(GL_FRAGMENT_SHADER, frag); + glAttachShader(p.program, vert_sh); + glAttachShader(p.program, frag_sh); + glLinkProgram(p.program); + + glDeleteShader(vert_sh); + glDeleteShader(frag_sh); + + int ok; + glGetProgramiv(p.program, GL_LINK_STATUS, &ok); + if (!ok) { + char msg[1024]; + glGetProgramInfoLog(p.program, 1024, NULL, msg); + ty_log_fatal(TY_PLATFORM_ERR, "failed to link shaders: %s", msg); + } + + p.uniform_tex_loc = glGetUniformLocation(p.program, "texture"); +} + +void ty_platform_deinit(void) +{ + glfwDestroyWindow(p.win); + glfwTerminate(); +} + +void ty_platform_frame(struct ty_image img) +{ + glfwPollEvents(); + + int win_width, win_height; + glfwGetWindowSize(p.win, &win_width, &win_height); + + glViewport(0, 0, win_width, win_height); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, p.screen_handle); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + img.width, img.height, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + img.data + ); + glGenerateMipmap(GL_TEXTURE_2D); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(p.program); + glUniform1i(p.uniform_tex_loc, 0); + + glBindVertexArray(p.vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glfwSwapBuffers(p.win); + + if (glfwGetKey(p.win, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + glfwSetWindowShouldClose(p.win, true); + } +} + +bool ty_platform_os_wants_quit(void) +{ + return glfwWindowShouldClose(p.win); +} + +double ty_platform_get_time(void) +{ + return glfwGetTime(); +} |
