From ce549a858346121c352461fac26253292679effb Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 14:29:12 +1000 Subject: [PATCH 1/7] Simple makefile for linux --- Makefile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6589d56 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +render=src/engine/render/render.c src/engine/render/render_init.c src/engine/render/render_util.c +io=src/engine/io/io.c +config=src/engine/config/config.c +input=src/engine/input/input.c +time=src/engine/time/time.c +physics=src/engine/physics/physics.c +array_list=src/engine/array_list/array_list.c +entity=src/engine/entity/entity.c +files=src/glad.c src/main.c src/engine/global.c $(render) $(io) $(config) $(input) $(time) $(physics) $(array_list) $(entity) + +libs=-lm `sdl2-config --cflags --libs` + +#CL /Zi /I W:/include $(files) /link $(libs) /OUT:mygame.exe + +build: + gcc -g3 $(files) $(libs) -o mygame.out From 8be621c150cb984adeda075cf4bb0ec9f80c4eae Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 14:29:53 +1000 Subject: [PATCH 2/7] Remove global render state --- src/engine/global.h | 1 - src/engine/render.h | 4 +- src/engine/render/render.c | 60 +++++++++++++++++------------ src/engine/render/render_init.c | 18 +++++---- src/engine/render/render_internal.h | 13 +------ src/engine/types.h | 1 + src/main.c | 8 ++-- 7 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/engine/global.h b/src/engine/global.h index 6606f45..33dffce 100644 --- a/src/engine/global.h +++ b/src/engine/global.h @@ -6,7 +6,6 @@ #include "time.h" typedef struct global { - Render_State render; Config_State config; Input_State input; Time_State time; diff --git a/src/engine/render.h b/src/engine/render.h index 50fecf7..e6c054d 100644 --- a/src/engine/render.h +++ b/src/engine/render.h @@ -11,9 +11,9 @@ typedef struct render_state { f32 height; } Render_State; -void render_init(void); +SDL_Window *render_init(void); void render_begin(void); -void render_end(void); +void render_end(SDL_Window *window); void render_quad(vec2 pos, vec2 size, vec4 color); void render_quad_line(vec2 pos, vec2 size, vec4 color); void render_line_segment(vec2 start, vec2 end, vec4 color); diff --git a/src/engine/render/render.c b/src/engine/render/render.c index bedfa34..9b3afe3 100644 --- a/src/engine/render/render.c +++ b/src/engine/render/render.c @@ -4,20 +4,32 @@ #include "../render.h" #include "render_internal.h" -static Render_State_Internal state = {0}; - -void render_init(void) { - global.render.width = 1920; - global.render.height = 1080; - global.render.window = render_init_window(global.render.width, global.render.height); - - render_init_quad(&state.vao_quad, &state.vbo_quad, &state.ebo_quad); - render_init_line(&state.vao_line, &state.vbo_line); - render_init_shaders(&state); - render_init_color_texture(&state.texture_color); +static f32 window_width = 1920; +static f32 window_height = 1080; +static f32 render_width = 640; +static f32 render_height = 360; +static f32 scale = 3; + +static u32 vao_quad; +static u32 vbo_quad; +static u32 ebo_quad; +static u32 vao_line; +static u32 vbo_line; +static u32 shader_default; +static u32 texture_color; + +SDL_Window *render_init(void) { + SDL_Window *window = render_init_window(window_width, window_height); + + render_init_quad(&vao_quad, &vbo_quad, &ebo_quad); + render_init_line(&vao_line, &vbo_line); + render_init_shaders(&shader_default, render_width, render_height); + render_init_color_texture(&texture_color); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + return window; } void render_begin(void) { @@ -25,12 +37,12 @@ void render_begin(void) { glClear(GL_COLOR_BUFFER_BIT); } -void render_end(void) { - SDL_GL_SwapWindow(global.render.window); +void render_end(SDL_Window *window) { + SDL_GL_SwapWindow(window); } void render_quad(vec2 pos, vec2 size, vec4 color) { - glUseProgram(state.shader_default); + glUseProgram(shader_default); mat4x4 model; mat4x4_identity(model); @@ -38,19 +50,19 @@ void render_quad(vec2 pos, vec2 size, vec4 color) { mat4x4_translate(model, pos[0], pos[1], 0); mat4x4_scale_aniso(model, model, size[0], size[1], 1); - glUniformMatrix4fv(glGetUniformLocation(state.shader_default, "model"), 1, GL_FALSE, &model[0][0]); - glUniform4fv(glad_glGetUniformLocation(state.shader_default, "color"), 1, color); + glUniformMatrix4fv(glGetUniformLocation(shader_default, "model"), 1, GL_FALSE, &model[0][0]); + glUniform4fv(glad_glGetUniformLocation(shader_default, "color"), 1, color); - glBindVertexArray(state.vao_quad); + glBindVertexArray(vao_quad); - glBindTexture(GL_TEXTURE_2D, state.texture_color); + glBindTexture(GL_TEXTURE_2D, texture_color); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL); glBindVertexArray(0); } void render_line_segment(vec2 start, vec2 end, vec4 color) { - glUseProgram(state.shader_default); + glUseProgram(shader_default); glLineWidth(3); f32 x = end[0] - start[0]; @@ -60,13 +72,13 @@ void render_line_segment(vec2 start, vec2 end, vec4 color) { mat4x4 model; mat4x4_translate(model, start[0], start[1], 0); - glUniformMatrix4fv(glGetUniformLocation(state.shader_default, "model"), 1, GL_FALSE, &model[0][0]); - glUniform4fv(glGetUniformLocation(state.shader_default, "color"), 1, color); + glUniformMatrix4fv(glGetUniformLocation(shader_default, "model"), 1, GL_FALSE, &model[0][0]); + glUniform4fv(glGetUniformLocation(shader_default, "color"), 1, color); - glBindTexture(GL_TEXTURE_2D, state.texture_color); - glBindVertexArray(state.vao_line); + glBindTexture(GL_TEXTURE_2D, texture_color); + glBindVertexArray(vao_line); - glBindBuffer(GL_ARRAY_BUFFER, state.vbo_line); + glBindBuffer(GL_ARRAY_BUFFER, vbo_line); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(line), line); glDrawArrays(GL_LINES, 0, 2); diff --git a/src/engine/render/render_init.c b/src/engine/render/render_init.c index 22b3621..a1c6857 100644 --- a/src/engine/render/render_init.c +++ b/src/engine/render/render_init.c @@ -20,8 +20,8 @@ SDL_Window *render_init_window(u32 width, u32 height) { "MyGame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - global.render.width, - global.render.height, + width, + height, SDL_WINDOW_OPENGL ); @@ -42,17 +42,19 @@ SDL_Window *render_init_window(u32 width, u32 height) { return window; } -void render_init_shaders(Render_State_Internal *state) { - state->shader_default = render_shader_create("./shaders/default.vert", "./shaders/default.frag"); +void render_init_shaders(u32 *shader_default, f32 render_width, f32 render_height) { + mat4x4 projection; - mat4x4_ortho(state->projection, 0, global.render.width, 0, global.render.height, -2, 2); + *shader_default = render_shader_create("./shaders/default.vert", "./shaders/default.frag"); - glUseProgram(state->shader_default); + mat4x4_ortho(projection, 0, render_width, 0, render_height, -2, 2); + + glUseProgram(*shader_default); glUniformMatrix4fv( - glGetUniformLocation(state->shader_default, "projection"), + glGetUniformLocation(*shader_default, "projection"), 1, GL_FALSE, - &state->projection[0][0] + &projection[0][0] ); } diff --git a/src/engine/render/render_internal.h b/src/engine/render/render_internal.h index dca89b2..ea15ab1 100644 --- a/src/engine/render/render_internal.h +++ b/src/engine/render/render_internal.h @@ -5,21 +5,10 @@ #include "../types.h" #include "../render.h" -typedef struct render_state_internal { - u32 vao_quad; - u32 vbo_quad; - u32 ebo_quad; - u32 vao_line; - u32 vbo_line; - u32 shader_default; - u32 texture_color; - mat4x4 projection; -} Render_State_Internal; - SDL_Window *render_init_window(u32 width, u32 height); void render_init_quad(u32 *vao, u32 *vbo, u32 *ebo); void render_init_color_texture(u32 *texture); -void render_init_shaders(Render_State_Internal *state); +void render_init_shaders(u32 *shader_default, f32 render_width, f32 render_height); void render_init_line(u32 *vao, u32 *vbo); u32 render_shader_create(const char *path_vert, const char *path_frag); diff --git a/src/engine/types.h b/src/engine/types.h index a1de90a..7711a77 100644 --- a/src/engine/types.h +++ b/src/engine/types.h @@ -1,6 +1,7 @@ #pragma once #include +#include typedef uint8_t u8; typedef uint16_t u16; diff --git a/src/main.c b/src/main.c index d20ecac..1a782e4 100644 --- a/src/main.c +++ b/src/main.c @@ -78,7 +78,7 @@ void enemy_on_hit_static(Body *self, Static_Body *other, Hit hit) { int main(int argc, char *argv[]) { time_init(60); config_init(); - render_init(); + SDL_Window *window = render_init(); physics_init(); entity_init(); @@ -89,8 +89,8 @@ int main(int argc, char *argv[]) { usize player_id = entity_create((vec2){100, 800}, (vec2){100, 100}, (vec2){0, 0}, COLLISION_LAYER_PLAYER, player_mask, player_on_hit, player_on_hit_static); - f32 width = global.render.width; - f32 height = global.render.height; + i32 width, height; + SDL_GetWindowSize(window, &width, &height); u32 static_body_a_id = physics_static_body_create((vec2){width * 0.5 - 25, height - 25}, (vec2){width - 50, 50}, COLLISION_LAYER_TERRAIN); u32 static_body_b_id = physics_static_body_create((vec2){width - 25, height * 0.5 + 25}, (vec2){50, height - 50}, COLLISION_LAYER_TERRAIN); @@ -140,7 +140,7 @@ int main(int argc, char *argv[]) { render_aabb((f32*)physics_body_get(entity_get(entity_a_id)->body_id), WHITE); render_aabb((f32*)physics_body_get(entity_get(entity_b_id)->body_id), WHITE); - render_end(); + render_end(window); player_color[0] = 0; player_color[2] = 1; From 28f779a6450d839dcb4e04720795a31445671330 Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 14:48:02 +1000 Subject: [PATCH 3/7] Resize bodies, change gravity, add scale getter --- src/engine/physics/physics.c | 4 ++-- src/engine/render.h | 1 + src/engine/render/render.c | 3 +++ src/main.c | 36 +++++++++++++++++------------------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/engine/physics/physics.c b/src/engine/physics/physics.c index e99cb16..6a45bc8 100644 --- a/src/engine/physics/physics.c +++ b/src/engine/physics/physics.c @@ -110,8 +110,8 @@ void physics_init(void) { state.body_list = array_list_create(sizeof(Body), 0); state.static_body_list = array_list_create(sizeof(Static_Body), 0); - state.gravity = -200; - state.terminal_velocity = -10000; + state.gravity = -100; + state.terminal_velocity = -7000; tick_rate = 1.f / iterations; } diff --git a/src/engine/render.h b/src/engine/render.h index e6c054d..e454493 100644 --- a/src/engine/render.h +++ b/src/engine/render.h @@ -19,3 +19,4 @@ void render_quad_line(vec2 pos, vec2 size, vec4 color); void render_line_segment(vec2 start, vec2 end, vec4 color); void render_aabb(f32 *aabb, vec4 color); +f32 render_get_scale(); diff --git a/src/engine/render/render.c b/src/engine/render/render.c index 9b3afe3..1c8cc70 100644 --- a/src/engine/render/render.c +++ b/src/engine/render/render.c @@ -105,3 +105,6 @@ void render_aabb(f32 *aabb, vec4 color) { render_quad_line(&aabb[0], size, color); } +f32 render_get_scale() { + return scale; +} diff --git a/src/main.c b/src/main.c index 1a782e4..f341b32 100644 --- a/src/main.c +++ b/src/main.c @@ -32,20 +32,16 @@ static void input_handle(Body *body_player) { f32 vely = body_player->velocity[1]; if (global.input.right) { - velx += 1000; + velx += 600; } if (global.input.left) { - velx -= 1000; + velx -= 600; } if (global.input.up && player_is_grounded) { player_is_grounded = false; - vely = 4000; - } - - if (global.input.down) { - vely -= 800; + vely = 2000; } body_player->velocity[0] = velx; @@ -67,11 +63,11 @@ void player_on_hit_static(Body *self, Static_Body *other, Hit hit) { void enemy_on_hit_static(Body *self, Static_Body *other, Hit hit) { if (hit.normal[0] > 0) { - self->velocity[0] = 700; + self->velocity[0] = 400; } if (hit.normal[0] < 0) { - self->velocity[0] = -700; + self->velocity[0] = -400; } } @@ -87,19 +83,21 @@ int main(int argc, char *argv[]) { u8 enemy_mask = COLLISION_LAYER_PLAYER | COLLISION_LAYER_TERRAIN; u8 player_mask = COLLISION_LAYER_ENEMY | COLLISION_LAYER_TERRAIN; - usize player_id = entity_create((vec2){100, 800}, (vec2){100, 100}, (vec2){0, 0}, COLLISION_LAYER_PLAYER, player_mask, player_on_hit, player_on_hit_static); + usize player_id = entity_create((vec2){100, 200}, (vec2){24, 24}, (vec2){0, 0}, COLLISION_LAYER_PLAYER, player_mask, player_on_hit, player_on_hit_static); - i32 width, height; - SDL_GetWindowSize(window, &width, &height); + i32 window_width, window_height; + SDL_GetWindowSize(window, &window_width, &window_height); + f32 width = window_width / render_get_scale(); + f32 height = window_height / render_get_scale(); - u32 static_body_a_id = physics_static_body_create((vec2){width * 0.5 - 25, height - 25}, (vec2){width - 50, 50}, COLLISION_LAYER_TERRAIN); - u32 static_body_b_id = physics_static_body_create((vec2){width - 25, height * 0.5 + 25}, (vec2){50, height - 50}, COLLISION_LAYER_TERRAIN); - u32 static_body_c_id = physics_static_body_create((vec2){width * 0.5 + 25, 25}, (vec2){width - 50, 50}, COLLISION_LAYER_TERRAIN); - u32 static_body_d_id = physics_static_body_create((vec2){25, height * 0.5 - 25}, (vec2){50, height - 50}, COLLISION_LAYER_TERRAIN); - u32 static_body_e_id = physics_static_body_create((vec2){width * 0.5, height * 0.5}, (vec2){150, 150}, COLLISION_LAYER_TERRAIN); + u32 static_body_a_id = physics_static_body_create((vec2){width * 0.5 - 12.5, height - 12.5}, (vec2){width - 25, 25}, COLLISION_LAYER_TERRAIN); + u32 static_body_b_id = physics_static_body_create((vec2){width - 12.5, height * 0.5 + 12.5}, (vec2){25, height - 25}, COLLISION_LAYER_TERRAIN); + u32 static_body_c_id = physics_static_body_create((vec2){width * 0.5 + 12.5, 12.5}, (vec2){width - 25, 25}, COLLISION_LAYER_TERRAIN); + u32 static_body_d_id = physics_static_body_create((vec2){12.5, height * 0.5 - 12.5}, (vec2){25, height - 25}, COLLISION_LAYER_TERRAIN); + u32 static_body_e_id = physics_static_body_create((vec2){width * 0.5, height * 0.5}, (vec2){62.5, 62.5}, COLLISION_LAYER_TERRAIN); - usize entity_a_id = entity_create((vec2){600, 600}, (vec2){50, 50}, (vec2){900, 0}, COLLISION_LAYER_ENEMY, enemy_mask, NULL, enemy_on_hit_static); - usize entity_b_id = entity_create((vec2){800, 800}, (vec2){50, 50}, (vec2){900, 0}, 0, enemy_mask, NULL, enemy_on_hit_static); + usize entity_a_id = entity_create((vec2){200, 200}, (vec2){25, 25}, (vec2){400, 0}, COLLISION_LAYER_ENEMY, enemy_mask, NULL, enemy_on_hit_static); + usize entity_b_id = entity_create((vec2){300, 300}, (vec2){25, 25}, (vec2){400, 0}, 0, enemy_mask, NULL, enemy_on_hit_static); while (!should_quit) { time_update(); From fb8646c91dcf544749744db704927c681ffa856d Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 14:50:36 +1000 Subject: [PATCH 4/7] Fix bodies being scaled down twice --- src/engine/entity/entity.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/entity/entity.c b/src/engine/entity/entity.c index 10aa21b..98d2930 100644 --- a/src/engine/entity/entity.c +++ b/src/engine/entity/entity.c @@ -8,8 +8,6 @@ void entity_init(void) { } usize entity_create(vec2 position, vec2 size, vec2 velocity, u8 collision_layer, u8 collision_mask, On_Hit on_hit, On_Hit_Static on_hit_static) { - vec2_scale(size, size, 0.5); - Entity entity = { .body_id = physics_body_create(position, size, velocity, collision_layer, collision_mask, on_hit, on_hit_static), .is_active = true, From 410a31e881c70c3fc434bda776cf05234455fb9a Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 14:55:48 +1000 Subject: [PATCH 5/7] Remove render state struct type --- src/engine/render.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/engine/render.h b/src/engine/render.h index e454493..e5783a5 100644 --- a/src/engine/render.h +++ b/src/engine/render.h @@ -5,12 +5,6 @@ #include "types.h" -typedef struct render_state { - SDL_Window *window; - f32 width; - f32 height; -} Render_State; - SDL_Window *render_init(void); void render_begin(void); void render_end(SDL_Window *window); From 425071049449568a2d7bc5b70d5415363b8db6f1 Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 17:16:01 +1000 Subject: [PATCH 6/7] batch quad renderer --- shaders/batch_quad.frag | 11 +++++ shaders/batch_quad.vert | 15 +++++++ src/engine/render.h | 14 +++++- src/engine/render/render.c | 68 ++++++++++++++++++++++++++++- src/engine/render/render_init.c | 46 ++++++++++++++++++- src/engine/render/render_internal.h | 3 +- src/main.c | 13 ++++++ 7 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 shaders/batch_quad.frag create mode 100644 shaders/batch_quad.vert diff --git a/shaders/batch_quad.frag b/shaders/batch_quad.frag new file mode 100644 index 0000000..8b4d4f1 --- /dev/null +++ b/shaders/batch_quad.frag @@ -0,0 +1,11 @@ +#version 330 core +out vec4 o_color; + +in vec4 v_color; +in vec2 v_uvs; + +uniform sampler2D texture_slot; + +void main() { + o_color = texture(texture_slot, v_uvs) * v_color; +} diff --git a/shaders/batch_quad.vert b/shaders/batch_quad.vert new file mode 100644 index 0000000..9a01ae0 --- /dev/null +++ b/shaders/batch_quad.vert @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec2 a_pos; +layout (location = 1) in vec2 a_uvs; +layout (location = 2) in vec4 a_color; + +out vec4 v_color; +out vec2 v_uvs; + +uniform mat4 projection; + +void main() { + v_color = a_color; + v_uvs = a_uvs; + gl_Position = projection * vec4(a_pos, 0.0, 1.0); +} diff --git a/src/engine/render.h b/src/engine/render.h index e5783a5..cb149cb 100644 --- a/src/engine/render.h +++ b/src/engine/render.h @@ -5,6 +5,16 @@ #include "types.h" +typedef struct batch_vertex { + vec2 position; + vec2 uvs; + vec4 color; +} Batch_Vertex; + +#define MAX_BATCH_QUADS 10000 +#define MAX_BATCH_VERTICES 40000 +#define MAX_BATCH_ELEMENTS 60000 + SDL_Window *render_init(void); void render_begin(void); void render_end(SDL_Window *window); @@ -12,5 +22,7 @@ void render_quad(vec2 pos, vec2 size, vec4 color); void render_quad_line(vec2 pos, vec2 size, vec4 color); void render_line_segment(vec2 start, vec2 end, vec4 color); void render_aabb(f32 *aabb, vec4 color); - f32 render_get_scale(); + +// Temporary! +void append_quad(vec2 position, vec2 size, vec4 texture_coordinates, vec4 color); diff --git a/src/engine/render/render.c b/src/engine/render/render.c index 1c8cc70..97b4568 100644 --- a/src/engine/render/render.c +++ b/src/engine/render/render.c @@ -1,7 +1,11 @@ #include +#define STB_IMAGE_IMPLEMENTATION +#include + #include "../global.h" #include "../render.h" +#include "../array_list.h" #include "render_internal.h" static f32 window_width = 1920; @@ -17,27 +21,89 @@ static u32 vao_line; static u32 vbo_line; static u32 shader_default; static u32 texture_color; +static u32 vao_batch; +static u32 vbo_batch; +static u32 ebo_batch; +static u32 shader_batch; +static Array_List *list_batch; SDL_Window *render_init(void) { SDL_Window *window = render_init_window(window_width, window_height); render_init_quad(&vao_quad, &vbo_quad, &ebo_quad); + render_init_batch_quads(&vao_batch, &vbo_batch, &ebo_batch); render_init_line(&vao_line, &vbo_line); - render_init_shaders(&shader_default, render_width, render_height); + render_init_shaders(&shader_default, &shader_batch, render_width, render_height); render_init_color_texture(&texture_color); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + list_batch = array_list_create(sizeof(Batch_Vertex), 8); + + stbi_set_flip_vertically_on_load(1); + return window; } void render_begin(void) { glClearColor(0.08, 0.1, 0.1, 1); glClear(GL_COLOR_BUFFER_BIT); + + list_batch->len = 0; +} + +static void render_batch(Batch_Vertex *vertices, usize count, u32 texture_id) { + glBindBuffer(GL_ARRAY_BUFFER, vbo_batch); + glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(Batch_Vertex), vertices); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture_id); + + glUseProgram(shader_batch); + glBindVertexArray(vao_batch); + + // count >> 2 is the same as count / 4. + // 4 vertices per quad. + // 6 indices per quad (two tris). + glDrawElements(GL_TRIANGLES, (count >> 2) * 6, GL_UNSIGNED_INT, NULL); +} + +void append_quad(vec2 position, vec2 size, vec4 texture_coordinates, vec4 color) { + vec4 uvs = {0, 0, 1, 1}; + + if (texture_coordinates != NULL) { + memcpy(uvs, texture_coordinates, sizeof(vec4)); + } + + array_list_append(list_batch, &(Batch_Vertex){ + .position = { position[0], position[1] }, + .uvs = { uvs[0], uvs[1] }, + .color = { color[0], color[1], color[2], color[3] }, + }); + + array_list_append(list_batch, &(Batch_Vertex){ + .position = { position[0] + size[0], position[1] }, + .uvs = { uvs[2], uvs[1] }, + .color = { color[0], color[1], color[2], color[3] }, + }); + + array_list_append(list_batch, &(Batch_Vertex){ + .position = { position[0] + size[0], position[1] + size[1] }, + .uvs = { uvs[2], uvs[3] }, + .color = { color[0], color[1], color[2], color[3] }, + }); + + array_list_append(list_batch, &(Batch_Vertex){ + .position = { position[0], position[1] + size[1] }, + .uvs = { uvs[0], uvs[3] }, + .color = { color[0], color[1], color[2], color[3] }, + }); } void render_end(SDL_Window *window) { + render_batch(list_batch->items, list_batch->len, texture_color); + SDL_GL_SwapWindow(window); } diff --git a/src/engine/render/render_init.c b/src/engine/render/render_init.c index a1c6857..3311f7d 100644 --- a/src/engine/render/render_init.c +++ b/src/engine/render/render_init.c @@ -42,10 +42,11 @@ SDL_Window *render_init_window(u32 width, u32 height) { return window; } -void render_init_shaders(u32 *shader_default, f32 render_width, f32 render_height) { +void render_init_shaders(u32 *shader_default, u32 *shader_batch, f32 render_width, f32 render_height) { mat4x4 projection; *shader_default = render_shader_create("./shaders/default.vert", "./shaders/default.frag"); + *shader_batch = render_shader_create("./shaders/batch_quad.vert", "./shaders/batch_quad.frag"); mat4x4_ortho(projection, 0, render_width, 0, render_height, -2, 2); @@ -56,6 +57,14 @@ void render_init_shaders(u32 *shader_default, f32 render_width, f32 render_heigh GL_FALSE, &projection[0][0] ); + + glUseProgram(*shader_batch); + glUniformMatrix4fv( + glGetUniformLocation(*shader_batch, "projection"), + 1, + GL_FALSE, + &projection[0][0] + ); } void render_init_color_texture(u32 *texture) { @@ -105,6 +114,41 @@ void render_init_quad(u32 *vao, u32 *vbo, u32 *ebo) { glBindVertexArray(0); } +void render_init_batch_quads(u32 *vao, u32 *vbo, u32 *ebo) { + glGenVertexArrays(1, vao); + glBindVertexArray(*vao); + + u32 indices[MAX_BATCH_ELEMENTS]; + for (u32 i = 0, offset = 0; i < MAX_BATCH_ELEMENTS; i += 6, offset += 4) { + indices[i + 0] = offset + 0; + indices[i + 1] = offset + 1; + indices[i + 2] = offset + 2; + indices[i + 3] = offset + 2; + indices[i + 4] = offset + 3; + indices[i + 5] = offset + 0; + } + + glGenBuffers(1, vbo); + glBindBuffer(GL_ARRAY_BUFFER, *vbo); + glBufferData(GL_ARRAY_BUFFER, MAX_BATCH_VERTICES * sizeof(Batch_Vertex), NULL, GL_DYNAMIC_DRAW); + + // [x, y], [u, v], [r, g, b, a] + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Batch_Vertex), (void*)offsetof(Batch_Vertex, position)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Batch_Vertex), (void*)offsetof(Batch_Vertex, uvs)); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Batch_Vertex), (void*)offsetof(Batch_Vertex, color)); + + glGenBuffers(1, ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_BATCH_ELEMENTS * sizeof(u32), indices, GL_STATIC_DRAW); + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + void render_init_line(u32 *vao, u32 *vbo) { glGenVertexArrays(1, vao); glBindVertexArray(*vao); diff --git a/src/engine/render/render_internal.h b/src/engine/render/render_internal.h index ea15ab1..0bf77c0 100644 --- a/src/engine/render/render_internal.h +++ b/src/engine/render/render_internal.h @@ -7,8 +7,9 @@ SDL_Window *render_init_window(u32 width, u32 height); void render_init_quad(u32 *vao, u32 *vbo, u32 *ebo); +void render_init_batch_quads(u32 *vao, u32 *vbo, u32 *ebo); void render_init_color_texture(u32 *texture); -void render_init_shaders(u32 *shader_default, f32 render_width, f32 render_height); +void render_init_shaders(u32 *shader_default, u32 *shader_batch, f32 render_width, f32 render_height); void render_init_line(u32 *vao, u32 *vbo); u32 render_shader_create(const char *path_vert, const char *path_frag); diff --git a/src/main.c b/src/main.c index f341b32..861bd3d 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,8 @@ +#include "engine/render.h" #include #include #include +#include #include #define SDL_MAIN_HANDLED #include @@ -72,6 +74,8 @@ void enemy_on_hit_static(Body *self, Static_Body *other, Hit hit) { } int main(int argc, char *argv[]) { + srand(time(NULL)); + time_init(60); config_init(); SDL_Window *window = render_init(); @@ -138,6 +142,15 @@ int main(int argc, char *argv[]) { render_aabb((f32*)physics_body_get(entity_get(entity_a_id)->body_id), WHITE); render_aabb((f32*)physics_body_get(entity_get(entity_b_id)->body_id), WHITE); + for (u32 i = 0; i < 10000; ++i) { + vec4 color = { + (rand() % 255) / 255.0, + (rand() % 255) / 255.0, + (rand() % 255) / 255.0, + (rand() % 255) / 255.0}; + append_quad((vec2){rand() % 640, rand() % 360}, (vec2){rand() % 100, rand() % 100}, NULL, color); + } + render_end(window); player_color[0] = 0; From 598f6f17785b3012625e9bde78470061cc8727f1 Mon Sep 17 00:00:00 2001 From: Dylan Falconer Date: Tue, 6 Sep 2022 17:28:07 +1000 Subject: [PATCH 7/7] sprite sheet rendering --- assets/player.png | Bin 0 -> 5490 bytes src/engine/render.h | 13 +++++++++- src/engine/render/render.c | 51 ++++++++++++++++++++++++++++++++++--- src/main.c | 16 +++++------- 4 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 assets/player.png diff --git a/assets/player.png b/assets/player.png new file mode 100644 index 0000000000000000000000000000000000000000..88b57b23eabcada5d995b4be3e3aab48e6e66809 GIT binary patch literal 5490 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 2) * 6, GL_UNSIGNED_INT, NULL); } -void append_quad(vec2 position, vec2 size, vec4 texture_coordinates, vec4 color) { +static void append_quad(vec2 position, vec2 size, vec4 texture_coordinates, vec4 color) { vec4 uvs = {0, 0, 1, 1}; if (texture_coordinates != NULL) { @@ -101,8 +102,8 @@ void append_quad(vec2 position, vec2 size, vec4 texture_coordinates, vec4 color) }); } -void render_end(SDL_Window *window) { - render_batch(list_batch->items, list_batch->len, texture_color); +void render_end(SDL_Window *window, u32 batch_texture_id) { + render_batch(list_batch->items, list_batch->len, batch_texture_id); SDL_GL_SwapWindow(window); } @@ -171,6 +172,50 @@ void render_aabb(f32 *aabb, vec4 color) { render_quad_line(&aabb[0], size, color); } +static void calculate_sprite_texture_coordinates(vec4 result, f32 row, f32 column, f32 texture_width, f32 texture_height, f32 cell_width, f32 cell_height) { + f32 w = 1.0 / (texture_width / cell_width); + f32 h = 1.0 / (texture_height / cell_height); + f32 x = column * w; + f32 y = row * h; + result[0] = x; + result[1] = y; + result[2] = x + w; + result[3] = y + h; +} + +void render_sprite_sheet_init(Sprite_Sheet *sprite_sheet, const char *path, f32 cell_width, f32 cell_height) { + glGenTextures(1, &sprite_sheet->texture_id); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, sprite_sheet->texture_id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + int width, height, channel_count; + u8 *image_data = stbi_load(path, &width, &height, &channel_count, 0); + if (!image_data) { + ERROR_EXIT("Failed to load image: %s\n", path); + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + stbi_image_free(image_data); + + sprite_sheet->width = (f32)width; + sprite_sheet->height = (f32)height; + sprite_sheet->cell_width = cell_width; + sprite_sheet->cell_height = cell_height; +} + +void render_sprite_sheet_frame(Sprite_Sheet *sprite_sheet, f32 row, f32 column, vec2 position) { + vec4 uvs; + calculate_sprite_texture_coordinates(uvs, row, column, sprite_sheet->width, sprite_sheet->height, sprite_sheet->cell_width, sprite_sheet->cell_height); + + vec2 size = {sprite_sheet->cell_width, sprite_sheet->cell_height}; + vec2 bottom_left = {position[0] - size[0] * 0.5, position[1] - size[1] * 0.5}; + append_quad(bottom_left, size, uvs, (vec4){1, 1, 1, 1}); +} + f32 render_get_scale() { return scale; } diff --git a/src/main.c b/src/main.c index 861bd3d..7f67c2b 100644 --- a/src/main.c +++ b/src/main.c @@ -103,6 +103,9 @@ int main(int argc, char *argv[]) { usize entity_a_id = entity_create((vec2){200, 200}, (vec2){25, 25}, (vec2){400, 0}, COLLISION_LAYER_ENEMY, enemy_mask, NULL, enemy_on_hit_static); usize entity_b_id = entity_create((vec2){300, 300}, (vec2){25, 25}, (vec2){400, 0}, 0, enemy_mask, NULL, enemy_on_hit_static); + Sprite_Sheet sprite_sheet_player; + render_sprite_sheet_init(&sprite_sheet_player, "assets/player.png", 24, 24); + while (!should_quit) { time_update(); @@ -142,16 +145,11 @@ int main(int argc, char *argv[]) { render_aabb((f32*)physics_body_get(entity_get(entity_a_id)->body_id), WHITE); render_aabb((f32*)physics_body_get(entity_get(entity_b_id)->body_id), WHITE); - for (u32 i = 0; i < 10000; ++i) { - vec4 color = { - (rand() % 255) / 255.0, - (rand() % 255) / 255.0, - (rand() % 255) / 255.0, - (rand() % 255) / 255.0}; - append_quad((vec2){rand() % 640, rand() % 360}, (vec2){rand() % 100, rand() % 100}, NULL, color); - } + render_sprite_sheet_frame(&sprite_sheet_player, 1, 2, (vec2){100, 100}); + render_sprite_sheet_frame(&sprite_sheet_player, 0, 4, (vec2){100, 200}); + render_sprite_sheet_frame(&sprite_sheet_player, 0, 0, body_player->aabb.position); - render_end(window); + render_end(window, sprite_sheet_player.texture_id); player_color[0] = 0; player_color[2] = 1;