townengine/src/rendering.c

196 lines
5.3 KiB
C
Raw Normal View History

#include "rendering/internal_api.h"
#include "rendering/sprites.h"
#include "rendering/triangles.h"
#include "rendering/circles.h"
2024-07-08 00:44:20 +00:00
#include "context.h"
#include "textures.h"
#include <SDL2/SDL.h>
#include <glad/glad.h>
#include <stb_ds.h>
2024-07-08 00:44:20 +00:00
#include <stddef.h>
2024-07-08 00:44:20 +00:00
#include <tgmath.h>
/* TODO: have a default initialized one */
static t_matrix4 camera_projection;
2024-07-08 00:44:20 +00:00
void render_queue_clear(void) {
/* 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 upload_quad_vertices(t_frect rect) {
/* client memory needs to be reachable on glDraw*, so */
static float vertices[6 * 2];
vertices[0] = rect.x; vertices[1] = rect.y;
vertices[2] = rect.x; vertices[3] = rect.y + rect.h;
vertices[4] = rect.x + rect.w; vertices[5] = rect.y + rect.h;
vertices[6] = rect.x + rect.w; vertices[7] = rect.y + rect.h;
vertices[8] = rect.x + rect.w; vertices[9] = rect.y;
vertices[10] = rect.x; vertices[11] = rect.y;
glVertexPointer(2, GL_FLOAT, 0, (void *)&vertices);
}
static void render_rectangle(const struct rect_primitive *rectangle) {
glColor4ub(rectangle->color.r, rectangle->color.g,
rectangle->color.b, rectangle->color.a);
glEnableClientState(GL_VERTEX_ARRAY);
upload_quad_vertices(rectangle->rect);
2024-07-08 00:44:20 +00:00
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableClientState(GL_VERTEX_ARRAY);
2024-07-08 00:44:20 +00:00
}
static void render_2d(void) {
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
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);
glDepthRange((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-07-08 00:44:20 +00:00
}
}
static void render_space(void) {
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glActiveTexture(GL_TEXTURE0);
/* solid white, no modulation */
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
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.window_size_has_changed) {
if ((float)ctx.window_w / (float)ctx.window_h > RENDER_BASE_RATIO) {
float ratio = (float)ctx.window_h / (float)RENDER_BASE_HEIGHT;
int w = (int)((float)RENDER_BASE_WIDTH * ratio);
glViewport(
ctx.window_w / 2 - w / 2,
0,
w,
ctx.window_h
);
} else {
float ratio = (float)ctx.window_w / (float)RENDER_BASE_WIDTH;
int h = (int)((float)RENDER_BASE_HEIGHT * ratio);
glViewport(
0,
ctx.window_h / 2 - h / 2,
ctx.window_w,
h
);
}
}
glClearColor((1.0f / 255) * 230,
(1.0f / 255) * 230,
(1.0f / 255) * 230, 1);
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
2024-07-08 00:44:20 +00:00
{
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&camera_projection.row[0].x);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_space();
}
2024-07-08 00:44:20 +00:00
/* TODO: only do it when transition between spaces is needed */
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_2d();
}
SDL_GL_SwapWindow(ctx.window);
2024-07-08 00:44:20 +00:00
}
void push_camera(const t_camera *const camera) {
/* TODO: skip recaulculating if it's the same? */
camera_projection = camera_look_at(camera);
}