townengine/src/rendering/twn_rendering.c

148 lines
4.1 KiB
C
Raw Normal View History

#include "twn_rendering_c.h"
#include "twn_rendering.h"
#include "twn_engine_context_c.h"
#include "twn_camera.h"
2024-07-08 00:44:20 +00:00
#include <SDL2/SDL.h>
#include <stb_ds.h>
2024-07-08 00:44:20 +00:00
#ifdef EMSCRIPTEN
#include <GLES2/gl2.h>
#else
#include <glad/glad.h>
#endif
#include <stddef.h>
2024-07-08 00:44:20 +00:00
#include <tgmath.h>
/* TODO: have a default initialized one */
t_matrix4 camera_projection_matrix;
t_matrix4 camera_look_at_matrix;
2024-07-08 00:44:20 +00:00
void render_queue_clear(void) {
2024-08-23 02:41:52 +00:00
/* this doesn't even _deserve_ a TODO */
/* if you're gonna remove it, this is also being done in main.c */
for (size_t i = 0; i < arrlenu(ctx.render_queue_2d); ++i) {
if (ctx.render_queue_2d[i].type == PRIMITIVE_2D_TEXT) {
free(ctx.render_queue_2d[i].text.text);
}
}
2024-07-08 00:44:20 +00:00
/* since i don't intend to free the queues, */
/* it's faster and simpler to just "start over" */
/* and start overwriting the existing data */
arrsetlen(ctx.render_queue_2d, 0);
for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i)
arrsetlen(ctx.uncolored_mesh_batches[i].value.primitives, 0);
2024-07-08 00:44:20 +00:00
}
/* rectangle */
void push_rectangle(t_frect rect, t_color color) {
struct rect_primitive rectangle = {
.rect = rect,
.color = color,
};
struct primitive_2d primitive = {
.type = PRIMITIVE_2D_RECT,
.rect = rectangle,
};
arrput(ctx.render_queue_2d, primitive);
2024-07-08 00:44:20 +00:00
}
static void render_2d(void) {
use_2d_pipeline();
2024-07-08 00:44:20 +00:00
const size_t render_queue_len = arrlenu(ctx.render_queue_2d);
2024-07-08 00:44:20 +00:00
size_t batch_count = 0;
2024-07-08 00:44:20 +00:00
for (size_t i = 0; i < render_queue_len; ++i) {
const struct primitive_2d *current = &ctx.render_queue_2d[i];
switch (current->type) {
case PRIMITIVE_2D_SPRITE: {
const struct sprite_batch batch =
collect_sprite_batch(current, render_queue_len - i);
/* TODO: what's even the point? just use OR_EQUAL comparison */
set_depth_range((double)batch_count / UINT16_MAX, 1.0);
render_sprites(current, batch);
i += batch.size - 1; ++batch_count;
break;
}
case PRIMITIVE_2D_RECT:
render_rectangle(&current->rect);
break;
case PRIMITIVE_2D_CIRCLE:
render_circle(&current->circle);
break;
2024-08-23 02:41:52 +00:00
case PRIMITIVE_2D_TEXT:
render_text(&current->text);
break;
}
2024-07-08 00:44:20 +00:00
}
}
static void render_space(void) {
/* nothing to do, abort */
/* as space pipeline isn't used we can have fewer changes and initialization costs */
if (hmlenu(ctx.uncolored_mesh_batches) == 0)
return;
use_space_pipeline();
for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i) {
draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i].value,
ctx.uncolored_mesh_batches[i].key);
}
}
2024-07-08 00:44:20 +00:00
void render(void) {
textures_update_atlas(&ctx.texture_cache);
/* fit rendering context onto the resizable screen */
if (ctx.game.window_size_has_changed) {
if ((float)ctx.game.window_w / (float)ctx.game.window_h > RENDER_BASE_RATIO) {
float ratio = (float)ctx.game.window_h / (float)RENDER_BASE_HEIGHT;
int w = (int)((float)RENDER_BASE_WIDTH * ratio);
setup_viewport(
ctx.game.window_w / 2 - w / 2,
0,
w,
ctx.game.window_h
);
} else {
float ratio = (float)ctx.game.window_w / (float)RENDER_BASE_WIDTH;
int h = (int)((float)RENDER_BASE_HEIGHT * ratio);
setup_viewport(
0,
ctx.game.window_h / 2 - h / 2,
ctx.game.window_w,
h
);
}
}
clear_draw_buffer();
render_space();
render_2d();
swap_buffers();
2024-07-08 00:44:20 +00:00
}
2024-07-30 15:05:05 +00:00
void set_camera(const t_camera *const camera) {
/* TODO: skip recaulculating if it's the same? */
2024-07-30 15:05:05 +00:00
camera_projection_matrix = camera_perspective(camera);
camera_look_at_matrix = camera_look_at(camera);
}