diff --git a/game/Makefile b/game/Makefile index a5bb3d7..cf3ae1a 100644 --- a/game/Makefile +++ b/game/Makefile @@ -1,5 +1,6 @@ -SRC=src/main.c src/program.c src/resources.c src/camera.c \ - src/chunk/chunk.c src/chunk/mesh.c src/flags.c src/texture.c src/chunk/manager.c +SRC=src/main.c src/program.c src/resources.c src/camera.c src/chunk/chunk.c \ + src/chunk/mesh.c src/flags.c src/texture.c src/chunk/manager.c \ + src/event/manager.c src/event/handlers.c src/state.c src/graphics.c OBJ=$(SRC:.c=.o) CFLAGS=-Werror -Wextra -Wall `pkg-config --cflags sdl3 sdl3-image cglm gl glib-2.0` diff --git a/game/src/chunk/chunk.h b/game/src/chunk/chunk.h index 75af918..9115a6b 100644 --- a/game/src/chunk/chunk.h +++ b/game/src/chunk/chunk.h @@ -6,7 +6,7 @@ #include "../util.h" -#define CHUNK_DIM 16 +#define CHUNK_DIM 32 #define CHUNK_SIZE (CHUNK_DIM*CHUNK_DIM) #define INDEX(x, z) (CHUNK_DIM * (z) + (x)) diff --git a/game/src/chunk/manager.c b/game/src/chunk/manager.c index d1539ac..4720fa4 100644 --- a/game/src/chunk/manager.c +++ b/game/src/chunk/manager.c @@ -1,7 +1,7 @@ #include "manager.h" -/* TODO: switch from string keys to struct keys or some other - stuff. */ +/* TODO: perhaps render the chunks in a circle, not a square, around + the player? */ ChunkManager chunk_manager; diff --git a/game/src/chunk/manager.h b/game/src/chunk/manager.h index 9cff0fb..9996671 100644 --- a/game/src/chunk/manager.h +++ b/game/src/chunk/manager.h @@ -7,7 +7,7 @@ #include "chunk.h" #include "mesh.h" -#define RENDER_DISTANCE 3 +#define RENDER_DISTANCE 8 typedef struct ChunkManager { diff --git a/game/src/event/handlers.c b/game/src/event/handlers.c new file mode 100644 index 0000000..9a1651b --- /dev/null +++ b/game/src/event/handlers.c @@ -0,0 +1,76 @@ +#include "handlers.h" + +extern GameState game_state; +extern GameFlags game_flags; + +void +handlers_init () +{ + EventManager_add_SDL_handler (handler_lookaround); + EventManager_add_SDL_handler (handler_movement); +} + +void +handler_lookaround (SDL_Event *event) +{ + if (event->type == SDL_EVENT_MOUSE_MOTION && game_flags.can_free_look) + { + game_state.camera.rotation[0] -= event->motion.xrel / 100.f; + game_state.camera.rotation[1] -= event->motion.yrel / 100.f; + game_state.camera.rotation[1] = + CLAMP (game_state.camera.rotation[1], -M_PI / 2 + 0.025, M_PI / 2 - 0.025); + } +} + +void +handler_movement (SDL_Event *event) +{ + if (event->type == SDL_EVENT_KEY_DOWN) + { + switch (event->key.key) + { + case SDLK_W: + game_flags.moving_forward = 1; + break; + case SDLK_A: + game_flags.moving_left = 1; + break; + case SDLK_S: + game_flags.moving_backward = 1; + break; + case SDLK_D: + game_flags.moving_right = 1; + break; + case SDLK_F1: + game_flags.wireframe_enabled = !game_flags.wireframe_enabled; + break; + case SDLK_F2: + int active_program; + glGetIntegerv (GL_CURRENT_PROGRAM, &active_program); + program_print (active_program); + break; + case SDLK_F3: + Camera_print (&game_state.camera); + break; + } + } + + if (event->type == SDL_EVENT_KEY_UP) + { + switch (event->key.key) + { + case SDLK_W: + game_flags.moving_forward = 0; + break; + case SDLK_A: + game_flags.moving_left = 0; + break; + case SDLK_S: + game_flags.moving_backward = 0; + break; + case SDLK_D: + game_flags.moving_right = 0; + break; + } + } +} diff --git a/game/src/event/handlers.h b/game/src/event/handlers.h new file mode 100644 index 0000000..632f6c6 --- /dev/null +++ b/game/src/event/handlers.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include "manager.h" +#include "../camera.h" +#include "../flags.h" +#include "../program.h" +#include "../state.h" + +void handlers_init (); +void handler_lookaround (SDL_Event *event); +void handler_movement (SDL_Event *event); diff --git a/game/src/event/manager.c b/game/src/event/manager.c new file mode 100644 index 0000000..16e75c0 --- /dev/null +++ b/game/src/event/manager.c @@ -0,0 +1,24 @@ +#include "manager.h" + +EventManager event_manager; + +void +EventManager_add_SDL_handler (SDLHandler h) +{ + event_manager.sdl_handlers = g_slist_append (event_manager.sdl_handlers, h); +} + + +void +em_handle_sdl_internal (gpointer data, gpointer userdata) +{ + SDLHandler handler = data; + SDL_Event *event = userdata; + handler (event); +} + +void +EventManager_handle_SDL_Event (SDL_Event *event) +{ + g_slist_foreach (event_manager.sdl_handlers, em_handle_sdl_internal, event); +} diff --git a/game/src/event/manager.h b/game/src/event/manager.h new file mode 100644 index 0000000..3c19b45 --- /dev/null +++ b/game/src/event/manager.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include +#include + +#include "../util.h" + +typedef struct EventManager +{ + GSList *sdl_handlers; +} EventManager; + +typedef void (*SDLHandler) (SDL_Event *event); + +void EventManager_add_SDL_handler (SDLHandler handler); +void EventManager_handle_SDL_Event (SDL_Event *event); diff --git a/game/src/graphics.c b/game/src/graphics.c new file mode 100644 index 0000000..dd415e8 --- /dev/null +++ b/game/src/graphics.c @@ -0,0 +1,84 @@ +#include "graphics.h" + +GraphicsContext gfx; + +extern ChunkManager chunk_manager; +extern GameState game_state; +extern Resources resources; + +void +GraphicsContext_init () +{ + if (!SDL_Init (SDL_INIT_VIDEO)) + { + FATAL ("Couldn't initialize SDL: %s", SDL_GetError ()); + } + + gfx.window = SDL_CreateWindow (GAME_NAME, 640, 480, SDL_WINDOW_OPENGL); + + if (!gfx.window) + { + FATAL ("Couldn't create window: %s", SDL_GetError ()); + } + + /* We use OpenGL ES 2.0. It should support everything, and it's more + than enough for the game. */ + SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); + + gfx.gl_context = SDL_GL_CreateContext (gfx.window); + + if (!gfx.gl_context) + { + FATAL ("Couldn't create OpenGL context: %s", SDL_GetError ()); + } + + SDL_GL_MakeCurrent (gfx.window, gfx.gl_context); + SDL_SetWindowRelativeMouseMode (gfx.window, true); + + INFO ("Renderer: %s", glGetString (GL_RENDERER)); + INFO ("OpenGL version: %s", glGetString (GL_VERSION)); + INFO ("GLSL version: %s", glGetString (GL_SHADING_LANGUAGE_VERSION)); + INFO ("Max vertex attributes: %d", GL_MAX_VERTEX_ATTRIBS); + + glViewport(0, 0, 640, 480); + glClearColor (0, 0.3, 0.8, 1); + + glEnable (GL_CULL_FACE); + glEnable (GL_DEPTH_TEST); +} + +void +GraphicsContext_render () +{ + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + program_use (resources.programs[1]); + + mat4 projection, view; + Camera_get_projection (&game_state.camera, 640.0 / 480.0, projection); + Camera_get_view (&game_state.camera, view); + + program_set_mat4 (resources.programs[1], "projection", projection); + program_set_mat4 (resources.programs[1], "view", view); + + for (size_t i = 0; i < resources.textures_len; ++i) + { + glActiveTexture (GL_TEXTURE0 + i); + glBindTexture (GL_TEXTURE_2D, resources.textures[i]); + } + + ChunkManager_render (game_state.camera.position[0], game_state.camera.position[2], resources.programs[1]); + + glBindTexture (GL_TEXTURE_2D, 0); + + SDL_GL_SwapWindow (gfx.window); +} + +void +GraphicsContext_free () +{ + SDL_GL_DestroyContext (gfx.gl_context); + SDL_DestroyWindow (gfx.window); +} diff --git a/game/src/graphics.h b/game/src/graphics.h new file mode 100644 index 0000000..37daaad --- /dev/null +++ b/game/src/graphics.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "util.h" +#include "chunk/manager.h" +#include "state.h" +#include "resources.h" + +typedef struct GraphicsContext +{ + SDL_Window *window; + SDL_GLContext gl_context; +} GraphicsContext; + +void GraphicsContext_init (); +void GraphicsContext_render (); +void GraphicsContext_free (); diff --git a/game/src/main.c b/game/src/main.c index 4f0adb3..b7d3885 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -1,236 +1,62 @@ #define SDL_MAIN_USE_CALLBACKS 1 -#include #include #include +#include "event/manager.h" +#include "event/handlers.h" #include "chunk/manager.h" #include "state.h" -#include "flags.h" -#include "camera.h" #include "resources.h" - -/* TODO: switch back to cglm.h, since it's faster or something */ - -static SDL_Window *window = NULL; -static SDL_GLContext context = NULL; +#include "graphics.h" extern GameState game_state; extern GameFlags game_flags; +extern EventManager event_manager; +extern GraphicsContext gfx; extern Resources resources; extern ChunkManager chunk_manager; -static Camera camera; - SDL_AppResult SDL_AppInit (void **appstate, int argc, char **argv) { - (void) appstate; (void) argc; (void) argv; + UNUSED (appstate, argc, argv); SDL_SetAppMetadata (GAME_NAME, GAME_VERSION, "eur.chopininteractive.wschod-game"); - - if (!SDL_Init (SDL_INIT_VIDEO)) - { - FATAL ("Couldn't initialize SDL: %s", SDL_GetError ()); - } - - window = SDL_CreateWindow (GAME_NAME, 640, 480, SDL_WINDOW_OPENGL); - - if (!window) - { - FATAL ("Couldn't create window: %s", SDL_GetError ()); - } - - /* We use OpenGL ES 2.0. It should support everything, and it's more - than enough for the game. */ - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); - - context = SDL_GL_CreateContext (window); - - if (!context) - { - FATAL ("Couldn't create OpenGL context: %s", SDL_GetError ()); - } - - SDL_GL_MakeCurrent (window, context); - SDL_SetWindowRelativeMouseMode (window, true); - - INFO ("Renderer: %s", glGetString (GL_RENDERER)); - INFO ("OpenGL version: %s", glGetString (GL_VERSION)); - INFO ("GLSL version: %s", glGetString (GL_SHADING_LANGUAGE_VERSION)); - INFO ("Max vertex attributes: %d", GL_MAX_VERTEX_ATTRIBS); - - glViewport(0, 0, 640, 480); - glClearColor (0, 0.3, 0.8, 1); - - glEnable (GL_CULL_FACE); - glEnable (GL_DEPTH_TEST); - - /* Initialize and load resources. */ + GraphicsContext_init (); + handlers_init (); Resources_init (); ChunkManager_init (); - - program_use (resources.programs[1]); - int arr[5] = { 0, 1, 2, 3, 4 }; - program_set_int_array (resources.programs[1], "materials", 5, arr); - - /* Set up game state. */ - game_state.last_time = SDL_GetTicks (); - + GameState_init (SDL_GetTicks ()); /* Set some basic game flags for testing. */ game_flags.can_free_look = 1; game_flags.wireframe_enabled = 0; - - /* Initialize the default camera. */ - camera = Camera_default (); - + return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent (void *appstate, SDL_Event *event) { - (void) appstate; + UNUSED (appstate); if (event->type == SDL_EVENT_QUIT) { return SDL_APP_SUCCESS; } - if (event->type == SDL_EVENT_MOUSE_MOTION && game_flags.can_free_look) - { - camera.rotation[0] -= event->motion.xrel / 100.f; - camera.rotation[1] -= event->motion.yrel / 100.f; - camera.rotation[1] = - CLAMP (camera.rotation[1], -M_PI / 2 + 0.025, M_PI / 2 - 0.025); - } - - if (event->type == SDL_EVENT_KEY_DOWN) - { - switch (event->key.key) - { - case SDLK_W: - game_flags.moving_forward = 1; - break; - case SDLK_A: - game_flags.moving_left = 1; - break; - case SDLK_S: - game_flags.moving_backward = 1; - break; - case SDLK_D: - game_flags.moving_right = 1; - break; - case SDLK_F1: - game_flags.wireframe_enabled = !game_flags.wireframe_enabled; - break; - case SDLK_F2: - int active_program; - glGetIntegerv (GL_CURRENT_PROGRAM, &active_program); - program_print (active_program); - break; - case SDLK_F3: - Camera_print (&camera); - break; - } - } - - if (event->type == SDL_EVENT_KEY_UP) - { - switch (event->key.key) - { - case SDLK_W: - game_flags.moving_forward = 0; - break; - case SDLK_A: - game_flags.moving_left = 0; - break; - case SDLK_S: - game_flags.moving_backward = 0; - break; - case SDLK_D: - game_flags.moving_right = 0; - break; - } - } - + EventManager_handle_SDL_Event (event); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate (void *appstate) { - (void) appstate; + UNUSED (appstate); - /* Caluclate stuff per frame. */ - int now = SDL_GetTicks (); - game_state.delta_time = (now - game_state.last_time) / 1000.0; - game_state.last_time = now; - - if (game_flags.moving_forward) - { - vec3 dir, change, new_pos; - Camera_get_direction (&camera, dir); - glm_vec3_scale (dir, game_state.delta_time * 5, change); - glm_vec3_add (camera.position, change, new_pos); - glm_vec3_copy (new_pos, camera.position); - } - - if (game_flags.moving_backward) - { - vec3 dir, change, new_pos; - Camera_get_direction (&camera, dir); - glm_vec3_scale (dir, game_state.delta_time * 5, change); - glm_vec3_sub (camera.position, change, new_pos); - glm_vec3_copy (new_pos, camera.position); - } - - if (game_flags.moving_right) - { - vec3 right, change, new_pos; - Camera_get_right (&camera, right); - glm_vec3_scale (right, game_state.delta_time * 5, change); - glm_vec3_add (camera.position, change, new_pos); - glm_vec3_copy (new_pos, camera.position); - } - - if (game_flags.moving_left) - { - vec3 right, change, new_pos; - Camera_get_right (&camera, right); - glm_vec3_scale (right, game_state.delta_time * 5, change); - glm_vec3_sub (camera.position, change, new_pos); - glm_vec3_copy (new_pos, camera.position); - } - - ChunkManager_update (camera.position[0], camera.position[2]); - - /* Render stuff. */ - - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - program_use (resources.programs[1]); - - mat4 projection, view; - Camera_get_projection (&camera, 640.0 / 480.0, projection); - Camera_get_view (&camera, view); - - program_set_mat4 (resources.programs[1], "projection", projection); - program_set_mat4 (resources.programs[1], "view", view); - - for (size_t i = 0; i < resources.textures_len; ++i) - { - glActiveTexture (GL_TEXTURE0 + i); - glBindTexture (GL_TEXTURE_2D, resources.textures[i]); - } - - ChunkManager_render (camera.position[0], camera.position[2], resources.programs[1]); - - glBindTexture (GL_TEXTURE_2D, 0); - - SDL_GL_SwapWindow (window); + ChunkManager_update (game_state.camera.position[0], game_state.camera.position[2]); + GameState_tick (SDL_GetTicks ()); + GraphicsContext_render (); return SDL_APP_CONTINUE; } @@ -238,8 +64,7 @@ SDL_AppIterate (void *appstate) void SDL_AppQuit (void *appstate, SDL_AppResult result) { - (void) appstate; (void) result; + UNUSED (appstate, result); Resources_free (); - SDL_GL_DestroyContext (context); - SDL_DestroyWindow (window); + GraphicsContext_free (); } diff --git a/game/src/resources.c b/game/src/resources.c index 3c505f4..3518d2f 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -75,6 +75,9 @@ Resources_init () Resources_load_program ("res/shaders/default.vert", "res/shaders/default.frag"); Resources_load_program ("res/shaders/chunk.vert", "res/shaders/chunk.frag"); + program_use (resources.programs[1]); + program_set_int_array (resources.programs[1], "materials", 5, (int[5]) { 0, 1, 2, 3, 4 }); + resources.textures_len = 0; resources.textures = malloc (sizeof (unsigned int)); Resources_load_texture ("res/textures/dirt.png"); diff --git a/game/src/state.c b/game/src/state.c new file mode 100644 index 0000000..63c9562 --- /dev/null +++ b/game/src/state.c @@ -0,0 +1,56 @@ +#include "state.h" + +GameState game_state; + +extern GameFlags game_flags; + +void +GameState_init (int ticks) +{ + game_state.last_time = ticks; + game_state.camera = Camera_default (); +} + +void +GameState_tick (int ticks) +{ + /* Caluclate stuff per frame. */ + game_state.delta_time = (ticks - game_state.last_time) / 1000.0; + game_state.last_time = ticks; + + if (game_flags.moving_forward) + { + vec3 dir, change, new_pos; + Camera_get_direction (&game_state.camera, dir); + glm_vec3_scale (dir, game_state.delta_time * 5, change); + glm_vec3_add (game_state.camera.position, change, new_pos); + glm_vec3_copy (new_pos, game_state.camera.position); + } + + if (game_flags.moving_backward) + { + vec3 dir, change, new_pos; + Camera_get_direction (&game_state.camera, dir); + glm_vec3_scale (dir, game_state.delta_time * 5, change); + glm_vec3_sub (game_state.camera.position, change, new_pos); + glm_vec3_copy (new_pos, game_state.camera.position); + } + + if (game_flags.moving_right) + { + vec3 right, change, new_pos; + Camera_get_right (&game_state.camera, right); + glm_vec3_scale (right, game_state.delta_time * 5, change); + glm_vec3_add (game_state.camera.position, change, new_pos); + glm_vec3_copy (new_pos, game_state.camera.position); + } + + if (game_flags.moving_left) + { + vec3 right, change, new_pos; + Camera_get_right (&game_state.camera, right); + glm_vec3_scale (right, game_state.delta_time * 5, change); + glm_vec3_sub (game_state.camera.position, change, new_pos); + glm_vec3_copy (new_pos, game_state.camera.position); + } +} diff --git a/game/src/state.h b/game/src/state.h index 5a848ea..d201868 100644 --- a/game/src/state.h +++ b/game/src/state.h @@ -1,9 +1,15 @@ #pragma once +#include "camera.h" +#include "flags.h" + typedef struct GameState { int last_time; float delta_time; + + Camera camera; } GameState; -GameState game_state; +void GameState_init (); +void GameState_tick (); diff --git a/game/src/util.h b/game/src/util.h index 671ae37..1d09f14 100644 --- a/game/src/util.h +++ b/game/src/util.h @@ -16,3 +16,8 @@ #define FATAL(fmt, args...) (fprintf (stderr, COLOR_RED "[!] %s:%d:%s(): " COLOR_RESET fmt "\n", __FILE__, __LINE__, __func__, ##args), exit (-1)) #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +#define UNUSED(...) (UNUSED_1 (__VA_ARGS__, 0)) +#define UNUSED_1(arg, ...) (void) arg, UNUSED_2 (__VA_ARGS__, 0) +#define UNUSED_2(arg, ...) (void) arg, UNUSED_3 (__VA_ARGS__, 0) +#define UNUSED_3(arg, ...) (void) arg