From 118980e02e59ff31871df59dce257075394f3533 Mon Sep 17 00:00:00 2001 From: Aaditya Dhruv Date: Sun, 25 Jan 2026 15:10:37 -0600 Subject: wip --- src/CMakeLists.txt | 9 +++- src/block.c | 55 ++++++++++++++++++++ src/block.h | 13 +++++ src/junkcraft.c | 148 +++++++++++------------------------------------------ src/shader.c | 63 +++++++++++++++++++++++ src/shader.h | 5 ++ src/util.c | 24 +++++++++ src/util.h | 4 ++ src/window.c | 41 +++++++++++++++ src/window.h | 26 ++++++++++ 10 files changed, 269 insertions(+), 119 deletions(-) create mode 100644 src/block.c create mode 100644 src/block.h create mode 100644 src/shader.c create mode 100644 src/shader.h create mode 100644 src/util.c create mode 100644 src/util.h create mode 100644 src/window.c create mode 100644 src/window.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0fcef0e..2286d1a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1 +1,8 @@ -add_executable(junkcraft junkcraft.h junkcraft.c glad.c) +add_executable(junkcraft + junkcraft.c + glad.c + shader.c + block.c + util.c + window.c +) diff --git a/src/block.c b/src/block.c new file mode 100644 index 0000000..e93ae6c --- /dev/null +++ b/src/block.c @@ -0,0 +1,55 @@ +#include "cglm/types.h" +#include "glad/glad.h" +#include "block.h" +#include "util.h" +#include "cglm/cglm.h" +#include "block.h" +#include + + +int block_init(vec3 pos, struct block* blk) { + // Store buffer data into struct + // Initialize vbo and ebo for block + memcpy(blk->coords, pos, sizeof(vec3)); + float vertices[] = { + 0.5f, 0.5f, 0.0f, // top-right + -0.5f, 0.5f, 0.0f, // top-left + -0.5f, -0.5f, 0.0f, // bottom-left + 0.5f, -0.5f, 0.0f, // bottom-right + }; + float colors[] = { + 1.0f, 0.0f, 0.0f, // r,g,b of first point. + 0.0f, 1.0f, 0.0f, // r,g,b of second point. + 0.0f, 0.0f, 1.0f, // r,g,b of third point. + 1.0f, 1.0f, 1.0f // r,g,b of fourth point. + }; + int vertex_order[] = { 1, 2, 3, 3, 0, 1 }; + + //TODO: + //1. Create VAO for mesh + //2. Create VBOs for vertices and colors + //3. Set EBO for index order + create_vbo(&blk->_vbo1, (void*)vertices, sizeof(float) * 12); + create_vbo(&blk->_vbo2, (void*)colors, sizeof(float) * 12); + create_ebo(&blk->_ebo, (void*)vertex_order, sizeof(int) * 6); + glGenVertexArrays(1, &blk->_vao); + glBindVertexArray(blk->_vao); + // Enable 2 attribs - position and color + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + // set vao_buffer to pos buffer obj + glBindBuffer(GL_ARRAY_BUFFER, blk->_vbo1); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + // set vao_buffer to color buffer obj + glBindBuffer(GL_ARRAY_BUFFER, blk->_vbo2); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, blk->_ebo); + return 0; +} + +// Register block vbos and ebos to context +int block_draw(struct block* blk) { + glBindVertexArray(blk->_vao); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + return 0; +} diff --git a/src/block.h b/src/block.h new file mode 100644 index 0000000..46607b4 --- /dev/null +++ b/src/block.h @@ -0,0 +1,13 @@ +#pragma once +#include "cglm/types.h" +#include "glad/glad.h" +struct block { + vec3 coords; + int type; + GLuint _vao; + GLuint _vbo1; + GLuint _vbo2; + GLuint _ebo; +}; +int block_init(vec3 pos, struct block* blk); +int block_draw(struct block* blk); diff --git a/src/junkcraft.c b/src/junkcraft.c index 0d27175..d914973 100644 --- a/src/junkcraft.c +++ b/src/junkcraft.c @@ -3,130 +3,42 @@ #include #include #include -#include -#include "SDL2/SDL.h" -#include "SDL2/SDL_video.h" #include "SDL2/SDL_render.h" #include "glad/glad.h" - -const float vertices[] = { - 0.0f, 0.5f, 0.0f, // x,y,z of first point. - 0.5f, -0.5f, 0.0f, // x,y,z of second point. - -0.5f, -0.5f, 0.0f // x,y,z of third point. -}; - - -const char* fragment_shader = -"#version 410 core\n" -"out vec4 frag_colour;" -"in vec3 color;" -"void main() {" -" frag_colour = vec4( color, 1.0 );" -"}"; - -const char* vertex_shader = -"#version 410 core\n" -"in vec3 vp;" -"out vec3 color;" -"void main() {" -" gl_Position = vec4( vp, 1.0 );" -" color = vp;" -"}"; - -GLuint shader_init() { - GLuint vs = glCreateShader( GL_VERTEX_SHADER ); -glShaderSource( vs, 1, &vertex_shader, NULL ); -glCompileShader( vs ); -GLuint fs = glCreateShader( GL_FRAGMENT_SHADER ); -glShaderSource( fs, 1, &fragment_shader, NULL ); -glCompileShader( fs ); -GLuint shader_program = glCreateProgram(); -glAttachShader( shader_program, fs ); -glAttachShader( shader_program, vs ); -glLinkProgram( shader_program ); -return shader_program; -} - -GLuint vbo; - -void quit(int _val) { - fprintf(stderr, "Quitting"); - exit(1); -} - -void gl_buffer_init() { - //tell opengl we want mem for 1 buffer object - glGenBuffers(1, &vbo); - // set aray_buffer to above - glBindBuffer(GL_ARRAY_BUFFER, vbo); - // copy vertex data to gpu memory - glBufferData(GL_ARRAY_BUFFER, 9* sizeof(float), vertices, GL_STATIC_DRAW); - // cleanup - glBindBuffer(GL_ARRAY_BUFFER, 0); +#include "shader.h" +#include "block.h" +#include "window.h" + +// Global OpenGL Context +GLuint shader_program; +int game_loop = 1; + +void draw(struct window* window, struct block* block) { + while (game_loop) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + // Quit game + if (event.type == SDL_QUIT) { + game_loop = 0; + } + } + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(shader_program); + block_draw(block); + SDL_RenderPresent(window->renderer); + } } int main() { - signal(SIGINT, quit); - SDL_Init(SDL_INIT_VIDEO); - // This will call SDL_GL_LoadLibrary so you don't need glad to do anything - SDL_Window* window = SDL_CreateWindow("Junkcraft", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL); - - SDL_GLContext* ctx = SDL_GL_CreateContext(window); - // Let GLAD use the SDL GetProcAddress loader instead of using its own - int version = gladLoadGLLoader(SDL_GL_GetProcAddress); - if (version == 0) { - printf("Failed to initialize OpenGL context\n"); + struct window window = {0}; + if (window_init(&window) != 0) { return -1; } - printf("Loaded OpenGL %d\n", version); - - - if (window == NULL) { - perror("Failed to create window!"); - SDL_DestroyWindow(window); - SDL_Quit(); - return -1; - } - - SDL_Renderer* render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); - if (render == NULL) { - perror("Failed to create renderer!"); - SDL_DestroyWindow(window); - SDL_Quit(); - return -1; - } - - // SDL_RenderClear(render); - // SDL_Rect rect = { 0, 0, 100, 100 }; - // SDL_SetRenderDrawColor(render, 255, 0, 0, SDL_ALPHA_OPAQUE); - SDL_ShowWindow(window); - // SDL_RenderFillRect(render, &rect); - - - gl_buffer_init(); - - GLuint array; - // Create VAO - glGenVertexArrays(1, &array); - glBindVertexArray(array); - // set array_buffer to pos buffer obj - glBindBuffer(GL_ARRAY_BUFFER, vbo); - /// allow vertex shader - // describe data and enable - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - // draw data as a triangle - //glDrawArrays(GL_TRIANGLES, 0, 3); - // set viewport - //glViewport(0, 0, 200, 100); - //final - GLuint shader_program = shader_init(); - while (1) { - glClear(GL_COLOR_BUFFER_BIT); - glUseProgram( shader_program ); - glBindVertexArray(array); - glDrawArrays(GL_TRIANGLES, 0, 3); - SDL_RenderPresent(render); - } + struct block blk = {0}; + vec3 pos = { 0, 0, 0 }; + block_init(pos, &blk); + shader_program = shader_init(); + draw(&window, &blk); + window_cleanup(&window); return 0; } diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..c78a7e5 --- /dev/null +++ b/src/shader.c @@ -0,0 +1,63 @@ +#include "shader.h" +#include +#include + + + +/** + * Simple method to read shaders from path and return a string + * containing the code. Function allocates memory which needs + * to be cleaned up + * @param path Path to shader GLSL file + * @return buf Contents of shader file as a string + */ +char* read_shader(char* path) { + FILE* file = fopen(path, "r"); + fseek(file, 0, SEEK_END); + int file_size = ftell(file); + rewind(file); + char* buf = malloc(file_size); + fread(buf, file_size, 1, file); + return buf; +} + +/** + * Compile some given shader code + * @param type The type of shader (GL_VERTEX_SHADER, GL_FRAGMENT_SHADER etc) + * @param code The string corresponding to the shader code + * @return shader The GLuint pointer to the compiled shader + */ +GLuint compile_shader(GLuint type, const char* code) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &code, NULL); + glCompileShader(shader); + return shader; +} + +/* + * Given a vertex and fragment shader, link and compile a shader program, + * returning the GLuint pointing to that program + * @param vs The vertex shader string, usually returend from read_shader + * @param fs The fragment shader string, usually returend from read_shader + * @return shader_program The pointer to the compiled shader + */ +GLuint create_shader_program(const char* vs, const char* fs) { + GLuint shader_program = glCreateProgram(); + GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vs); + GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fs); + glAttachShader(shader_program, fragment_shader); + glAttachShader(shader_program, vertex_shader); + glLinkProgram(shader_program); + return shader_program; +} + + +GLuint shader_init() { + char* shaders[2] = { "shaders/fragment.glsl", "shaders/vertex.glsl" }; + char* fragment_shader = read_shader(shaders[0]); + char* vertex_shader = read_shader(shaders[1]); + GLuint shader_program = create_shader_program(vertex_shader, fragment_shader); + free(vertex_shader); + free(fragment_shader); + return shader_program; +} diff --git a/src/shader.h b/src/shader.h new file mode 100644 index 0000000..c613708 --- /dev/null +++ b/src/shader.h @@ -0,0 +1,5 @@ +#include "glad/glad.h" + +//Load a vertex and framgent shader defined in +//the shaders/ directory. +GLuint shader_init(); diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..0a5d983 --- /dev/null +++ b/src/util.c @@ -0,0 +1,24 @@ +#include "util.h" + +void create_vbo(GLuint *vbo, void* buf, int size) { + //tell opengl we want mem for 1 buffer object + glGenBuffers(1, vbo); + // set aray_buffer to above + glBindBuffer(GL_ARRAY_BUFFER, *vbo); + // copy vertex data to gpu memory + glBufferData(GL_ARRAY_BUFFER, size, buf, GL_STATIC_DRAW); + // cleanup + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void create_ebo(GLuint *ebo, void* buf, int size) { + //tell opengl we want mem for 1 buffer object + glGenBuffers(1, ebo); + // set aray_buffer to above + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo); + // copy vertex data to gpu memory + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buf, GL_STATIC_DRAW); + // cleanup + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..81c9733 --- /dev/null +++ b/src/util.h @@ -0,0 +1,4 @@ +#pragma once +#include "glad/glad.h" +void create_vbo(GLuint *vbo, void* buf, int size); +void create_ebo(GLuint *ebo, void* buf, int size); diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..e3faff7 --- /dev/null +++ b/src/window.c @@ -0,0 +1,41 @@ +#include "window.h" +#include "glad/glad.h" +#include + +int window_init(struct window* window) { + SDL_Init(SDL_INIT_VIDEO); + // This will call SDL_GL_LoadLibrary so you don't need glad to do anything + window->window = SDL_CreateWindow("Junkcraft", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL); + + SDL_GLContext* ctx = SDL_GL_CreateContext(window->window); + // Let GLAD use the SDL GetProcAddress loader instead of using its own + int version = gladLoadGLLoader(SDL_GL_GetProcAddress); + if (version == 0) { + printf("Failed to initialize OpenGL context\n"); + return -1; + } + printf("Loaded OpenGL %s\n", glGetString(GL_VERSION)); + printf("System: %s\n", glGetString(GL_RENDERER)); + + + if (window == NULL) { + perror("Failed to create window!"); + SDL_DestroyWindow(window->window); + SDL_Quit(); + return -1; + } + + window->renderer = SDL_CreateRenderer(window->window, -1, SDL_RENDERER_ACCELERATED); + if (window->renderer == NULL) { + perror("Failed to create renderer!"); + SDL_DestroyWindow(window->window); + SDL_Quit(); + return -1; + } + SDL_ShowWindow(window->window); + return 0; +} +void window_cleanup(struct window* window) { + SDL_DestroyWindow(window->window); + SDL_Quit(); +} diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..9a8c942 --- /dev/null +++ b/src/window.h @@ -0,0 +1,26 @@ +#include "SDL2/SDL.h" +#include "SDL2/SDL_video.h" +#include "SDL2/SDL_render.h" + + +struct window { + SDL_Renderer* renderer; + SDL_Window* window; +}; + +/** + * Get a basic SDL window up and running. This also initializes the OpenGL context, sets up a renderer and stores all the relevant data in the window struct. Memory is managed externally. We usually don't even need to free that allocated memory because it lasts till program death. + * @param @out window destination window pointer + * @return 0 on success, -1 on failure + * + */ +int window_init(struct window* window); + + +/** + * Cleanup the allocated Window and quit SDL. Basically called when the user closes the window + * + * @param window Window to close + * + */ +void window_cleanup(struct window* window); -- cgit