You've already forked flecs_tests
Tiling system for SDF multi resolution
This commit is contained in:
146
src/main.c
146
src/main.c
@@ -1,25 +1,49 @@
|
|||||||
#include "api.h"
|
#include "api.h"
|
||||||
|
|
||||||
typedef struct uniform_t {
|
#define COMPUTE_VIEWIDX_segments 0
|
||||||
float x, y;
|
#define COMPUTE_VIEWIDX_shapes 1
|
||||||
float zoom;
|
#define COMPUTE_VIEWIDX_SDF 2
|
||||||
} uniform_t;
|
|
||||||
|
#define DISPLAY_VIEWIDX_SDF 0
|
||||||
|
|
||||||
|
typedef struct display_uniforms {
|
||||||
|
uint32_t frame;
|
||||||
|
uint32_t time;
|
||||||
|
|
||||||
|
float mvp[16];
|
||||||
|
} display_uniforms;
|
||||||
|
|
||||||
typedef struct renderer_t {
|
typedef struct renderer_t {
|
||||||
sg_pipeline pipeline;
|
sg_pipeline pipeline;
|
||||||
sg_pass_action clear_pass;
|
sg_pass_action clear_pass;
|
||||||
uniform_t uniforms;
|
sg_bindings bindings;
|
||||||
|
|
||||||
|
display_uniforms uniforms;
|
||||||
} renderer_t;
|
} renderer_t;
|
||||||
|
|
||||||
|
typedef struct compute_uniforms {
|
||||||
|
uint32_t frame;
|
||||||
|
uint32_t time;
|
||||||
|
|
||||||
|
float pan_x, pan_y;
|
||||||
|
float zoom, rotation;
|
||||||
|
} compute_uniforms;
|
||||||
|
|
||||||
typedef struct compute_t {
|
typedef struct compute_t {
|
||||||
sg_pipeline pipeline;
|
sg_pipeline pipeline;
|
||||||
sg_bindings bindings;
|
sg_bindings bindings;
|
||||||
|
|
||||||
|
compute_uniforms uniforms
|
||||||
} compute_t;
|
} compute_t;
|
||||||
|
|
||||||
typedef struct userdata_t {
|
typedef struct userdata_t {
|
||||||
scene_t scene;
|
scene_t scene;
|
||||||
renderer_t renderer;
|
renderer_t renderer;
|
||||||
compute_t compute;
|
compute_t compute;
|
||||||
|
|
||||||
|
//Viewport related values
|
||||||
|
float pan_x, pan_y;
|
||||||
|
float zoom, rotation;
|
||||||
} userdata_t;
|
} userdata_t;
|
||||||
|
|
||||||
static void log_fn(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data)
|
static void log_fn(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data)
|
||||||
@@ -33,34 +57,42 @@ static void log_fn(const char* tag, uint32_t log_level, uint32_t log_item_id, co
|
|||||||
|
|
||||||
static void draw_scene(userdata_t* ud)
|
static void draw_scene(userdata_t* ud)
|
||||||
{
|
{
|
||||||
if(ud->scene.dirty)
|
//Get visible tiles
|
||||||
{
|
float view_world_w = sapp_widthf() * ud->zoom;
|
||||||
sg_buffer seg_buffer = sg_query_view_buffer(ud->compute.bindings.views[0]);
|
float view_world_h = sapp_heightf() * ud->zoom;
|
||||||
//_SG_VALIDATE(seg_buffer.id == SG_INVALID_ID, COMPUTE_INVALID_BUFFER);
|
box_t viewport = (box_t) {
|
||||||
sg_update_buffer(seg_buffer, &(sg_range) { .ptr = ud->scene.segments, .size = sizeof(segment_t) * ud->scene.num_segments });
|
ud->pan_x - view_world_w * 0.5f,
|
||||||
|
ud->pan_y - view_world_h * 0.5f,
|
||||||
|
ud->pan_x + view_world_w * 0.5f,
|
||||||
|
ud->pan_y + view_world_h * 0.5f,
|
||||||
|
};
|
||||||
|
|
||||||
sg_buffer shape_buffer = sg_query_view_buffer(ud->compute.bindings.views[1]);
|
sg_buffer seg_buffer = sg_query_view_buffer(ud->compute.bindings.views[0]);
|
||||||
//_SG_VALIDATE(shape_buffer.id == SG_INVALID_ID, COMPUTE_INVALID_BUFFER);
|
//_SG_VALIDATE(seg_buffer.id == SG_INVALID_ID, COMPUTE_INVALID_BUFFER);
|
||||||
sg_update_buffer(shape_buffer, &(sg_range) { .ptr = ud->scene.shapes, .size = sizeof(shape_meta_t) * ud->scene.num_shapes });
|
sg_update_buffer(seg_buffer, &(sg_range) { .ptr = ud->scene.segments, .size = sizeof(segment_t) * ud->scene.num_segments });
|
||||||
|
|
||||||
sg_begin_pass(&(sg_pass){ .compute = true, .label = "Compute Pass" });
|
sg_buffer shape_buffer = sg_query_view_buffer(ud->compute.bindings.views[1]);
|
||||||
sg_apply_pipeline(ud->compute.pipeline);
|
//_SG_VALIDATE(shape_buffer.id == SG_INVALID_ID, COMPUTE_INVALID_BUFFER);
|
||||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniforms));
|
sg_update_buffer(shape_buffer, &(sg_range) { .ptr = ud->scene.shapes, .size = sizeof(shape_meta_t) * ud->scene.num_shapes });
|
||||||
sg_apply_uniforms(1, &SG_RANGE(ud->scene.tiles[0]));
|
|
||||||
sg_apply_bindings(&ud->compute.bindings);
|
|
||||||
|
|
||||||
sg_dispatch(TILE_SIZE / 8, TILE_SIZE / 8, 1);
|
sg_begin_pass(&(sg_pass){ .compute = true, .label = "Compute Pass" });
|
||||||
|
sg_apply_pipeline(ud->compute.pipeline);
|
||||||
|
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniforms));
|
||||||
|
sg_apply_uniforms(1, &SG_RANGE(ud->scene.LODs));
|
||||||
|
sg_apply_bindings(&ud->compute.bindings);
|
||||||
|
|
||||||
sg_end_pass();
|
sg_dispatch(TILE_SIZE / 8, TILE_SIZE / 8, 1);
|
||||||
|
|
||||||
ud->scene.dirty = false;
|
sg_end_pass();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame(void* _userdata)
|
static void frame(void* _userdata)
|
||||||
{
|
{
|
||||||
userdata_t* ud = (userdata_t*) _userdata;
|
userdata_t* ud = (userdata_t*) _userdata;
|
||||||
|
|
||||||
|
ud->renderer.uniforms.frame = ud->compute.uniforms.frame = sapp_frame_count();
|
||||||
|
ud->renderer.uniforms.time = ud->compute.uniforms.time += sapp_frame_duration_unfiltered();
|
||||||
|
|
||||||
draw_scene(ud);
|
draw_scene(ud);
|
||||||
|
|
||||||
sg_begin_pass(&(sg_pass){
|
sg_begin_pass(&(sg_pass){
|
||||||
@@ -71,13 +103,13 @@ static void frame(void* _userdata)
|
|||||||
simgui_new_frame(&(simgui_frame_desc_t){
|
simgui_new_frame(&(simgui_frame_desc_t){
|
||||||
.width = sapp_width(),
|
.width = sapp_width(),
|
||||||
.height = sapp_height(),
|
.height = sapp_height(),
|
||||||
.delta_time = sapp_frame_duration(),
|
.delta_time = sapp_frame_duration_unfiltered(),
|
||||||
.dpi_scale = sapp_dpi_scale(),
|
.dpi_scale = sapp_dpi_scale(),
|
||||||
});
|
});
|
||||||
|
|
||||||
igBegin("Framerate", (bool*) true, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
igBegin("Framerate", (bool*) true, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||||
igText("%.0f FPS", 1 / sapp_frame_duration());
|
igText("%.0f FPS", 1 / sapp_frame_duration_unfiltered());
|
||||||
igText("%.3fms", sapp_frame_duration() * 1000);
|
igText("%.3fms", sapp_frame_duration_unfiltered() * 1000);
|
||||||
igEnd();
|
igEnd();
|
||||||
|
|
||||||
simgui_render();
|
simgui_render();
|
||||||
@@ -96,7 +128,7 @@ static void init(void* _userdata)
|
|||||||
simgui_setup(&(simgui_desc_t){0});
|
simgui_setup(&(simgui_desc_t){0});
|
||||||
|
|
||||||
ud->scene = (scene_t) {0};
|
ud->scene = (scene_t) {0};
|
||||||
if(!scene_init(&ud->scene, 128, 1024)) return;
|
if(!scene_init(&ud->scene, 128, 1024, (vec2) { 8192.0f, 8192.0f })) return;
|
||||||
|
|
||||||
ud->compute = (compute_t) {
|
ud->compute = (compute_t) {
|
||||||
.pipeline = sg_make_pipeline(&(sg_pipeline_desc){
|
.pipeline = sg_make_pipeline(&(sg_pipeline_desc){
|
||||||
@@ -131,7 +163,7 @@ static void init(void* _userdata)
|
|||||||
},
|
},
|
||||||
.uniform_blocks = {
|
.uniform_blocks = {
|
||||||
[0] = {
|
[0] = {
|
||||||
.size = sizeof(uniform_t),
|
.size = sizeof(compute_uniforms),
|
||||||
.stage = SG_SHADERSTAGE_COMPUTE,
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
.wgsl_group0_binding_n = 0,
|
.wgsl_group0_binding_n = 0,
|
||||||
},
|
},
|
||||||
@@ -146,7 +178,7 @@ static void init(void* _userdata)
|
|||||||
.label = "SDF Compute Pipeline",
|
.label = "SDF Compute Pipeline",
|
||||||
}),
|
}),
|
||||||
.bindings = (sg_bindings) {
|
.bindings = (sg_bindings) {
|
||||||
.views[0] = sg_make_view(&(sg_view_desc) {
|
.views[COMPUTE_VIEWIDX_segments] = sg_make_view(&(sg_view_desc) {
|
||||||
.label = "Segments view",
|
.label = "Segments view",
|
||||||
.storage_buffer = {
|
.storage_buffer = {
|
||||||
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
@@ -159,7 +191,7 @@ static void init(void* _userdata)
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
.views[1] = sg_make_view(&(sg_view_desc) {
|
.views[COMPUTE_VIEWIDX_shapes] = sg_make_view(&(sg_view_desc) {
|
||||||
.label = "Shapes metadata view",
|
.label = "Shapes metadata view",
|
||||||
.storage_buffer = {
|
.storage_buffer = {
|
||||||
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
@@ -172,19 +204,33 @@ static void init(void* _userdata)
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
.views[2] = sg_make_view(&(sg_view_desc) {
|
.views[COMPUTE_VIEWIDX_SDF] = sg_make_view(&(sg_view_desc) {
|
||||||
.label = "SDF field view",
|
.label = "SDF tiles view",
|
||||||
.storage_buffer = {
|
.storage_image = {
|
||||||
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
.image = sg_make_image(&(sg_image_desc) {
|
||||||
.label = "SDF field buffer",
|
.height = TILE_SIZE,
|
||||||
.size = sizeof(float),
|
.width = TILE_SIZE,
|
||||||
.usage.storage_buffer = true,
|
.label = "SDF tiles texture",
|
||||||
|
.num_slices = TILE_LAYERS,
|
||||||
|
.pixel_format = SG_PIXELFORMAT_R32F,
|
||||||
|
.type = SG_IMAGETYPE_ARRAY,
|
||||||
|
.usage = { .storage_image = true },
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const vec2 quad[4] = {
|
||||||
|
{ 0.0f, 1.0f }, // bottom left
|
||||||
|
{ 1.0f, 1.0f }, // bottom right
|
||||||
|
{ 1.0f, 0.0f }, // top right
|
||||||
|
{ 0.0f, 0.0f }, // top left
|
||||||
|
};
|
||||||
|
const uint16_t indices[] = {
|
||||||
|
0, 1, 2, 0, 2, 3,
|
||||||
|
};
|
||||||
|
|
||||||
ud->renderer = (renderer_t) {
|
ud->renderer = (renderer_t) {
|
||||||
.pipeline = sg_make_pipeline(&(sg_pipeline_desc){
|
.pipeline = sg_make_pipeline(&(sg_pipeline_desc){
|
||||||
.shader = sg_make_shader(&(sg_shader_desc) {
|
.shader = sg_make_shader(&(sg_shader_desc) {
|
||||||
@@ -197,7 +243,7 @@ static void init(void* _userdata)
|
|||||||
.entry = "fs_main",
|
.entry = "fs_main",
|
||||||
},
|
},
|
||||||
.views = {
|
.views = {
|
||||||
[0] = {
|
[DISPLAY_VIEWIDX_SDF] = {
|
||||||
.storage_buffer = {
|
.storage_buffer = {
|
||||||
.stage = SG_SHADERSTAGE_FRAGMENT,
|
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||||
.wgsl_group1_binding_n = 1,
|
.wgsl_group1_binding_n = 1,
|
||||||
@@ -207,7 +253,7 @@ static void init(void* _userdata)
|
|||||||
},
|
},
|
||||||
.uniform_blocks = {
|
.uniform_blocks = {
|
||||||
[0] = {
|
[0] = {
|
||||||
.size = sizeof(uniform_t),
|
.size = sizeof(display_uniforms),
|
||||||
.stage = SG_SHADERSTAGE_VERTEX,
|
.stage = SG_SHADERSTAGE_VERTEX,
|
||||||
.wgsl_group0_binding_n = 0,
|
.wgsl_group0_binding_n = 0,
|
||||||
},
|
},
|
||||||
@@ -219,16 +265,38 @@ static void init(void* _userdata)
|
|||||||
},
|
},
|
||||||
.label = "Display Shader",
|
.label = "Display Shader",
|
||||||
}),
|
}),
|
||||||
|
.cull_mode = SG_CULLMODE_FRONT,
|
||||||
|
.index_type = SG_INDEXTYPE_UINT16,
|
||||||
|
.layout.attrs = {
|
||||||
|
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
|
},
|
||||||
.label = "Render pipeline",
|
.label = "Render pipeline",
|
||||||
}),
|
}),
|
||||||
.clear_pass = (sg_pass_action) {
|
.clear_pass = (sg_pass_action) {
|
||||||
.colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR }
|
.colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR }
|
||||||
|
},
|
||||||
|
.bindings = {
|
||||||
|
.index_buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
|
.label = "Index buffer",
|
||||||
|
.usage.index_buffer = true,
|
||||||
|
.size = sizeof(uint16_t),
|
||||||
|
.data = SG_RANGE(indices),
|
||||||
|
}),
|
||||||
|
.vertex_buffers = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
|
.label = "Vertex buffer",
|
||||||
|
.usage.vertex_buffer = true,
|
||||||
|
.size = sizeof(vec2),
|
||||||
|
.data = SG_RANGE(quad),
|
||||||
|
}),
|
||||||
|
.views = {
|
||||||
|
[DISPLAY_VIEWIDX_SDF] = ud->compute.bindings.views[COMPUTE_VIEWIDX_SDF]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
add_rectangle(&ud->scene, (vec2) { 200.0f, 100.0f }, (vec2) { 100.0f, 150.0f });
|
add_rectangle(&ud->scene, (vec2) { 200.0f, 100.0f }, (vec2) { 100.0f, 150.0f });
|
||||||
add_circle(&ud->scene, (vec2) { 400.0f, 300.0f }, 125.0f);
|
add_circle(&ud->scene, (vec2) { 400.0f, 300.0f }, 125.0f);
|
||||||
scene_add_tile(&ud->scene, (tile_cache_entry) { .id = { .lod = 0, .tile = TILE_SIZE, .world_min = { 0.0f, 0.0f }, .world_max = { 1024.0f, 1024.0f } } });
|
scene_add_tile(&ud->scene, (tile_ID) { .lod = 0, .tile = TILE_SIZE, .bounds = { 0.0f, 0.0f, 1024.0f, 1024.0f } });
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup(void* _userdata)
|
static void cleanup(void* _userdata)
|
||||||
|
|||||||
115
src/shape.h
115
src/shape.h
@@ -3,6 +3,10 @@
|
|||||||
typedef struct uvec2 { uint32_t x, y; } uvec2;
|
typedef struct uvec2 { uint32_t x, y; } uvec2;
|
||||||
typedef struct vec2 { float x, y; } vec2;
|
typedef struct vec2 { float x, y; } vec2;
|
||||||
|
|
||||||
|
typedef struct box_t {
|
||||||
|
float min_x, min_y, max_x, max_y;
|
||||||
|
} box_t;
|
||||||
|
|
||||||
typedef struct segment_t {
|
typedef struct segment_t {
|
||||||
vec2 p0, p1, p2, p3; // cubic Bézier: start, control1, control2, end
|
vec2 p0, p1, p2, p3; // cubic Bézier: start, control1, control2, end
|
||||||
} segment_t;
|
} segment_t;
|
||||||
@@ -14,26 +18,32 @@ typedef struct shape_meta_t {
|
|||||||
} shape_meta_t;
|
} shape_meta_t;
|
||||||
|
|
||||||
#define TILE_SIZE 128 // pixels per tile (same for all LODs)
|
#define TILE_SIZE 128 // pixels per tile (same for all LODs)
|
||||||
|
#define TILE_LAYERS 256 // 16 MB buffer
|
||||||
|
|
||||||
// Tile descriptor
|
#define _INTERSECTS(a, b) !(b.min_x > a.max_x \
|
||||||
|
|| b.max_x < a.min_x \
|
||||||
|
|| b.min_y > a.max_y \
|
||||||
|
|| b.max_y < a.min_y)
|
||||||
|
|
||||||
|
// Tile descriptor (separated from tile_cache_entry to be sent to the GPU)
|
||||||
typedef struct tile_ID {
|
typedef struct tile_ID {
|
||||||
uint32_t lod; // LOD level (0 = coarsest)
|
uint32_t lod;
|
||||||
uvec2 tile; // position in the grid at that LOD
|
uvec2 tile;
|
||||||
|
|
||||||
// world-space bounds (derived from lod, tile_x, tile_y)
|
// Cached tile bounds
|
||||||
vec2 world_min;
|
box_t bounds;
|
||||||
vec2 world_max;
|
|
||||||
} tile_ID;
|
} tile_ID;
|
||||||
|
|
||||||
// Tile cache entry (CPU side)
|
typedef struct LOD_t {
|
||||||
typedef struct tile_cache_entry {
|
tile_ID* tiles;
|
||||||
tile_ID id;
|
|
||||||
// GPU texture holding the SDF values (R32Float)
|
uvec2 dimension; //Tile amount per dimension
|
||||||
sg_buffer SDF; //TODO
|
vec2 range; //Zoom min-max range
|
||||||
bool ready;
|
} LOD_t;
|
||||||
} tile_cache_entry;
|
|
||||||
|
|
||||||
typedef struct scene_t {
|
typedef struct scene_t {
|
||||||
|
vec2 world_size;
|
||||||
|
|
||||||
uint32_t num_shapes;
|
uint32_t num_shapes;
|
||||||
uint32_t max_shapes;
|
uint32_t max_shapes;
|
||||||
shape_meta_t* shapes;
|
shape_meta_t* shapes;
|
||||||
@@ -42,15 +52,17 @@ typedef struct scene_t {
|
|||||||
uint32_t max_segments;
|
uint32_t max_segments;
|
||||||
segment_t* segments;
|
segment_t* segments;
|
||||||
|
|
||||||
uint32_t num_tiles;
|
//Theorically, the LOD amount and tile per LOD are computable, so it's not relevant to store them.
|
||||||
uint32_t max_tiles;
|
uint32_t max_LOD;
|
||||||
tile_cache_entry* tiles;
|
LOD_t* LODs;
|
||||||
|
|
||||||
bool dirty;
|
sg_view texture_cache;
|
||||||
} scene_t;
|
} scene_t;
|
||||||
|
|
||||||
|
typedef int (*tile_callback)(scene_t* s, tile_ID* tile);
|
||||||
|
|
||||||
// Initialise a scene_t with a given capacity for shapes and segments.
|
// Initialise a scene_t with a given capacity for shapes and segments.
|
||||||
static int scene_init(scene_t* s, int init_shape_cap, int init_seg_cap) {
|
static int scene_init(scene_t* s, int init_shape_cap, int init_seg_cap, vec2 world_size) {
|
||||||
s->num_shapes = 0;
|
s->num_shapes = 0;
|
||||||
s->max_shapes = init_shape_cap;
|
s->max_shapes = init_shape_cap;
|
||||||
s->shapes = (shape_meta_t*) malloc(init_shape_cap * sizeof(shape_meta_t));
|
s->shapes = (shape_meta_t*) malloc(init_shape_cap * sizeof(shape_meta_t));
|
||||||
@@ -59,16 +71,49 @@ static int scene_init(scene_t* s, int init_shape_cap, int init_seg_cap) {
|
|||||||
s->max_segments = init_seg_cap;
|
s->max_segments = init_seg_cap;
|
||||||
s->segments = (segment_t*) malloc(init_seg_cap * sizeof(segment_t));
|
s->segments = (segment_t*) malloc(init_seg_cap * sizeof(segment_t));
|
||||||
|
|
||||||
s->num_tiles = 0;
|
const uint32_t max_LOD = max(ceilf(log2(world_size.x / TILE_SIZE)), ceilf(log2(world_size.y / TILE_SIZE)));
|
||||||
s->max_tiles = 8;
|
|
||||||
s->tiles = (tile_cache_entry*) malloc(8 * sizeof(tile_cache_entry));
|
|
||||||
|
|
||||||
s->dirty = true;
|
s->max_LOD = max_LOD;
|
||||||
|
s->LODs = malloc(max_LOD * sizeof(LOD_t));
|
||||||
|
for(int i = 0; i < max_LOD; ++i)
|
||||||
|
{
|
||||||
|
const float factor = 1 << i;
|
||||||
|
s->LODs[i].dimension = (uvec2) { (uint32_t) ceilf(world_size.x * factor / TILE_SIZE), (uint32_t) ceilf(world_size.y * factor / TILE_SIZE) };
|
||||||
|
|
||||||
if (!s->shapes || !s->segments || !s->tiles) return 0; // allocation failure
|
const uint32_t tiles_count = s->LODs[i].dimension.x * s->LODs[i].dimension.y;
|
||||||
|
s->LODs[i].tiles = malloc(sizeof(tile_ID) * tiles_count);
|
||||||
|
|
||||||
|
s->LODs[i].range = (vec2) { }; //TODO
|
||||||
|
|
||||||
|
uint32_t x = 0; uint32_t y = 0;
|
||||||
|
for(int j = 0; j < tiles_count; j++)
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
if(x >= s->LODs[i].dimension.x) { x = 0; y++; }
|
||||||
|
|
||||||
|
s->LODs[i].tiles[j] = (tile_ID) { .bounds = { x * factor, y * factor, (x + 1) * factor, (y + 1) * factor }, .lod = i, .tile = { x, y } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->world_size = world_size;
|
||||||
|
|
||||||
|
if (!s->shapes || !s->segments || !s->LODs) return 0; // allocation failure
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Viewport bounds in *world* space
|
||||||
|
static void scene_for_each_tiles(scene_t* s, box_t viewport, tile_callback callback)
|
||||||
|
{
|
||||||
|
const uint32_t lod = 0;
|
||||||
|
const uint32_t count = s->LODs[lod].dimension.x * s->LODs[lod].dimension.y;
|
||||||
|
for(uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
tile_ID tile = s->LODs[lod].tiles[i];
|
||||||
|
if(_INTERSECTS(tile.bounds, viewport))
|
||||||
|
callback(s, &tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Append a segment, returns its index. (Reallocs if needed, simplified.)
|
// Append a segment, returns its index. (Reallocs if needed, simplified.)
|
||||||
static int scene_add_segment(scene_t* s, segment_t seg) {
|
static int scene_add_segment(scene_t* s, segment_t seg) {
|
||||||
if (s->num_segments >= s->max_segments) {
|
if (s->num_segments >= s->max_segments) {
|
||||||
@@ -81,7 +126,6 @@ static int scene_add_segment(scene_t* s, segment_t seg) {
|
|||||||
int idx = s->num_segments++;
|
int idx = s->num_segments++;
|
||||||
s->segments[idx] = seg;
|
s->segments[idx] = seg;
|
||||||
|
|
||||||
s->dirty = true;
|
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,30 +141,17 @@ static int scene_add_shape(scene_t* s, shape_meta_t meta) {
|
|||||||
int idx = s->num_shapes++;
|
int idx = s->num_shapes++;
|
||||||
s->shapes[idx] = meta;
|
s->shapes[idx] = meta;
|
||||||
|
|
||||||
s->dirty = true;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int scene_add_tile(scene_t* s, tile_cache_entry tile)
|
|
||||||
{
|
|
||||||
if (s->num_tiles >= s->max_tiles) {
|
|
||||||
int new_cap = s->max_tiles * 2;
|
|
||||||
tile_cache_entry* tmp = (tile_cache_entry*) realloc(s->tiles, new_cap * sizeof(tile_cache_entry));
|
|
||||||
if (!tmp) return -1;
|
|
||||||
s->tiles = tmp;
|
|
||||||
s->max_tiles = new_cap;
|
|
||||||
}
|
|
||||||
int idx = s->num_tiles++;
|
|
||||||
s->tiles[idx] = tile;
|
|
||||||
|
|
||||||
s->dirty = true;
|
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scene_shutdown(scene_t* s) {
|
static int scene_shutdown(scene_t* s) {
|
||||||
free(s->segments);
|
free(s->segments);
|
||||||
free(s->shapes);
|
free(s->shapes);
|
||||||
free(s->tiles);
|
|
||||||
|
for(uint32_t i = 0; i < s->max_LOD; ++i)
|
||||||
|
free(s->LODs[i].tiles);
|
||||||
|
|
||||||
|
free(s->LODs);
|
||||||
|
|
||||||
free(s);
|
free(s);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user