#include "twn_rendering_c.h" #include "twn_rendering.h" #include "twn_engine_context_c.h" #include "twn_camera.h" #include #include #ifdef EMSCRIPTEN #include #else #include #endif #include #include /* TODO: have a default initialized one */ t_matrix4 camera_projection_matrix; t_matrix4 camera_look_at_matrix; void render_queue_clear(void) { /* 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); } } /* 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); } /* 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); } static void render_2d(void) { use_2d_pipeline(); const size_t render_queue_len = arrlenu(ctx.render_queue_2d); size_t batch_count = 0; 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(¤t->rect); break; case PRIMITIVE_2D_CIRCLE: render_circle(¤t->circle); break; case PRIMITIVE_2D_TEXT: render_text(¤t->text); break; } } } 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); } } 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(); } void set_camera(const t_camera *const camera) { /* TODO: skip recaulculating if it's the same? */ camera_projection_matrix = camera_perspective(camera); camera_look_at_matrix = camera_look_at(camera); }