summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authororangerot <orangerot@orangerot.dev>2025-10-13 21:07:46 +0200
committerorangerot <orangerot@orangerot.dev>2025-10-13 21:07:46 +0200
commit37a07856a7b6592cbe63d1caf3a610f7867e0bf9 (patch)
tree3c271c100c8c4a236a9e3d963c200fd43e1745be /main.c
parentd0aadff9a41b15aed3a8b0c8e90130805f16c609 (diff)
feat: render texture using glfw
Diffstat (limited to 'main.c')
-rw-r--r--main.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2a94c73
--- /dev/null
+++ b/main.c
@@ -0,0 +1,232 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <spng.h>
+
+#include <glad/glad.h>
+#include <GLFW/glfw3.h>
+#include <math.h>
+
+unsigned int SCR_WIDTH = 800;
+unsigned int SCR_HEIGHT = 600;
+
+typedef struct decoded_image {
+ size_t width;
+ size_t height;
+ uint32_t *buf;
+ ssize_t buf_size;
+} decoded_image;
+
+struct decoded_image canvas = {
+ .width = 256,
+ .height = 240,
+ .buf_size = 256 * 240,
+};
+
+const char *vertex_shader_source =
+ "#version 330 core\n"
+ "layout (location = 0) in vec3 aPos;\n"
+ "layout (location = 1) in vec3 aColor;\n"
+ "layout (location = 2) in vec2 aTexCoord;\n"
+ "\n"
+ "out vec3 ourColor;\n"
+ "out vec2 TexCoord;\n"
+ "\n"
+ "uniform mat4 transform;"
+ "\n"
+ "void main() {\n"
+ " gl_Position = transform * vec4(aPos, 1.0);\n"
+ " ourColor = aColor;\n"
+ " TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\n"
+ "}\n";
+
+const char *fragment_shader_source =
+ "#version 330 core\n"
+ "out vec4 FragColor;\n"
+ "\n"
+ "in vec3 ourColor;\n"
+ "in vec2 TexCoord;\n"
+ "\n"
+ "uniform sampler2D texture1;\n"
+ "\n"
+ "void main() {\n"
+ " FragColor = texture(texture1, TexCoord);\n"
+ "}\n";
+
+void character_callback(GLFWwindow* window, unsigned int codepoint) {
+ printf("%c\n", codepoint);
+}
+
+void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
+ if (action != GLFW_PRESS) return;
+ switch (key) {
+ case GLFW_KEY_ENTER:
+ break;
+ case GLFW_KEY_BACKSPACE:
+ break;
+ }
+}
+
+void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
+ glViewport(0, 0, width, height);
+ SCR_WIDTH = width;
+ SCR_HEIGHT = height;
+}
+
+const uint32_t COLOR_RGBA = 0xFF21FF00;
+
+int main(int argc, const char *argv[]) {
+
+ canvas.buf = malloc(canvas.buf_size * sizeof(int));
+ for (int i = 0; i < canvas.buf_size; i++) canvas.buf[i] = i;
+
+ glfwInit();
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+#ifdef __APPLE__
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+
+ GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "202-anything", NULL, NULL);
+ if (window == NULL) {
+ printf("Failed to create GLFW window\n");
+ glfwTerminate();
+ return -1;
+ }
+ glfwMakeContextCurrent(window);
+ glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
+ glfwSetCharCallback(window, character_callback);
+ glfwSetKeyCallback(window, key_callback);
+
+ if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
+ printf("Failed to initialize GLAD\n");
+ return -1;
+ }
+
+ GLint success;
+ GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex_shader, 1, (const char **)&vertex_shader_source, NULL);
+ glCompileShader(vertex_shader);
+ glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
+
+ if(success == GL_FALSE) {
+ char infoLog[512];
+ glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
+ fprintf(stderr, "Shader compilation error: %s\n", infoLog);
+ glDeleteShader(vertex_shader);
+ return 1;
+ }
+
+ GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment_shader, 1, (const char **)&fragment_shader_source, NULL);
+ glCompileShader(fragment_shader);
+ glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
+
+ if(success == GL_FALSE) {
+ char infoLog[512];
+ glGetShaderInfoLog(fragment_shader, 512, NULL, infoLog);
+ fprintf(stderr, "Shader compilation error: %s\n", infoLog);
+ glDeleteShader(fragment_shader);
+ return 1;
+ }
+
+ GLuint shader_program = glCreateProgram();
+ glAttachShader(shader_program, vertex_shader);
+ glAttachShader(shader_program, fragment_shader);
+ glLinkProgram(shader_program);
+
+ float vertices[] = {
+ // positions // colors // texture coords
+ 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
+ -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
+ -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
+ };
+ unsigned int indices[] = {
+ 0, 1, 3, // first triangle
+ 1, 2, 3 // second triangle
+ };
+ unsigned int VBO, VAO, EBO;
+ glGenVertexArrays(1, &VAO);
+ glGenBuffers(1, &VBO);
+ glGenBuffers(1, &EBO);
+
+ glBindVertexArray(VAO);
+
+ glBindBuffer(GL_ARRAY_BUFFER, VBO);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
+
+ // position attribute
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ // color attribute
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
+ glEnableVertexAttribArray(1);
+ // texture coord attribute
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
+ glEnableVertexAttribArray(2);
+
+ unsigned int texture;
+ // texture 1
+ // ---------
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ // set the texture wrapping parameters
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ // set texture filtering parameters
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, canvas.width, canvas.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, canvas.buf);
+
+ glUseProgram(shader_program);
+ glUniform1i(glGetUniformLocation(shader_program, "texture1"), 0);
+
+ while (!glfwWindowShouldClose(window)) {
+ if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
+ glfwSetWindowShouldClose(window, 1);
+
+ glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // bind textures on corresponding texture units
+ glActiveTexture(GL_TEXTURE);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ float scale_x = fmin(
+ (float) SCR_HEIGHT / SCR_WIDTH * (float) canvas.height / canvas.width,
+ 1.0
+ );
+ float scale_y = fmin((float) SCR_WIDTH / SCR_HEIGHT * (float) canvas.width / canvas.height,
+ 1.0
+ );
+
+ float m[] = {
+ 2.0 * scale_x, 0.0, 0.0, 0.0,
+ 0.0, 2.0 * scale_y, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0,
+ };
+
+ // render container
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, canvas.width, canvas.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, canvas.buf);
+ glUseProgram(shader_program);
+ glUniform1i(glGetUniformLocation(shader_program, "texture1"), 0);
+ glUniformMatrix4fv(glGetUniformLocation(shader_program, "transform"), 1, GL_FALSE, m);
+
+ glBindVertexArray(VAO);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+
+ glfwSwapBuffers(window);
+ glfwPollEvents();
+ }
+
+ glfwTerminate();
+
+ return 0;
+}