Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch rendering, sprite sheets, refactoring #12

Draft
wants to merge 3 commits into
base: rec
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/player.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions shaders/batch_quad_frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#version 330 core
out vec4 o_color;

in vec4 v_color;
in vec2 v_uvs;

uniform sampler2D texture_slot;

void main() {
//o_color = vec4(1, 0, 0, 1);
o_color = texture(texture_slot, v_uvs) * v_color;
}

15 changes: 15 additions & 0 deletions shaders/batch_quad_vert.glsl
Original file line number Diff line number Diff line change
@@ -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);
}
3 changes: 2 additions & 1 deletion src/engine/entity/entity.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ 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);
// Mistake!
//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),
Expand Down
1 change: 0 additions & 1 deletion src/engine/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "time.h"

typedef struct global {
Render_State render;
Config_State config;
Input_State input;
Time_State time;
Expand Down
4 changes: 2 additions & 2 deletions src/engine/physics/physics.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = -150;
state.terminal_velocity = -7000;

tick_rate = 1.f / iterations;
}
Expand Down
30 changes: 24 additions & 6 deletions src/engine/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,36 @@
#include <linmath.h>

#include "types.h"
#include "array_list.h"

typedef struct render_state {
SDL_Window *window;
typedef struct sprite_sheet {
f32 width;
f32 height;
} Render_State;
f32 cell_width;
f32 cell_height;
u32 texture_id;
} Sprite_Sheet;

void render_init(void);
typedef struct batch_vertex {
vec2 position;
vec2 uvs;
vec4 color;
} Batch_Vertex;

enum {
MAX_BATCH_QUADS = 10000,
MAX_BATCH_VERTICES = MAX_BATCH_QUADS * 4,
MAX_BATCH_ELEMENTS = MAX_BATCH_QUADS * 6,
};

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);
void render_aabb(f32 *aabb, vec4 color);

void render_sprite_sheet_init(Sprite_Sheet *sprite_sheet, const char *path, f32 cell_width, f32 cell_height);
void render_sprite_sheet_frame(Sprite_Sheet *sprite_sheet, f32 row, f32 column, vec2 position);
void render_set_batch_texture(u32 texture_id);
f32 render_get_scale();
182 changes: 158 additions & 24 deletions src/engine/render/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,104 @@
#include "../global.h"
#include "../render.h"
#include "render_internal.h"
#include "../util.h"

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

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;
static u32 vao_batch;
static u32 vbo_batch;
static u32 ebo_batch;
static u32 shader_batch;
static u32 texture_batch;
static Array_List *list_batch;

SDL_Window *render_init(void) {
/// RENDER WIDTH AND VIEWPORT WIDTH SHOULD BE DIFFERENT - PIXEL ART
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, &shader_batch, render_width, render_height);
render_init_color_texture(&texture_color);
render_init_batch_quads(&vao_batch, &vbo_batch, &ebo_batch);

static Render_State_Internal state = {0};
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

void render_init(void) {
global.render.width = 1920;
global.render.height = 1080;
global.render.window = render_init_window(global.render.width, global.render.height);
list_batch = array_list_create(sizeof(Batch_Vertex), 8);

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);
stbi_set_flip_vertically_on_load(1);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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 s the same as count / 4.
// 4 Vertices per Quad.
// 6 Indices per Quad (two triangles).
glDrawElements(GL_TRIANGLES, (count >> 2) * 6, GL_UNSIGNED_INT, NULL);
}

void render_end(void) {
SDL_GL_SwapWindow(global.render.window);
void render_end(SDL_Window *window) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINES);
render_batch(list_batch->items, list_batch->len, texture_batch);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

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);

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];
Expand All @@ -60,13 +110,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);

Expand All @@ -93,3 +143,87 @@ void render_aabb(f32 *aabb, vec4 color) {
render_quad_line(&aabb[0], size, color);
}

static 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] },
});
}

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;
}

// NOTE: Temporary setter - will use texture slots later.
void render_set_batch_texture(u32 texture_id) {
texture_batch = texture_id;
}
Loading