2024-07-08 00:44:20 +00:00
|
|
|
#include "private/rendering.h"
|
|
|
|
#include "context.h"
|
|
|
|
#include "textures.h"
|
|
|
|
|
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
#include <stb_ds.h>
|
2024-07-09 12:35:54 +00:00
|
|
|
#include <glad/glad.h>
|
2024-07-08 00:44:20 +00:00
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
#include <stddef.h>
|
2024-07-08 00:44:20 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <tgmath.h>
|
|
|
|
|
|
|
|
|
|
|
|
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_sprites, 0);
|
|
|
|
arrsetlen(ctx.render_queue_rectangles, 0);
|
|
|
|
arrsetlen(ctx.render_queue_circles, 0);
|
2024-07-10 16:15:28 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < arrlenu(ctx.uncolored_mesh_batches); ++i)
|
|
|
|
arrsetlen(ctx.uncolored_mesh_batches[i].data, 0);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < shlenu(ctx.uncolored_mesh_batches_loners); ++i)
|
|
|
|
arrsetlen(ctx.uncolored_mesh_batches_loners[i].value.data, 0);
|
2024-07-08 00:44:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* an implementation note:
|
|
|
|
* try to avoid doing expensive work in the push functions,
|
|
|
|
* because they will be called multiple times in the main loop
|
|
|
|
* before anything is really rendered
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* sprite */
|
|
|
|
void push_sprite(char *path, t_frect rect) {
|
|
|
|
textures_load(&ctx.texture_cache, path);
|
|
|
|
|
|
|
|
struct sprite_primitive sprite = {
|
|
|
|
.rect = rect,
|
|
|
|
.color = (t_color) { 255, 255, 255, 255 },
|
|
|
|
.path = path,
|
|
|
|
.rotation = 0.0,
|
|
|
|
.blend_mode = SDL_BLENDMODE_BLEND,
|
|
|
|
.atlas_index =
|
|
|
|
textures_get_atlas_index(&ctx.texture_cache, path),
|
|
|
|
.layer = 0,
|
|
|
|
.flip_x = false,
|
|
|
|
.flip_y = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
arrput(ctx.render_queue_sprites, sprite);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void push_sprite_ex(t_frect rect, t_push_sprite_args args) {
|
|
|
|
textures_load(&ctx.texture_cache, args.path);
|
|
|
|
|
|
|
|
struct sprite_primitive sprite = {
|
|
|
|
.rect = rect,
|
|
|
|
.color = args.color,
|
|
|
|
.path = args.path,
|
|
|
|
.rotation = args.rotation,
|
|
|
|
.blend_mode = args.blend_mode,
|
|
|
|
.atlas_index =
|
|
|
|
textures_get_atlas_index(&ctx.texture_cache, args.path),
|
|
|
|
.layer = args.layer,
|
|
|
|
.flip_x = args.flip_x,
|
|
|
|
.flip_y = args.flip_y,
|
|
|
|
};
|
|
|
|
|
|
|
|
arrput(ctx.render_queue_sprites, sprite);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* rectangle */
|
|
|
|
void push_rectangle(t_frect rect, t_color color) {
|
|
|
|
struct rect_primitive rectangle = {
|
|
|
|
.rect = rect,
|
|
|
|
.color = color,
|
|
|
|
};
|
|
|
|
|
|
|
|
arrput(ctx.render_queue_rectangles, rectangle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* circle */
|
|
|
|
void push_circle(t_fvec2 position, float radius, t_color color) {
|
|
|
|
struct circle_primitive circle = {
|
|
|
|
.radius = radius,
|
|
|
|
.color = color,
|
|
|
|
.position = position,
|
|
|
|
};
|
|
|
|
|
|
|
|
arrput(ctx.render_queue_circles, circle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
/* TODO: automatic handling of repeating textures */
|
|
|
|
void unfurl_triangle(const char *path,
|
|
|
|
t_fvec3 v0,
|
|
|
|
t_fvec3 v1,
|
|
|
|
t_fvec3 v2,
|
|
|
|
t_shvec2 uv0,
|
|
|
|
t_shvec2 uv1,
|
|
|
|
t_shvec2 uv2)
|
|
|
|
{
|
|
|
|
/* corrected atlas texture coordinates */
|
|
|
|
t_shvec2 uv0c, uv1c, uv2c;
|
|
|
|
struct mesh_batch *batch_p;
|
|
|
|
|
|
|
|
textures_load(&ctx.texture_cache, path);
|
|
|
|
|
|
|
|
const int atlas_index = textures_get_atlas_index(&ctx.texture_cache, path);
|
|
|
|
if (atlas_index == -1) {
|
|
|
|
/* loners span whole texture i assume */
|
|
|
|
uv0c = uv0;
|
|
|
|
uv1c = uv1;
|
|
|
|
uv2c = uv2;
|
|
|
|
|
|
|
|
batch_p = &shgetp(ctx.uncolored_mesh_batches_loners, path)->value;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
const size_t old_len = arrlenu(ctx.uncolored_mesh_batches);
|
|
|
|
if ((size_t)atlas_index + 1 >= old_len) {
|
|
|
|
/* grow to accommodate texture cache atlases */
|
|
|
|
arrsetlen(ctx.uncolored_mesh_batches, atlas_index + 1);
|
|
|
|
|
|
|
|
/* zero initialize it all, it's a valid state */
|
|
|
|
SDL_memset(&ctx.uncolored_mesh_batches[atlas_index],
|
|
|
|
0,
|
|
|
|
sizeof (struct mesh_batch) * ((atlas_index + 1) - old_len));
|
|
|
|
}
|
|
|
|
|
|
|
|
const SDL_Rect srcrect = ctx.texture_cache.hash[atlas_index].value.srcrect; /* TODO: does it work? */
|
|
|
|
|
|
|
|
/* fixed point galore */
|
|
|
|
const int16_t srcratx = (int16_t)srcrect.x * (INT16_MAX / TEXTURE_ATLAS_SIZE);
|
|
|
|
const int16_t srcratw = (int16_t)srcrect.w * (INT16_MAX / TEXTURE_ATLAS_SIZE);
|
|
|
|
const int16_t srcrath = (int16_t)srcrect.h * (INT16_MAX / TEXTURE_ATLAS_SIZE);
|
|
|
|
const int16_t srcraty = (int16_t)srcrect.y * (INT16_MAX / TEXTURE_ATLAS_SIZE); /* flip? */
|
|
|
|
|
|
|
|
uv0c.x = (int16_t)(srcratx + ((uint16_t)((uv0.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7));
|
|
|
|
uv0c.y = (int16_t)(srcraty + ((uint16_t)((uv0.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7));
|
|
|
|
uv1c.x = (int16_t)(srcratx + ((uint16_t)((uv1.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7));
|
|
|
|
uv1c.y = (int16_t)(srcraty + ((uint16_t)((uv1.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7));
|
|
|
|
uv2c.x = (int16_t)(srcratx + ((uint16_t)((uv2.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7));
|
|
|
|
uv2c.y = (int16_t)(srcraty + ((uint16_t)((uv2.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7));
|
|
|
|
|
|
|
|
batch_p = &ctx.uncolored_mesh_batches[atlas_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
struct uncolored_space_triangle *data = (struct uncolored_space_triangle *)batch_p->data;
|
|
|
|
struct uncolored_space_triangle pack = {
|
|
|
|
.v0 = v0,
|
|
|
|
// .uv0 = uv0c,
|
|
|
|
.uv0 = { 0, 0 },
|
|
|
|
.v1 = v1,
|
|
|
|
// .uv1 = uv1c,
|
|
|
|
.uv1 = { INT16_MAX, 0 },
|
|
|
|
.v2 = v2,
|
|
|
|
// .uv2 = uv2c,
|
|
|
|
.uv2 = { INT16_MAX, INT16_MAX },
|
|
|
|
};
|
|
|
|
arrpush(data, pack);
|
|
|
|
|
|
|
|
batch_p->data = (uint8_t *)data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
/* compare functions for the sort in render_sprites */
|
|
|
|
static int cmp_atlases(const void *a, const void *b) {
|
|
|
|
int index_a = ((const struct sprite_primitive *)a)->atlas_index;
|
|
|
|
int index_b = ((const struct sprite_primitive *)b)->atlas_index;
|
|
|
|
|
|
|
|
return (index_a > index_b) - (index_a < index_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int cmp_blend_modes(const void *a, const void *b) {
|
|
|
|
SDL_BlendMode mode_a = ((const struct sprite_primitive *)a)->blend_mode;
|
|
|
|
SDL_BlendMode mode_b = ((const struct sprite_primitive *)b)->blend_mode;
|
|
|
|
|
|
|
|
return (mode_a > mode_b) - (mode_a < mode_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int cmp_colors(const void *a, const void *b) {
|
|
|
|
t_color color_a = ((const struct sprite_primitive *)a)->color;
|
|
|
|
t_color color_b = ((const struct sprite_primitive *)b)->color;
|
|
|
|
|
|
|
|
/* check reds */
|
|
|
|
if (color_a.r < color_b.r)
|
|
|
|
return -1;
|
|
|
|
else if (color_a.r > color_b.r)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* reds were equal, check greens */
|
|
|
|
else if (color_a.g < color_b.g)
|
|
|
|
return -1;
|
|
|
|
else if (color_a.g > color_b.g)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* greens were equal, check blues */
|
|
|
|
else if (color_a.b < color_b.b)
|
|
|
|
return -1;
|
|
|
|
else if (color_a.b > color_b.b)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* blues were equal, check alphas */
|
|
|
|
else if (color_a.a < color_b.a)
|
|
|
|
return -1;
|
|
|
|
else if (color_a.a > color_b.a)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* entirely equal */
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int cmp_layers(const void *a, const void *b) {
|
|
|
|
int layer_a = ((const struct sprite_primitive *)a)->layer;
|
|
|
|
int layer_b = ((const struct sprite_primitive *)b)->layer;
|
|
|
|
|
|
|
|
return (layer_a > layer_b) - (layer_a < layer_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* necessary to allow the renderer to draw in batches in the best case */
|
|
|
|
static void sort_sprites(struct sprite_primitive *sprites) {
|
|
|
|
size_t sprites_len = arrlenu(sprites);
|
|
|
|
qsort(sprites, sprites_len, sizeof *sprites, cmp_atlases);
|
|
|
|
qsort(sprites, sprites_len, sizeof *sprites, cmp_blend_modes);
|
|
|
|
qsort(sprites, sprites_len, sizeof *sprites, cmp_colors);
|
|
|
|
qsort(sprites, sprites_len, sizeof *sprites, cmp_layers);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_sprite(struct sprite_primitive *sprite) {
|
|
|
|
SDL_Rect srcrect_value = { 0 };
|
|
|
|
SDL_Rect *srcrect = &srcrect_value;
|
|
|
|
SDL_Texture *texture = NULL;
|
|
|
|
|
|
|
|
/* loner */
|
|
|
|
if (sprite->atlas_index == -1) {
|
|
|
|
srcrect = NULL;
|
|
|
|
texture = textures_get_loner(&ctx.texture_cache, sprite->path);
|
|
|
|
} else {
|
|
|
|
*srcrect = textures_get_srcrect(&ctx.texture_cache, sprite->path);
|
|
|
|
texture = textures_get_atlas(&ctx.texture_cache, sprite->atlas_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_RendererFlip flip = SDL_FLIP_NONE;
|
|
|
|
if (sprite->flip_x)
|
|
|
|
flip |= SDL_FLIP_HORIZONTAL;
|
|
|
|
if (sprite->flip_y)
|
|
|
|
flip |= SDL_FLIP_VERTICAL;
|
|
|
|
|
|
|
|
SDL_SetTextureColorMod(texture,
|
|
|
|
sprite->color.r,
|
|
|
|
sprite->color.g,
|
|
|
|
sprite->color.b);
|
|
|
|
SDL_SetTextureAlphaMod(texture, sprite->color.a);
|
|
|
|
SDL_SetTextureBlendMode(texture, sprite->blend_mode);
|
|
|
|
|
|
|
|
SDL_Rect rect = {
|
|
|
|
(int)sprite->rect.x,
|
|
|
|
(int)sprite->rect.y,
|
|
|
|
(int)sprite->rect.w,
|
|
|
|
(int)sprite->rect.h
|
|
|
|
};
|
|
|
|
|
|
|
|
SDL_RenderCopyEx(ctx.renderer,
|
|
|
|
texture,
|
|
|
|
srcrect,
|
|
|
|
&rect,
|
|
|
|
sprite->rotation,
|
|
|
|
NULL,
|
|
|
|
flip);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_rectangle(struct rect_primitive *rectangle) {
|
|
|
|
SDL_SetRenderDrawColor(ctx.renderer,
|
|
|
|
rectangle->color.r,
|
|
|
|
rectangle->color.g,
|
|
|
|
rectangle->color.b,
|
|
|
|
rectangle->color.a);
|
|
|
|
|
|
|
|
SDL_Rect rect = {
|
|
|
|
(int)rectangle->rect.x,
|
|
|
|
(int)rectangle->rect.y,
|
|
|
|
(int)rectangle->rect.w,
|
|
|
|
(int)rectangle->rect.h
|
|
|
|
};
|
|
|
|
|
|
|
|
SDL_RenderFillRect(ctx.renderer, &rect);
|
|
|
|
SDL_SetRenderDrawColor(ctx.renderer, 255, 255, 255, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* vertices_out and indices_out MUST BE FREED */
|
|
|
|
static void create_circle_geometry(t_fvec2 position,
|
|
|
|
t_color color,
|
|
|
|
float radius,
|
|
|
|
size_t num_vertices,
|
|
|
|
SDL_Vertex **vertices_out,
|
|
|
|
int **indices_out)
|
|
|
|
{
|
|
|
|
SDL_Vertex *vertices = cmalloc(sizeof *vertices * (num_vertices + 1));
|
|
|
|
int *indices = cmalloc(sizeof *indices * (num_vertices * 3));
|
|
|
|
|
|
|
|
/* the angle (in radians) to rotate by on each iteration */
|
|
|
|
float seg_rotation_angle = (360.0f / (float)num_vertices) * ((float)M_PI / 180);
|
|
|
|
|
|
|
|
vertices[0].position.x = (float)position.x;
|
|
|
|
vertices[0].position.y = (float)position.y;
|
|
|
|
vertices[0].color.r = color.r;
|
|
|
|
vertices[0].color.g = color.g;
|
|
|
|
vertices[0].color.b = color.b;
|
|
|
|
vertices[0].color.a = color.a;
|
|
|
|
vertices[0].tex_coord = (SDL_FPoint){ 0, 0 };
|
|
|
|
|
|
|
|
/* this point will rotate around the center */
|
|
|
|
float start_x = 0.0f - radius;
|
|
|
|
float start_y = 0.0f;
|
|
|
|
|
|
|
|
for (size_t i = 1; i < num_vertices + 1; ++i) {
|
|
|
|
float final_seg_rotation_angle = (float)i * seg_rotation_angle;
|
|
|
|
|
|
|
|
vertices[i].position.x =
|
|
|
|
cos(final_seg_rotation_angle) * start_x -
|
|
|
|
sin(final_seg_rotation_angle) * start_y;
|
|
|
|
vertices[i].position.y =
|
|
|
|
cos(final_seg_rotation_angle) * start_y +
|
|
|
|
sin(final_seg_rotation_angle) * start_x;
|
|
|
|
|
|
|
|
vertices[i].position.x += position.x;
|
|
|
|
vertices[i].position.y += position.y;
|
|
|
|
|
|
|
|
vertices[i].color.r = color.r;
|
|
|
|
vertices[i].color.g = color.g;
|
|
|
|
vertices[i].color.b = color.b;
|
|
|
|
vertices[i].color.a = color.a;
|
|
|
|
|
|
|
|
vertices[i].tex_coord = (SDL_FPoint){ 0, 0 };
|
|
|
|
|
|
|
|
|
|
|
|
size_t triangle_offset = 3 * (i - 1);
|
|
|
|
|
|
|
|
/* center point index */
|
|
|
|
indices[triangle_offset] = 0;
|
|
|
|
/* generated point index */
|
|
|
|
indices[triangle_offset + 1] = (int)i;
|
|
|
|
|
|
|
|
size_t index = (i + 1) % num_vertices;
|
|
|
|
if (index == 0)
|
|
|
|
index = num_vertices;
|
|
|
|
indices[triangle_offset + 2] = (int)index;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vertices_out = vertices;
|
|
|
|
*indices_out = indices;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_circle(struct circle_primitive *circle) {
|
|
|
|
SDL_Vertex *vertices = NULL;
|
|
|
|
int *indices = NULL;
|
|
|
|
int num_vertices = (int)circle->radius;
|
|
|
|
|
|
|
|
create_circle_geometry(circle->position,
|
|
|
|
circle->color,
|
|
|
|
circle->radius,
|
|
|
|
num_vertices,
|
|
|
|
&vertices,
|
|
|
|
&indices);
|
|
|
|
|
|
|
|
SDL_RenderGeometry(ctx.renderer, NULL,
|
|
|
|
vertices,
|
|
|
|
num_vertices + 1, /* vertices + center vertex */
|
|
|
|
indices,
|
|
|
|
num_vertices * 3);
|
|
|
|
|
|
|
|
free(vertices);
|
|
|
|
free(indices);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_sprites(void) {
|
|
|
|
sort_sprites(ctx.render_queue_sprites);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arrlenu(ctx.render_queue_sprites); ++i) {
|
|
|
|
render_sprite(&ctx.render_queue_sprites[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_rectangles(void) {
|
|
|
|
for (size_t i = 0; i < arrlenu(ctx.render_queue_rectangles); ++i) {
|
|
|
|
render_rectangle(&ctx.render_queue_rectangles[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_circles(void) {
|
|
|
|
for (size_t i = 0; i < arrlenu(ctx.render_queue_circles); ++i) {
|
|
|
|
render_circle(&ctx.render_queue_circles[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch) {
|
|
|
|
size_t data_len = arrlenu(batch->data);
|
|
|
|
|
|
|
|
/* create vertex array object */
|
|
|
|
if (batch->buffer == 0)
|
|
|
|
glGenBuffers(1, &batch->buffer);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, batch->buffer);
|
|
|
|
|
|
|
|
/* TODO: try using mapped buffers while building batches instead? */
|
|
|
|
/* this way we could skip client side copy that is kept until commitment */
|
|
|
|
/* alternatively we could commit glBufferSubData based on a threshold */
|
|
|
|
|
|
|
|
/* upload batched data */
|
|
|
|
glBufferData(GL_ARRAY_BUFFER,
|
|
|
|
data_len * sizeof (struct uncolored_space_triangle),
|
|
|
|
batch->data,
|
|
|
|
GL_STREAM_DRAW);
|
|
|
|
|
|
|
|
/* vertex specification*/
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
glVertexPointer(3,
|
|
|
|
GL_FLOAT,
|
|
|
|
offsetof(struct uncolored_space_triangle, v1),
|
|
|
|
(void *)offsetof(struct uncolored_space_triangle, v0));
|
|
|
|
|
|
|
|
/* note: propagates further to where texture binding is done */
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glClientActiveTexture(GL_TEXTURE0);
|
|
|
|
glTexCoordPointer(2,
|
|
|
|
GL_SHORT,
|
|
|
|
offsetof(struct uncolored_space_triangle, v1),
|
|
|
|
(void *)offsetof(struct uncolored_space_triangle, uv0));
|
|
|
|
|
|
|
|
// for (size_t i = 0; i < data_len; ++i) {
|
|
|
|
// struct uncolored_space_triangle t = ((struct uncolored_space_triangle *)batch->data)[i];
|
|
|
|
// log_info("{%i, %i, %i, %i, %i, %i}\n", t.uv0.x, t.uv0.y, t.uv1.x, t.uv1.y, t.uv2.x, t.uv2.y);
|
|
|
|
// }
|
|
|
|
|
|
|
|
/* commit for drawing */
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 3 * (int)data_len);
|
|
|
|
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
|
|
|
/* invalidate the buffer immediately */
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-09 12:35:54 +00:00
|
|
|
static void render_space(void) {
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
|
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
glUseProgramObjectARB(0);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
|
|
|
/* solid white, no modulation */
|
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arrlenu(ctx.uncolored_mesh_batches); ++i) {
|
|
|
|
if (arrlenu(&ctx.uncolored_mesh_batches[i].data) > 0) {
|
|
|
|
SDL_Texture *const atlas = textures_get_atlas(&ctx.texture_cache, (int)i);
|
|
|
|
SDL_GL_BindTexture(atlas, NULL, NULL);
|
|
|
|
draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i]);
|
|
|
|
SDL_GL_UnbindTexture(atlas);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < shlenu(ctx.uncolored_mesh_batches_loners); ++i) {
|
|
|
|
if (arrlenu(&ctx.uncolored_mesh_batches_loners[i].value.data) > 0) {
|
|
|
|
SDL_Texture *const atlas = textures_get_loner(&ctx.texture_cache,
|
|
|
|
ctx.uncolored_mesh_batches_loners[i].key);
|
|
|
|
SDL_GL_BindTexture(atlas, NULL, NULL);
|
|
|
|
draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches_loners[i].value);
|
|
|
|
SDL_GL_UnbindTexture(atlas);
|
|
|
|
}
|
|
|
|
}
|
2024-07-09 12:35:54 +00:00
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
void render(void) {
|
2024-07-10 16:15:28 +00:00
|
|
|
if (ctx.texture_cache.is_dirty)
|
|
|
|
textures_update_current_atlas(&ctx.texture_cache);
|
|
|
|
|
2024-07-09 12:35:54 +00:00
|
|
|
glClearColor((1.0f / 255) * 230,
|
|
|
|
(1.0f / 255) * 230,
|
|
|
|
(1.0f / 255) * 230, 1);
|
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT |
|
|
|
|
GL_DEPTH_BUFFER_BIT |
|
|
|
|
GL_STENCIL_BUFFER_BIT);
|
2024-07-08 00:44:20 +00:00
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
// glDisable(GL_CULL_FACE);
|
|
|
|
// glDisable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
|
|
/* TODO: write with no depth test, just fill it in */
|
2024-07-08 00:44:20 +00:00
|
|
|
render_sprites();
|
|
|
|
render_rectangles();
|
|
|
|
render_circles();
|
|
|
|
|
2024-07-10 16:15:28 +00:00
|
|
|
// glEnable(GL_CULL_FACE);
|
|
|
|
// glEnable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
|
|
|
/* TODO: use depth test to optimize gui regions away */
|
|
|
|
render_space();
|
|
|
|
|
2024-07-09 12:35:54 +00:00
|
|
|
SDL_RenderFlush(ctx.renderer);
|
|
|
|
SDL_GL_SwapWindow(ctx.window);
|
2024-07-08 00:44:20 +00:00
|
|
|
}
|