a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

commit bd88d22d902bd6e582766d4b5681a4e7a9386e82
parent 63795490e5ccc2c318b479d4eef189b575ce6c22
Author: amin <dev@aminmesbah.com>
Date:   Mon, 10 Jun 2019 01:59:33 +0000

Split rendering code into module

FossilOrigin-Name: e2a20963b3ca6477eb7b824ee5f27b9d6279e0d1cf6ace008b2d8db15866ec08
Diffstat:
Msrc/game.c | 136++++++++++---------------------------------------------------------------------
Msrc/game.h | 18+-----------------
Msrc/memory.c | 1+
Asrc/render.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/render.h | 21+++++++++++++++++++++
5 files changed, 164 insertions(+), 137 deletions(-)

diff --git a/src/game.c b/src/game.c @@ -3,19 +3,9 @@ #include "shader.c" #include "memory.c" #include "collision.c" +#include "render.c" #include "world.c" -#define RENDER_QUEUE_SIZE 512 -global_variable struct RenderJob g_render_queue[RENDER_QUEUE_SIZE]; -global_variable u32 g_render_queue_count = 0; - -internal void render_job_enqueue(struct RenderJob job) -{ - assert(g_render_queue_count + 1 < RENDER_QUEUE_SIZE); - g_render_queue[g_render_queue_count] = job; - g_render_queue_count++; -} - internal void game_init(struct GameMemory *game_memory, v2u framebuffer) { assert(sizeof(struct GameState) <= game_memory->buffer_size); @@ -109,57 +99,9 @@ internal void game_init(struct GameMemory *game_memory, v2u framebuffer) } } - // set up and load tiles - { - GLfloat quad_vertices[] = { - 0.5f, 0.5f, - 0.5f, -0.5f, - -0.5f, -0.5f, - -0.5f, 0.5f, - }; - - GLuint quad_elements[] = { 0, 1, 3, 1, 2, 3 }; - GLuint rect_elements[] = { 0, 1, 1, 2, 2, 3, 3, 0 }; - - GLuint vao; - GLuint quad_vbo; - GLuint quad_ebo; - GLuint rect_ebo; - glGenVertexArrays(1, &vao); - glGenBuffers(1, &quad_vbo); - glGenBuffers(1, &quad_ebo); - glGenBuffers(1, &rect_ebo); - - // NOTE(amin): We will leave this bound for the duration of the game. - // There should not be any calls to glBindVertexArray(0). - glBindVertexArray(vao); - - glBindBuffer(GL_ARRAY_BUFFER, quad_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); - glVertexAttribPointer( - 0, // Data location - 2, // Number of values - GL_FLOAT, // Data type - GL_FALSE, // Normalize data - 2 * sizeof(GLfloat), // Stride - (GLvoid*)0 // Position data offset (0) - ); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_elements), quad_elements, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rect_ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(rect_elements), rect_elements, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_ebo); - - game_state->renderer.vao = vao; - game_state->renderer.quad_vbo = quad_vbo; - game_state->renderer.quad_ebo = quad_ebo; - game_state->renderer.rect_ebo = rect_ebo; - } + render_init(&game_state->renderer, &game_state->world_allocator); + // game_shader_load { struct PlatformApi platform = game_memory->platform; char *v_source = platform.platform_read_entire_file("shader/main_v.glsl"); @@ -216,9 +158,10 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga view = math_scale(view, (v3) {1.0f, -1.0f, 1.0f}); view = math_translate(view, (v3) {viewport.min.x, viewport.min.y, 0.0f}); view = math_scale(view, (v3) {ppm, ppm, 1.0f}); + game_state->renderer.view = view; // Screen origin is in the upper left - m4 projection = math_projection_ortho(0.0f, framebuffer.width, framebuffer.height, 0.0f, -1.0f, 0.0f); + game_state->renderer.projection = math_projection_ortho(0.0f, framebuffer.width, framebuffer.height, 0.0f, -1.0f, 0.0f); v2i current_room_i = game_state->player.pos.room; struct Room *r = world_room_get(game_state->world, current_room_i); @@ -305,7 +248,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga .color = color, .model = model, }; - render_job_enqueue(j); + render_job_enqueue(&game_state->renderer, j); } } } @@ -363,7 +306,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga // game_detect_collisions { -#define RENDER_COLLISION_DEBUG_QUAD(r, c) render_debug_quad(game_state, (r), (c), &view, &projection); +#define RENDER_COLLISION_DEBUG_QUAD(r, c) render_debug_quad(&game_state->renderer, (r), (c)); v2 player_delta = math_v2f_m(player->velocity, dt); v2 new_p = math_v2_a(player->pos.local, player_delta); @@ -575,7 +518,6 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga } } - // render_player { struct Entity player = game_state->player; @@ -586,69 +528,23 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga v3 color = (v3) { 1.0f, 0.0f, 1.0f }; - struct RenderJob j = { - .ebo = game_state->renderer.quad_ebo, - .color = color, - .model = model, - }; - render_job_enqueue(j); - - } - - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); -#if 0 - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -#else - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif - shader_use(&game_state->renderer.shader); - shader_setm4(&game_state->renderer.shader, "projection", &projection); - shader_setm4(&game_state->renderer.shader, "view", &view); - for (u32 i = 0; i < g_render_queue_count; i++) - { - struct RenderJob j = g_render_queue[i]; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, j.ebo); - shader_setv3(&game_state->renderer.shader, "color", &j.color); - shader_setm4(&game_state->renderer.shader, "model", &j.model); - if (j.ebo == game_state->renderer.quad_ebo) - { - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - } - else - { - glDrawElements(GL_LINES, 8, GL_UNSIGNED_INT, 0); - } + render_job_enqueue( + &game_state->renderer, + (struct RenderJob) { + .ebo = game_state->renderer.quad_ebo, + .color = color, + .model = model, + }); } - g_render_queue_count = 0; + render_jobs(&game_state->renderer); } internal void game_cleanup(struct GameMemory *game_memory) { assert(sizeof(struct GameState) <= game_memory->buffer_size); struct GameState *game_state = (struct GameState *)game_memory->buffer; - glDeleteVertexArrays(1, &game_state->renderer.vao); - glDeleteBuffers(1, &game_state->renderer.quad_vbo); - glDeleteBuffers(1, &game_state->renderer.quad_ebo); - glDeleteBuffers(1, &game_state->renderer.rect_ebo); -} - -internal void render_debug_quad(struct GameState *game_state, rect r, v3 color, m4 *view, m4 *projection) -{ - v2 dim = {r.max.x - r.min.x, r.max.y - r.min.y}; - - m4 model = math_m4_init_id(); - model = math_translate(model, (v3) {dim.x * 0.5f, dim.y * 0.5f, 0.0f}); - model = math_translate(model, (v3) {r.min.x, r.min.y, 0.0f}); - model = math_scale(model, (v3) {dim.width, dim.height, 1.0f}); - - struct RenderJob j = { - .ebo = game_state->renderer.rect_ebo, - .color = color, - .model = model, - }; - render_job_enqueue(j); + render_cleanup(&game_state->renderer); } #ifdef PLATFORM_HOTLOAD_GAME_CODE diff --git a/src/game.h b/src/game.h @@ -21,6 +21,7 @@ #include "am_math.h" #include "shader.h" #include "memory.h" +#include "render.h" #include "world.h" #include "platform.h" @@ -29,22 +30,6 @@ static_assert(-1 == ~0, "Implementation doesn't use two's complement"); // One tile is one square meter #define TILE_SIZE 1.0f -struct RenderJob -{ - GLuint ebo; - v3 color; - m4 model; -}; - -struct RendererState -{ - GLuint vao; - GLuint quad_vbo; - GLuint quad_ebo; - GLuint rect_ebo; - struct Shader shader; -}; - // TODO: Move this to world.h struct AbsolutePos { @@ -70,4 +55,3 @@ struct GameState internal void game_init(struct GameMemory *game_memory, v2u framebuffer); internal void game_cleanup(struct GameMemory *game_memory); -internal void render_debug_quad(struct GameState *game_state, rect r, v3 color, m4 *view, m4 *projection); diff --git a/src/memory.c b/src/memory.c @@ -1,4 +1,5 @@ #define mem_st_alloc_struct(allocator, type) mem_st_alloc((allocator), sizeof(type), alignof(type)) +#define mem_st_alloc_buffer(allocator, type, count) mem_st_alloc((allocator), sizeof(type) * (count), alignof(type)) // TODO: test that alignment is working properly internal inline uintptr_t mem_align_address(uintptr_t address, size_t alignment) diff --git a/src/render.c b/src/render.c @@ -0,0 +1,125 @@ +internal void render_init(struct RendererState *renderer, struct StackAllocator *allocator) +{ + GLfloat quad_vertices[] = { + 0.5f, 0.5f, + 0.5f, -0.5f, + -0.5f, -0.5f, + -0.5f, 0.5f, + }; + + GLuint quad_elements[] = { 0, 1, 3, 1, 2, 3 }; + GLuint rect_elements[] = { 0, 1, 1, 2, 2, 3, 3, 0 }; + + GLuint vao; + GLuint quad_vbo; + GLuint quad_ebo; + GLuint rect_ebo; + glGenVertexArrays(1, &vao); + glGenBuffers(1, &quad_vbo); + glGenBuffers(1, &quad_ebo); + glGenBuffers(1, &rect_ebo); + + // NOTE(amin): We will leave this bound for the duration of the game. + // There should not be any calls to glBindVertexArray(0). + glBindVertexArray(vao); + + glBindBuffer(GL_ARRAY_BUFFER, quad_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); + glVertexAttribPointer( + 0, // Data location + 2, // Number of values + GL_FLOAT, // Data type + GL_FALSE, // Normalize data + 2 * sizeof(GLfloat), // Stride + (GLvoid*)0 // Position data offset (0) + ); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_elements), quad_elements, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rect_ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(rect_elements), rect_elements, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_ebo); + + renderer->vao = vao; + renderer->quad_vbo = quad_vbo; + renderer->quad_ebo = quad_ebo; + renderer->rect_ebo = rect_ebo; + renderer->queue = mem_st_alloc_buffer(allocator, struct RenderJob, RENDER_QUEUE_SIZE); + renderer->queue_count = 0; +} + +internal void render_jobs(struct RendererState *renderer) +{ + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + +#if 0 + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +#else + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif + + shader_use(&renderer->shader); + shader_setm4(&renderer->shader, "projection", &renderer->projection); + shader_setm4(&renderer->shader, "view", &renderer->view); + + GLuint current_ebo = renderer->quad_ebo; + for (u32 i = 0; i < renderer->queue_count; i++) + { + struct RenderJob j = renderer->queue[i]; + if (current_ebo != j.ebo) + { + current_ebo = j.ebo; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, j.ebo); + } + shader_setv3(&renderer->shader, "color", &j.color); + shader_setm4(&renderer->shader, "model", &j.model); + if (j.ebo == renderer->quad_ebo) + { + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + } + else + { + glDrawElements(GL_LINES, 8, GL_UNSIGNED_INT, 0); + } + } + + renderer->queue_count = 0; +} + +internal void render_job_enqueue(struct RendererState *renderer, struct RenderJob job) +{ + assert(renderer); + assert(renderer->queue); + assert(renderer->queue_count + 1 < RENDER_QUEUE_SIZE); + renderer->queue[renderer->queue_count] = job; + renderer->queue_count++; +} + +internal void render_debug_quad(struct RendererState *renderer, rect r, v3 color) +{ + v2 dim = {r.max.x - r.min.x, r.max.y - r.min.y}; + + m4 model = math_m4_init_id(); + model = math_translate(model, (v3) {dim.x * 0.5f, dim.y * 0.5f, 0.0f}); + model = math_translate(model, (v3) {r.min.x, r.min.y, 0.0f}); + model = math_scale(model, (v3) {dim.width, dim.height, 1.0f}); + + struct RenderJob j = { + .ebo = renderer->rect_ebo, + .color = color, + .model = model, + }; + render_job_enqueue(renderer, j); +} + +internal void render_cleanup(struct RendererState *renderer) +{ + glDeleteVertexArrays(1, &renderer->vao); + glDeleteBuffers(1, &renderer->quad_vbo); + glDeleteBuffers(1, &renderer->quad_ebo); + glDeleteBuffers(1, &renderer->rect_ebo); +} diff --git a/src/render.h b/src/render.h @@ -0,0 +1,21 @@ +#define RENDER_QUEUE_SIZE 512 + +struct RenderJob +{ + GLuint ebo; + v3 color; + m4 model; +}; + +struct RendererState +{ + GLuint vao; + GLuint quad_vbo; + GLuint quad_ebo; + GLuint rect_ebo; + m4 projection; + m4 view; + struct Shader shader; + struct RenderJob *queue; + u32 queue_count; +};