summaryrefslogtreecommitdiff
path: root/source/sdlmain.cpp
diff options
context:
space:
mode:
authortalha <talha@talhaamir.xyz>2025-11-27 13:18:57 +0500
committertalha <talha@talhaamir.xyz>2025-11-27 13:18:57 +0500
commit0b3d69976819219e71350b6a988d1704fd5f0746 (patch)
tree3511564cb2cb3b10697dc997260479a14540d706 /source/sdlmain.cpp
Added files to git.HEADmain
Current State: - hot reloading - math library (calcify) - triangle rendering (unbatched) - orthographic projection (no camera) - layer isolation setup (platform vs game)
Diffstat (limited to 'source/sdlmain.cpp')
-rw-r--r--source/sdlmain.cpp319
1 files changed, 319 insertions, 0 deletions
diff --git a/source/sdlmain.cpp b/source/sdlmain.cpp
new file mode 100644
index 0000000..372758a
--- /dev/null
+++ b/source/sdlmain.cpp
@@ -0,0 +1,319 @@
+#include <stdio.h>
+#include <unistd.h>
+
+#include <SDL2/SDL.h>
+#include <glad/glad.h>
+
+#include "glad.c"
+
+#include "fswatcher/fswatcher.h"
+#include "fswatcher/fswatcher.cpp"
+
+#include "core.h"
+
+#if defined(_WIN32)
+#define BUILD_GAME() system("build_game.bat")
+#else
+#define BUILD_GAME() system("sh build_game.sh")
+#endif
+
+// GAME LIBRARY FUNCTIONS
+typedef void (*GameHandleEvent)(GameState*, GameEventType);
+typedef void (*GameSetup)(GameState*);
+typedef void (*GameUpdateAndRender)(GameState*);
+
+struct GameLayer {
+ void *lib;
+ GameHandleEvent handle_event;
+ GameSetup setup;
+ GameUpdateAndRender update_and_render;
+};
+internal GameLayer game_layer;
+
+bool load_game_layer()
+{
+ // @hack: recompile game here before load object call
+ BUILD_GAME();
+
+ SDL_UnloadObject(game_layer.lib);
+ game_layer.lib = SDL_LoadObject("build/libgame.so");
+ if (game_layer.lib == NULL) {
+ return false;
+ }
+ game_layer.handle_event =
+ (GameHandleEvent)SDL_LoadFunction(game_layer.lib,
+ "game_handle_event");
+ game_layer.setup =
+ (GameSetup)SDL_LoadFunction(game_layer.lib,
+ "game_setup");
+ game_layer.update_and_render =
+ (GameUpdateAndRender)SDL_LoadFunction(game_layer.lib,
+ "game_update_and_render");
+
+ return true;
+}
+
+bool game_file_update(fswatcher_event_handler *handler,
+ fswatcher_event_type evtype,
+ const char *src,
+ const char *dst) {
+ return load_game_layer();
+}
+
+//bool game_shader_update(fswatcher_event_handler *handler,
+// fswatcher_event_type evtype,
+// const char *src,
+// const char *dst) {
+//}
+
+u32 gl_shader_program(char *vs, char *fs)
+{
+ //==============
+ // Vertex Shader
+ u32 handle_vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(handle_vs, 1, &vs, NULL);
+ glCompileShader(handle_vs);
+
+ i32 vertex_compiled;
+ glGetShaderiv(handle_vs,
+ GL_COMPILE_STATUS,
+ &vertex_compiled);
+
+ if (vertex_compiled != GL_TRUE)
+ {
+ i32 log_length = 0;
+ char message[1024];
+
+ glGetShaderInfoLog(handle_vs, 1024, &log_length, message);
+
+ fprintf(stderr, "===Error compiling vertex shader===\n");
+ fprintf(stderr, "%s\n", message);
+ }
+
+ //================
+ // Fragment Shader
+ u32 handle_fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(handle_fs, 1, &fs, NULL);
+ glCompileShader(handle_fs);
+
+ i32 fragment_compiled;
+ glGetShaderiv(handle_fs,
+ GL_COMPILE_STATUS,
+ &fragment_compiled);
+
+ if (fragment_compiled != GL_TRUE)
+ {
+ i32 log_length = 0;
+ char message[1024];
+
+ glGetShaderInfoLog(handle_fs, 1024, &log_length, message);
+
+ fprintf(stderr, "===Error compiling fragment shader===\n");
+ fprintf(stderr, "%s\n", message);
+ }
+
+ //===============
+ // Shader Program
+ u32 shader_program = glCreateProgram();
+
+ glAttachShader(shader_program, handle_vs);
+ glAttachShader(shader_program, handle_fs);
+ glLinkProgram(shader_program);
+
+ GLint program_compiled;
+ glGetProgramiv(shader_program, GL_LINK_STATUS, &program_compiled);
+
+ if (program_compiled != GL_TRUE)
+ {
+ i32 log_length = 0;
+ char message[1024];
+
+ glGetShaderInfoLog(shader_program, 1024, &log_length, message);
+
+ fprintf(stderr, "===Error linking shader program===\n");
+ fprintf(stderr, "%s\n", message);
+ }
+
+ glDeleteShader(handle_vs);
+ glDeleteShader(handle_fs);
+
+ return shader_program;
+}
+
+u32 gl_shader_program_from_path(const char *vspath, const char *fspath)
+{
+ size_t read_count;
+ char *vs = (char *)SDL_LoadFile(vspath, &read_count);
+ if (vs == NULL)
+ {
+ const char *error_msg = SDL_GetError();
+ fprintf(stderr, "Error loading file %s: %s\n", vspath, error_msg);
+ }
+
+ read_count = 0;
+ char *fs = (char *)SDL_LoadFile(fspath, &read_count);
+ if (fs == NULL)
+ {
+ const char *error_msg = SDL_GetError();
+ fprintf(stderr, "Error loading file %s: %s\n", fspath, error_msg);
+ }
+
+ u32 shader_program = gl_shader_program(vs, fs);
+
+ SDL_free(vs);
+ SDL_free(fs);
+
+ return shader_program;
+}
+
+int main(int argc, char *argv[])
+{
+ i32 raw_width = 1920;
+ i32 raw_height = 1080;
+ i32 dpi_width;
+ i32 dpi_height;
+ r32 scale_width;
+ r32 scale_height;
+ i32 width;
+ i32 height;
+
+ GameState state = {};
+
+ if (SDL_Init(SDL_INIT_VIDEO) != 0)
+ {
+ printf("Error initialising SDL2: %s\n", SDL_GetError());
+ return 0;
+ };
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
+ // initialise window with opengl flag
+ SDL_Window *window = SDL_CreateWindow("SDL Test",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ raw_width,
+ raw_height,
+ SDL_WINDOW_OPENGL |
+ SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI);
+
+ // create an opengl context
+ SDL_GLContext context = SDL_GL_CreateContext(window);
+ if (!context)
+ {
+ printf("OpenGL context creation failed: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ // calculate correct window size due to scaling
+ SDL_GL_GetDrawableSize(window, &dpi_width, &dpi_height);
+
+ scale_width = (r32)raw_width/(r32)dpi_width;
+ scale_height = (r32)raw_height/(r32)dpi_height;
+
+ state.width = raw_width * scale_width;
+ state.height = raw_height * scale_height;
+
+ SDL_SetWindowSize(window, state.width, state.height);
+
+ // load glad
+ if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
+ printf("Failed to initialize Glad\n");
+ return 1;
+ }
+
+ SDL_GL_SetSwapInterval(1);
+
+ u32 shader_program = gl_shader_program_from_path("./shaders/quad.vs.glsl",
+ "./shaders/quad.fs.glsl");
+
+ state.triangle_sp = shader_program;
+ glUseProgram(state.triangle_sp);
+
+ // @func: gl_setup_triangle
+ {
+ GLfloat vertices[9] = {
+ -0.5f, -0.5f, 0.0f,
+ 0.5f, -0.5f, 0.0f,
+ 0.0f, 0.5f, 0.0f
+ };
+
+ GLuint VBO, VAO;
+ glGenVertexArrays(1, &VAO);
+ glGenBuffers(1, &VBO);
+
+ glBindVertexArray(VAO);
+
+ glBindBuffer(GL_ARRAY_BUFFER, VBO);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
+ glEnableVertexAttribArray(0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+
+ state.triangle_vao = VAO;
+ state.triangle_vbo = VBO;
+ }
+ glUseProgram(0);
+
+ // add file watcher
+ fswatcher_t game_watcher = fswatcher_create(FSWATCHER_CREATE_DEFAULT,
+ FSWATCHER_EVENT_MODIFY,
+ "source/game", NULL);
+ fswatcher_event_handler game_file_update_handler;
+ game_file_update_handler.callback = game_file_update;
+ // load game layer
+ if (!load_game_layer()) {
+ return -1;
+ }
+
+ game_layer.setup(&state);
+
+ for(;;)
+ {
+ SDL_Event ev;
+ while(SDL_PollEvent(&ev))
+ {
+ if (ev.type == SDL_QUIT)
+ {
+ return 0;
+ }
+ if (ev.type == SDL_WINDOWEVENT)
+ {
+ if (ev.window.event == SDL_WINDOWEVENT_RESIZED)
+ {
+ state.width = ev.window.data1;
+ state.height = ev.window.data2;
+ game_layer.handle_event(&state, GAME_EVENT_RESIZE);
+ }
+ }
+ if (ev.type == SDL_KEYDOWN) {
+ if (ev.key.keysym.sym == SDLK_SPACE) {
+ }
+ }
+ }
+ fswatcher_poll(game_watcher, &game_file_update_handler, NULL);
+
+ // opengl rendering code here
+ game_layer.update_and_render(&state);
+ SDL_GL_SwapWindow(window);
+ }
+
+ // filewatcher
+ fswatcher_destroy(game_watcher);
+
+ // opengl free calls
+ glDeleteVertexArrays(1, &state.triangle_vao);
+ glDeleteBuffers(1, &state.triangle_vbo);
+ glDeleteProgram(state.triangle_sp);
+
+ // sdl free calls
+ SDL_GL_DeleteContext(context);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+ return 0;
+}
+