generated from rpuzonas/raylib-cpp-template
update repeat rendering in WebGL
This commit is contained in:
parent
d1af945202
commit
43d09a64ca
418
src/world.cpp
418
src/world.cpp
@ -465,78 +465,6 @@ static inline void append_many_b2b_cmp(World *world, BoidList *local_boids, boid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Dear god :O, this name.
|
|
||||||
static inline void world_compute_local_boids_looping_top_edge(BoidList *local_boids, World *world, ChunkGrid *chunks, uboid_t **static_chunks, boid_cmp *b2b_cmps, int *b2b_cmps_count, int neighbour_y) {
|
|
||||||
Vector2 to_offset = { 0, -world->size.y };
|
|
||||||
|
|
||||||
for (int x = 1; x < chunks->width; x++) {
|
|
||||||
size_t chunk_idx = chunkgrid_get_idx(chunks, x, 0);
|
|
||||||
BoidList *chunk = &chunks->data[chunk_idx];
|
|
||||||
uboid_t *chunk_boids = static_chunks[chunk_idx];
|
|
||||||
|
|
||||||
for (int ox = -1; ox <= 1; ox++) {
|
|
||||||
int neighbour_x = x+ox;
|
|
||||||
if (neighbour_x < 0 || neighbour_x >= chunks->width) continue;
|
|
||||||
size_t neighbour_idx = chunkgrid_get_idx(chunks, neighbour_x, neighbour_y);
|
|
||||||
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
|
|
||||||
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
|
|
||||||
|
|
||||||
for (int i = 0; i < chunk->count; i++) {
|
|
||||||
uboid_t from_boid = chunk_boids[i];
|
|
||||||
append_many_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, to_offset, chunk_boids[i], neighbour_boids, neighbour_chunk->count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Dear god :O, this name.
|
|
||||||
static inline void world_compute_local_boids_looping_left_edge(BoidList *local_boids, World *world, ChunkGrid *chunks, uboid_t **static_chunks, boid_cmp *b2b_cmps, int *b2b_cmps_count, int neighbour_x) {
|
|
||||||
Vector2 to_offset = { -world->size.x, 0 };
|
|
||||||
|
|
||||||
for (int y = 1; y < chunks->height; y++) {
|
|
||||||
size_t chunk_idx = chunkgrid_get_idx(chunks, 0, y);
|
|
||||||
BoidList *chunk = &chunks->data[chunk_idx];
|
|
||||||
uboid_t *chunk_boids = static_chunks[chunk_idx];
|
|
||||||
|
|
||||||
for (int oy = -1; oy <= 1; oy++) {
|
|
||||||
int neighbour_y = y+oy;
|
|
||||||
if (neighbour_y < 0 || neighbour_y >= chunks->height) continue;
|
|
||||||
size_t neighbour_idx = chunkgrid_get_idx(chunks, neighbour_x, neighbour_y);
|
|
||||||
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
|
|
||||||
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
|
|
||||||
|
|
||||||
for (int i = 0; i < chunk->count; i++) {
|
|
||||||
uboid_t from_boid = chunk_boids[i];
|
|
||||||
append_many_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, to_offset, chunk_boids[i], neighbour_boids, neighbour_chunk->count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Dear god :O, this name. PLEASE DO SOMETHING
|
|
||||||
static inline void world_compute_local_boids_looping_top_left(BoidList *local_boids, World *world, ChunkGrid *chunks, uboid_t **static_chunks, boid_cmp *b2b_cmps, int *b2b_cmps_count, int neighbour_x) {
|
|
||||||
Vector2 to_offset = { -world->size.x, 0 };
|
|
||||||
|
|
||||||
for (int y = 1; y < chunks->height; y++) {
|
|
||||||
size_t chunk_idx = chunkgrid_get_idx(chunks, 0, y);
|
|
||||||
BoidList *chunk = &chunks->data[chunk_idx];
|
|
||||||
uboid_t *chunk_boids = static_chunks[chunk_idx];
|
|
||||||
|
|
||||||
for (int oy = -1; oy <= 1; oy++) {
|
|
||||||
int neighbour_y = y+oy;
|
|
||||||
if (neighbour_y < 0 || neighbour_y >= chunks->height) continue;
|
|
||||||
size_t neighbour_idx = chunkgrid_get_idx(chunks, neighbour_x, neighbour_y);
|
|
||||||
BoidList *neighbour_chunk = &chunks->data[neighbour_idx];
|
|
||||||
uboid_t *neighbour_boids = static_chunks[neighbour_idx];
|
|
||||||
|
|
||||||
for (int i = 0; i < chunk->count; i++) {
|
|
||||||
uboid_t from_boid = chunk_boids[i];
|
|
||||||
append_many_b2b_cmp(world, local_boids, b2b_cmps, b2b_cmps_count, to_offset, chunk_boids[i], neighbour_boids, neighbour_chunk->count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void world_compute_local_boids(BoidList *local_boids, World *world, ChunkGrid *chunks) {
|
static void world_compute_local_boids(BoidList *local_boids, World *world, ChunkGrid *chunks) {
|
||||||
Boid *boids = world->boids.data();
|
Boid *boids = world->boids.data();
|
||||||
int boid_count = world->boids.size();
|
int boid_count = world->boids.size();
|
||||||
@ -596,22 +524,7 @@ static void world_compute_local_boids(BoidList *local_boids, World *world, Chunk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For checking neighbours on the edge of the wall
|
// TODO: Check for neighbours between world borders
|
||||||
if (world->looping_walls) {
|
|
||||||
// TODO: Rewrite a nicer version here.
|
|
||||||
|
|
||||||
// world_compute_local_boids_looping_top_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->height-1);
|
|
||||||
// world_compute_local_boids_looping_left_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->width-1);
|
|
||||||
//
|
|
||||||
// if (fmod(world->size.y, chunks->chunk_size) >= 1) {
|
|
||||||
// world_compute_local_boids_looping_top_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->height-2);
|
|
||||||
// }
|
|
||||||
// if (fmod(world->size.x, chunks->chunk_size) >= 1) {
|
|
||||||
// world_compute_local_boids_looping_left_edge(local_boids, world, chunks, static_chunks, b2b_cmps, &b2b_cmps_count, chunks->width-2);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: Check top left chunk
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b2b_cmps_count > 0) {
|
if (b2b_cmps_count > 0) {
|
||||||
world_calc_distances_and_angles(world, local_boids, b2b_cmps, &b2b_cmps_count);
|
world_calc_distances_and_angles(world, local_boids, b2b_cmps, &b2b_cmps_count);
|
||||||
@ -869,37 +782,61 @@ static Rectangle rect_matrix_mul(Rectangle rect, Matrix *mat) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 scale, bool y_flipped) {
|
static void DrawTextureTiled(Texture2D texture, Vector2 texture_size, Vector2 source_size, Rectangle dest, Vector2 scale, bool y_flipped) {
|
||||||
if ((texture.id <= 0)) return;
|
if ((texture.id <= 0)) return;
|
||||||
if ((source.width == 0) || (source.height == 0)) return;
|
if ((source_size.x == 0) || (source_size.y == 0)) return;
|
||||||
|
|
||||||
float tile_width = source.width * scale.x;
|
float tile_width = source_size.x * scale.x;
|
||||||
float tile_height = source.height * scale.y;
|
float tile_height = source_size.y * scale.y;
|
||||||
|
|
||||||
float left_tile_edge = ceil(dest.x / tile_width) * tile_width;
|
if (texture_size.x == source_size.x && texture_size.y == source_size.y) {
|
||||||
float ox = dest.x - left_tile_edge;
|
float left_tile_edge = ceil(dest.x / tile_width) * tile_width;
|
||||||
|
float ox = dest.x - left_tile_edge;
|
||||||
|
|
||||||
float oy = 0;
|
float oy = 0;
|
||||||
if (y_flipped) {
|
if (y_flipped) {
|
||||||
float bottom_edge = (dest.y + dest.height);
|
float bottom_edge = (dest.y + dest.height);
|
||||||
float bottom_tile_edge = floor(bottom_edge / tile_height) * tile_height;
|
float bottom_tile_edge = floor(bottom_edge / tile_height) * tile_height;
|
||||||
oy = (bottom_tile_edge - bottom_edge);
|
oy = (bottom_tile_edge - bottom_edge);
|
||||||
|
} else {
|
||||||
|
float top_tile_edge = ceil(dest.y / tile_height) * tile_height;
|
||||||
|
oy = (dest.y - top_tile_edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTextureWrap(texture, TEXTURE_WRAP_REPEAT);
|
||||||
|
DrawTexturePro(texture, {
|
||||||
|
ox / scale.x,
|
||||||
|
oy / scale.y,
|
||||||
|
source_size.x * scale.x,
|
||||||
|
source_size.y * scale.y * (y_flipped ? -1 : 1)
|
||||||
|
}, dest,
|
||||||
|
{ 0, 0 },
|
||||||
|
0,
|
||||||
|
WHITE
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
float top_tile_edge = ceil(dest.y / tile_height) * tile_height;
|
float from_iy = floor(dest.y / tile_height) * tile_height;
|
||||||
oy = (dest.y - top_tile_edge);
|
float to_iy = ceil((dest.y + dest.height) / tile_height) * tile_height;
|
||||||
}
|
|
||||||
|
|
||||||
SetTextureWrap(texture, TEXTURE_WRAP_REPEAT);
|
float from_ix = floor(dest.x / tile_width) * tile_width;
|
||||||
DrawTexturePro(texture, {
|
float to_ix = ceil((dest.x + dest.width) / tile_width) * tile_width;
|
||||||
source.x + ox / scale.x,
|
|
||||||
source.y + oy / scale.y,
|
// TODO: This loop will overdraw on the edges a bit
|
||||||
source.width * scale.x,
|
for (float iy = from_iy; iy < to_iy; iy += tile_height) {
|
||||||
source.height * scale.y * (y_flipped ? -1 : 1)
|
for (float ix = from_ix; ix < to_ix; ix += tile_width) {
|
||||||
}, dest,
|
DrawTexturePro(texture,
|
||||||
{ 0, 0 },
|
{
|
||||||
0,
|
0,
|
||||||
WHITE
|
texture_size.y-source_size.y,
|
||||||
);
|
source_size.x,
|
||||||
|
source_size.y * (y_flipped ? -1 : 1)
|
||||||
|
},
|
||||||
|
{ ix, iy, tile_width, tile_height },
|
||||||
|
{ 0, 0 },
|
||||||
|
0, WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_rect_inside_rect(Rectangle outer, Rectangle inner) {
|
static bool is_rect_inside_rect(Rectangle outer, Rectangle inner) {
|
||||||
@ -1041,52 +978,73 @@ static void draw_boid_triangles(World *world, Visuals *visuals, Rectangle chunk_
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_boids(World *world, Visuals *visuals) {
|
// https://stackoverflow.com/a/466242
|
||||||
int boid_count = world->boids.size();
|
static uint32_t next_two_power(uint32_t v) {
|
||||||
float chunk_size = world->chunks.chunk_size;
|
v--;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
v++;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vector2 nearest_square_two_power(Vector2 vec) {
|
||||||
|
int size = ceil(MAX(vec.x, vec.y));
|
||||||
|
size = next_two_power(size);
|
||||||
|
return { (float)size, (float)size };
|
||||||
|
}
|
||||||
|
|
||||||
|
static Rectangle get_visible_screen_rect() {
|
||||||
Matrix model_view = rlGetMatrixModelview();
|
Matrix model_view = rlGetMatrixModelview();
|
||||||
Matrix model_view_inv = MatrixInvert(model_view);
|
Matrix model_view_inv = MatrixInvert(model_view);
|
||||||
Rectangle screen_rect = rect_matrix_mul({
|
Rectangle screen_rect = rect_matrix_mul({
|
||||||
0, 0, (float)GetScreenWidth(), (float)GetScreenHeight(),
|
0, 0, (float)GetScreenWidth(), (float)GetScreenHeight(),
|
||||||
}, &model_view_inv);
|
}, &model_view_inv);
|
||||||
|
|
||||||
RPROF_START("Draw boids");
|
return screen_rect;
|
||||||
Vector2 scale = { model_view.m0, model_view.m5 };
|
}
|
||||||
Vector2 *vertices = (Vector2*)arena_malloc(&world->frame_arena, sizeof(Vector2)*boid_count*3);
|
|
||||||
|
|
||||||
if (!world->looping_walls) {
|
static void draw_boids_directly_visible(World *world, Visuals *visuals, Rectangle screen_rect, Vector2 *vertices) {
|
||||||
Rectangle world_rect = { 0, 0, world->size.x, world->size.y };
|
Rectangle world_rect = { 0, 0, world->size.x, world->size.y };
|
||||||
Rectangle visible_world_rect = rect_min_overlap(world_rect, screen_rect);
|
Rectangle visible_world_rect = rect_min_overlap(world_rect, screen_rect);
|
||||||
Rectangle visible_chunks_rect = to_chunk_bounds(visible_world_rect, &world->chunks);
|
Rectangle visible_chunks_rect = to_chunk_bounds(visible_world_rect, &world->chunks);
|
||||||
|
|
||||||
rlDrawRenderBatchActive();
|
// TODO: Add padding to visible area, so boids a bit offscreen could be rendered and still be seen
|
||||||
glUseProgram(visuals->boid_shader.id);
|
rlDrawRenderBatchActive();
|
||||||
Vector4 color = ColorNormalize(visuals->boid_color);
|
glUseProgram(visuals->boid_shader.id);
|
||||||
Matrix mvp = MatrixMultiply(model_view, rlGetMatrixProjection());
|
Vector4 color = ColorNormalize(visuals->boid_color);
|
||||||
rlEnableVertexArray(visuals->boid_shader.vao);
|
Matrix mvp = MatrixMultiply(rlGetMatrixModelview(), rlGetMatrixProjection());
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, visuals->boid_shader.vbo);
|
rlEnableVertexArray(visuals->boid_shader.vao);
|
||||||
glUniformMatrix4fv(visuals->boid_shader.mvp_loc, 1, false, MatrixToFloat(mvp));
|
glBindBuffer(GL_ARRAY_BUFFER, visuals->boid_shader.vbo);
|
||||||
glUniform4f(visuals->boid_shader.frag_color_loc, color.x, color.y, color.z, color.w);
|
glUniformMatrix4fv(visuals->boid_shader.mvp_loc, 1, false, MatrixToFloat(mvp));
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glUniform4f(visuals->boid_shader.frag_color_loc, color.x, color.y, color.z, color.w);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
draw_boid_triangles(world, visuals, visible_chunks_rect, { 0, 0 }, vertices);
|
draw_boid_triangles(world, visuals, visible_chunks_rect, { 0, 0 }, vertices);
|
||||||
rlDisableVertexArray();
|
rlDisableVertexArray();
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
} else if (scale.x >= 1 && scale.y >= 1) {
|
}
|
||||||
float bottom_edge = screen_rect.y + screen_rect.height;
|
|
||||||
float right_edge = screen_rect.x + screen_rect.width;
|
|
||||||
|
|
||||||
float world_ox1 = floor(screen_rect.x / world->size.x) * world->size.x;
|
static void draw_boids_repeating_nearby(World *world, Visuals *visuals, Rectangle screen_rect, Vector2 *vertices) {
|
||||||
float world_oy1 = floor(screen_rect.y / world->size.y) * world->size.y;
|
float bottom_edge = screen_rect.y + screen_rect.height;
|
||||||
float world_ox2 = floor(right_edge / world->size.x) * world->size.x;
|
float right_edge = screen_rect.x + screen_rect.width;
|
||||||
float world_oy2 = floor(bottom_edge / world->size.y) * world->size.y;
|
|
||||||
|
|
||||||
Rectangle visible_worlds[4];
|
float world_ox1 = floor(screen_rect.x / world->size.x) * world->size.x;
|
||||||
int visible_worlds_cnt = 0;
|
float world_oy1 = floor(screen_rect.y / world->size.y) * world->size.y;
|
||||||
|
float world_ox2 = floor(right_edge / world->size.x) * world->size.x;
|
||||||
|
float world_oy2 = floor(bottom_edge / world->size.y) * world->size.y;
|
||||||
|
|
||||||
|
// Because the width of the screen is less than the width of the world.
|
||||||
|
// At most 4 worlds separate worlds can be visible at once.
|
||||||
|
// Determine what sub-rectangles of each world is visible and save it the list.
|
||||||
|
Rectangle visible_worlds[4];
|
||||||
|
int visible_worlds_cnt = 0;
|
||||||
|
{
|
||||||
if (world_ox1 == world_ox2 && world_oy1 == world_oy2) {
|
if (world_ox1 == world_ox2 && world_oy1 == world_oy2) {
|
||||||
visible_worlds[0] = screen_rect;
|
visible_worlds[0] = screen_rect;
|
||||||
visible_worlds_cnt++;
|
visible_worlds_cnt = 1;
|
||||||
} else if (world_oy1 == world_oy2) {
|
} else if (world_oy1 == world_oy2) {
|
||||||
visible_worlds[0] = {
|
visible_worlds[0] = {
|
||||||
screen_rect.x,
|
screen_rect.x,
|
||||||
@ -1100,7 +1058,7 @@ static void draw_boids(World *world, Visuals *visuals) {
|
|||||||
(screen_rect.x + screen_rect.width) - world_ox2,
|
(screen_rect.x + screen_rect.width) - world_ox2,
|
||||||
screen_rect.height
|
screen_rect.height
|
||||||
};
|
};
|
||||||
visible_worlds_cnt+=2;
|
visible_worlds_cnt = 2;
|
||||||
} else if (world_ox1 == world_ox2) {
|
} else if (world_ox1 == world_ox2) {
|
||||||
visible_worlds[0] = {
|
visible_worlds[0] = {
|
||||||
screen_rect.x,
|
screen_rect.x,
|
||||||
@ -1114,7 +1072,7 @@ static void draw_boids(World *world, Visuals *visuals) {
|
|||||||
screen_rect.width,
|
screen_rect.width,
|
||||||
(screen_rect.y + screen_rect.height) - world_oy2,
|
(screen_rect.y + screen_rect.height) - world_oy2,
|
||||||
};
|
};
|
||||||
visible_worlds_cnt+=2;
|
visible_worlds_cnt = 2;
|
||||||
} else {
|
} else {
|
||||||
visible_worlds[0] = {
|
visible_worlds[0] = {
|
||||||
screen_rect.x,
|
screen_rect.x,
|
||||||
@ -1140,79 +1098,121 @@ static void draw_boids(World *world, Visuals *visuals) {
|
|||||||
right_edge - world_ox2,
|
right_edge - world_ox2,
|
||||||
bottom_edge - world_oy2,
|
bottom_edge - world_oy2,
|
||||||
};
|
};
|
||||||
visible_worlds_cnt+=4;
|
visible_worlds_cnt = 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rlDrawRenderBatchActive();
|
// TODO: Add padding to visible area, so boids a bit offscreen could be rendered and still be seen
|
||||||
|
rlDrawRenderBatchActive();
|
||||||
|
glUseProgram(visuals->boid_shader.id);
|
||||||
|
Vector4 color = ColorNormalize(visuals->boid_color);
|
||||||
|
Matrix mvp = MatrixMultiply(rlGetMatrixModelview(), rlGetMatrixProjection());
|
||||||
|
glUniformMatrix4fv(visuals->boid_shader.mvp_loc, 1, false, MatrixToFloat(mvp));
|
||||||
|
glUniform4f(visuals->boid_shader.frag_color_loc, color.x, color.y, color.z, color.w);
|
||||||
|
|
||||||
|
rlEnableVertexArray(visuals->boid_shader.vao);
|
||||||
|
for (int i = 0; i < visible_worlds_cnt; i++) {
|
||||||
|
Rectangle visible_rect = visible_worlds[i];
|
||||||
|
DEBUG_ASSERT(visible_rect.x <= world->size.x);
|
||||||
|
DEBUG_ASSERT(visible_rect.y <= world->size.y);
|
||||||
|
|
||||||
|
float offset_x = 0;
|
||||||
|
float offset_y = 0;
|
||||||
|
if (visible_rect.x < 0) {
|
||||||
|
offset_x -= world->size.x;
|
||||||
|
visible_rect.x += world->size.x;
|
||||||
|
} else if (visible_rect.x >= world->size.x) {
|
||||||
|
offset_x += world->size.x;
|
||||||
|
visible_rect.x -= world->size.x;
|
||||||
|
}
|
||||||
|
if (visible_rect.y < 0) {
|
||||||
|
offset_y -= world->size.y;
|
||||||
|
visible_rect.y += world->size.y;
|
||||||
|
} else if (visible_rect.y >= world->size.y) {
|
||||||
|
offset_y += world->size.y;
|
||||||
|
visible_rect.y -= world->size.y;
|
||||||
|
}
|
||||||
|
Rectangle visible_chunks = to_chunk_bounds(visible_rect, &world->chunks);
|
||||||
|
|
||||||
|
draw_boid_triangles(world, visuals, visible_chunks, { offset_x, offset_y }, vertices);
|
||||||
|
}
|
||||||
|
rlDisableVertexArray();
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_boids_repeating(World *world, Visuals *visuals, Rectangle screen_rect, Vector2 *vertices) {
|
||||||
|
Matrix model_view = rlGetMatrixModelview();
|
||||||
|
Vector2 scale = { model_view.m0, model_view.m5 };
|
||||||
|
|
||||||
|
Vector2 render_size = Vector2Multiply(world->size, scale);
|
||||||
|
|
||||||
|
RenderTexture2D *frame_buffer = &visuals->boid_shader.frame_buffer;
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
// Render buffer on WebGL must be a use powers of 2
|
||||||
|
Vector2 frame_buffer_size = nearest_square_two_power(render_size);
|
||||||
|
#else
|
||||||
|
Vector2 frame_buffer_size = render_size;
|
||||||
|
#endif
|
||||||
|
if (fabs(frame_buffer->texture.width - frame_buffer_size.x) >= 1 || fabs(frame_buffer->texture.height - frame_buffer_size.y) >= 1) {
|
||||||
|
UnloadRenderTexture(visuals->boid_shader.frame_buffer);
|
||||||
|
visuals->boid_shader.frame_buffer = LoadRenderTexture(frame_buffer_size.x, frame_buffer_size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Account for boids which are right on the edge of the world and should be seen on the other side
|
||||||
|
Matrix projection = rlGetMatrixProjection();
|
||||||
|
rlDrawRenderBatchActive();
|
||||||
|
BeginTextureMode(*frame_buffer);
|
||||||
|
Matrix model_view_no_trans = matrix_no_translation(model_view);
|
||||||
|
rlSetMatrixModelview(model_view_no_trans);
|
||||||
|
ClearBackground(visuals->bg_color);
|
||||||
glUseProgram(visuals->boid_shader.id);
|
glUseProgram(visuals->boid_shader.id);
|
||||||
Vector4 color = ColorNormalize(visuals->boid_color);
|
Vector4 color = ColorNormalize(visuals->boid_color);
|
||||||
Matrix mvp = MatrixMultiply(model_view, rlGetMatrixProjection());
|
Matrix render_projection = {
|
||||||
|
2.0f/frame_buffer_size.x, 0, 0, -1,
|
||||||
|
0, -2.0f/frame_buffer_size.y, 0, 1,
|
||||||
|
0, 0, -2, -1,
|
||||||
|
0, 0, 0, 1
|
||||||
|
};
|
||||||
|
Matrix mvp = MatrixMultiply(model_view_no_trans, render_projection);
|
||||||
glUniformMatrix4fv(visuals->boid_shader.mvp_loc, 1, false, MatrixToFloat(mvp));
|
glUniformMatrix4fv(visuals->boid_shader.mvp_loc, 1, false, MatrixToFloat(mvp));
|
||||||
glUniform4f(visuals->boid_shader.frag_color_loc, color.x, color.y, color.z, color.w);
|
glUniform4f(visuals->boid_shader.frag_color_loc, color.x, color.y, color.z, color.w);
|
||||||
|
|
||||||
rlEnableVertexArray(visuals->boid_shader.vao);
|
rlEnableVertexArray(visuals->boid_shader.vao);
|
||||||
for (int i = 0; i < visible_worlds_cnt; i++) {
|
draw_boid_triangles(world, visuals, { 0, 0, (float)world->chunks.width, (float)world->chunks.height }, { 0, 0 }, vertices);
|
||||||
Rectangle visible_rect = visible_worlds[i];
|
|
||||||
DEBUG_ASSERT(visible_rect.x <= world->size.x);
|
|
||||||
DEBUG_ASSERT(visible_rect.y <= world->size.y);
|
|
||||||
|
|
||||||
float offset_x = 0;
|
|
||||||
float offset_y = 0;
|
|
||||||
if (visible_rect.x < 0) {
|
|
||||||
offset_x -= world->size.x;
|
|
||||||
visible_rect.x += world->size.x;
|
|
||||||
} else if (visible_rect.x >= world->size.x) {
|
|
||||||
offset_x += world->size.x;
|
|
||||||
visible_rect.x -= world->size.x;
|
|
||||||
}
|
|
||||||
if (visible_rect.y < 0) {
|
|
||||||
offset_y -= world->size.y;
|
|
||||||
visible_rect.y += world->size.y;
|
|
||||||
} else if (visible_rect.y >= world->size.y) {
|
|
||||||
offset_y += world->size.y;
|
|
||||||
visible_rect.y -= world->size.y;
|
|
||||||
}
|
|
||||||
Rectangle visible_chunks = to_chunk_bounds(visible_rect, &world->chunks);
|
|
||||||
|
|
||||||
draw_boid_triangles(world, visuals, visible_chunks, { offset_x, offset_y }, vertices);
|
|
||||||
}
|
|
||||||
rlDisableVertexArray();
|
rlDisableVertexArray();
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
EndTextureMode();
|
||||||
|
|
||||||
|
rlSetMatrixModelview(model_view);
|
||||||
|
rlSetMatrixProjection(projection);
|
||||||
|
|
||||||
|
DrawTextureTiled(frame_buffer->texture,
|
||||||
|
frame_buffer_size,
|
||||||
|
render_size,
|
||||||
|
screen_rect,
|
||||||
|
Vector2Invert(scale),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_boids(World *world, Visuals *visuals) {
|
||||||
|
RPROF_START("Draw boids");
|
||||||
|
int boid_count = world->boids.size();
|
||||||
|
float chunk_size = world->chunks.chunk_size;
|
||||||
|
|
||||||
|
Rectangle screen_rect = get_visible_screen_rect();
|
||||||
|
Matrix model_view = rlGetMatrixModelview();
|
||||||
|
Vector2 scale = { model_view.m0, model_view.m5 };
|
||||||
|
Vector2 *vertices = (Vector2*)arena_malloc(&world->frame_arena, sizeof(Vector2)*boid_count*3);
|
||||||
|
|
||||||
|
if (!world->looping_walls) {
|
||||||
|
// Case 1: World is not repeating, so just draw the boids which are visible
|
||||||
|
draw_boids_directly_visible(world, visuals, screen_rect, vertices);
|
||||||
|
} else if (scale.x >= 1 && scale.y >= 1) {
|
||||||
|
// Case 2: World is repeating, but each bodi will at most be rendered once
|
||||||
|
draw_boids_repeating_nearby(world, visuals, screen_rect, vertices);
|
||||||
} else {
|
} else {
|
||||||
Vector2 frame_buffer_size = Vector2Multiply(world->size, scale);
|
// Case 3: World is repeating, any boid could be rendered many times
|
||||||
|
draw_boids_repeating(world, visuals, screen_rect, vertices);
|
||||||
RenderTexture2D *frame_buffer = &visuals->boid_shader.frame_buffer;
|
|
||||||
if (fabs(frame_buffer->texture.width - frame_buffer_size.x) >= 1 || fabs(frame_buffer->texture.height - frame_buffer_size.y) >= 1) {
|
|
||||||
UnloadRenderTexture(visuals->boid_shader.frame_buffer);
|
|
||||||
visuals->boid_shader.frame_buffer = LoadRenderTexture(frame_buffer_size.x, frame_buffer_size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix projection = rlGetMatrixProjection();
|
|
||||||
rlDrawRenderBatchActive();
|
|
||||||
BeginTextureMode(*frame_buffer);
|
|
||||||
Matrix model_view_no_trans = matrix_no_translation(model_view);
|
|
||||||
rlSetMatrixModelview(model_view_no_trans);
|
|
||||||
ClearBackground(visuals->bg_color);
|
|
||||||
glUseProgram(visuals->boid_shader.id);
|
|
||||||
Vector4 color = ColorNormalize(visuals->boid_color);
|
|
||||||
Matrix mvp = MatrixMultiply(model_view_no_trans, rlGetMatrixProjection());
|
|
||||||
glUniformMatrix4fv(visuals->boid_shader.mvp_loc, 1, false, MatrixToFloat(mvp));
|
|
||||||
glUniform4f(visuals->boid_shader.frag_color_loc, color.x, color.y, color.z, color.w);
|
|
||||||
|
|
||||||
rlEnableVertexArray(visuals->boid_shader.vao);
|
|
||||||
draw_boid_triangles(world, visuals, { 0, 0, (float)world->chunks.width, (float)world->chunks.height }, { 0, 0 }, vertices);
|
|
||||||
rlDisableVertexArray();
|
|
||||||
glUseProgram(0);
|
|
||||||
EndTextureMode();
|
|
||||||
|
|
||||||
rlSetMatrixModelview(model_view);
|
|
||||||
rlSetMatrixProjection(projection);
|
|
||||||
|
|
||||||
DrawTextureTiled(frame_buffer->texture,
|
|
||||||
{ 0, 0, frame_buffer_size.x, frame_buffer_size.y },
|
|
||||||
screen_rect,
|
|
||||||
Vector2Invert(scale),
|
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
RPROF_STOP();
|
RPROF_STOP();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user