aboutsummaryrefslogtreecommitdiff
path: root/platform/gl/gl.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/gl/gl.c')
-rw-r--r--platform/gl/gl.c203
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();
+}