upload wip work from desktop to take with me on laptop
This commit is contained in:
parent
c27fa53236
commit
3bff0f9501
@ -320,6 +320,14 @@ draw_tools_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
|
|||||||
r.h = ui_h(4, 0);
|
r.h = ui_h(4, 0);
|
||||||
|
|
||||||
if keybind_button(r, "Save world", .SAVE, *theme.button_theme) then sworld();
|
if keybind_button(r, "Save world", .SAVE, *theme.button_theme) then sworld();
|
||||||
|
r.y += r.h;
|
||||||
|
if GR.button(r, "Delete buried triles", *theme.button_theme, 400) {
|
||||||
|
curworld := get_current_world();
|
||||||
|
if curworld.valid {
|
||||||
|
removed := delete_buried_triles(*curworld.world);
|
||||||
|
log_info("Deleted % buried triles\n", removed);
|
||||||
|
}
|
||||||
|
}
|
||||||
r.y += r.h * 2;
|
r.y += r.h * 2;
|
||||||
|
|
||||||
// Tool mode buttons
|
// Tool mode buttons
|
||||||
@ -479,7 +487,6 @@ add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
|
|||||||
array_add(*group.instances, inst);
|
array_add(*group.instances, inst);
|
||||||
array_add(*chunk.groups, group);
|
array_add(*chunk.groups, group);
|
||||||
}
|
}
|
||||||
invalidate_buried_around(*curworld.world, x, y, z);
|
|
||||||
} @Command
|
} @Command
|
||||||
|
|
||||||
remove_trile :: (x: s32, y: s32, z: s32) {
|
remove_trile :: (x: s32, y: s32, z: s32) {
|
||||||
@ -491,21 +498,14 @@ remove_trile :: (x: s32, y: s32, z: s32) {
|
|||||||
|
|
||||||
lx, ly, lz := world_to_local(x, y, z);
|
lx, ly, lz := world_to_local(x, y, z);
|
||||||
|
|
||||||
removed := false;
|
|
||||||
for *group: chunk.groups {
|
for *group: chunk.groups {
|
||||||
for inst, idx: group.instances {
|
for inst, idx: group.instances {
|
||||||
if inst.x == lx && inst.y == ly && inst.z == lz {
|
if inst.x == lx && inst.y == ly && inst.z == lz {
|
||||||
array_unordered_remove_by_index(*group.instances, idx);
|
array_unordered_remove_by_index(*group.instances, idx);
|
||||||
if group.is_buried.count > idx {
|
return;
|
||||||
array_unordered_remove_by_index(*group.is_buried, idx);
|
|
||||||
}
|
|
||||||
removed = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if removed break;
|
|
||||||
}
|
}
|
||||||
if removed invalidate_buried_around(*curworld.world, x, y, z);
|
|
||||||
} @Command
|
} @Command
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -164,11 +164,7 @@ draw_particle_editor_ui :: (theme: *GR.Overall_Theme) {
|
|||||||
|
|
||||||
er.y += er.h;
|
er.y += er.h;
|
||||||
|
|
||||||
alive_count : s32 = 0;
|
pe_label(*er, tprint("Alive particles: %", count_alive_particles()), theme);
|
||||||
for p : g_particles {
|
|
||||||
if p.alive then alive_count += 1;
|
|
||||||
}
|
|
||||||
pe_label(*er, tprint("Alive particles: %", alive_count), theme);
|
|
||||||
pe_label(*er, tprint("Emitter defs: %", g_emitter_defs.count), theme);
|
pe_label(*er, tprint("Emitter defs: %", g_emitter_defs.count), theme);
|
||||||
pe_label(*er, tprint("Preview active: %", pe_preview_emitter.active), theme);
|
pe_label(*er, tprint("Preview active: %", pe_preview_emitter.active), theme);
|
||||||
pe_label(*er, tprint("Preview def: %", pe_preview_emitter.definition != null), theme);
|
pe_label(*er, tprint("Preview def: %", pe_preview_emitter.definition != null), theme);
|
||||||
|
|||||||
@ -41,25 +41,61 @@ Particle :: struct {
|
|||||||
definition : *Particle_Emitter_Config;
|
definition : *Particle_Emitter_Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAX_PARTICLES :: 16384;
|
BUCKET_MAX_PARTICLES :: 2048;
|
||||||
|
PARTICLE_BUCKETS :: 16;
|
||||||
|
MAX_PARTICLES :: PARTICLE_BUCKETS * BUCKET_MAX_PARTICLES;
|
||||||
|
|
||||||
|
|
||||||
|
Particle_Bucket :: struct {
|
||||||
|
in_use : bool;
|
||||||
|
name : string;
|
||||||
|
particles : [BUCKET_MAX_PARTICLES] Particle;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_particle_buckets : [PARTICLE_BUCKETS] Particle_Bucket;
|
||||||
|
|
||||||
|
Particle_Render_Buffer :: struct {
|
||||||
|
total_count : s32;
|
||||||
|
pos_size : [MAX_PARTICLES] Vector4;
|
||||||
|
uv_rects : [MAX_PARTICLES] Vector4;
|
||||||
|
colors : [MAX_PARTICLES] Vector4;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_particle_render_buffer : Particle_Render_Buffer;
|
||||||
|
|
||||||
g_particles : [MAX_PARTICLES] Particle;
|
|
||||||
g_emitter_defs : [..] Particle_Emitter_Config;
|
g_emitter_defs : [..] Particle_Emitter_Config;
|
||||||
|
|
||||||
clear_particles :: () {
|
clear_particles :: () {
|
||||||
for *p: g_particles p.alive = false;
|
for *bucket: g_particle_buckets {
|
||||||
|
bucket.in_use = false;
|
||||||
|
bucket.name = "";
|
||||||
|
for *p: bucket.particles p.alive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count_alive_particles :: () -> s32 {
|
||||||
|
count : s32 = 0;
|
||||||
|
for *bucket: g_particle_buckets {
|
||||||
|
if !bucket.in_use then continue;
|
||||||
|
for p: bucket.particles {
|
||||||
|
if p.alive then count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick_particles_physics :: (dt: float) {
|
tick_particles_physics :: (dt: float) {
|
||||||
for *p: g_particles {
|
for *bucket: g_particle_buckets {
|
||||||
if !p.alive then continue;
|
for *p: bucket.particles {
|
||||||
p.age += dt;
|
if !p.alive then continue;
|
||||||
if p.age >= p.lifetime {
|
p.age += dt;
|
||||||
p.alive = false;
|
if p.age >= p.lifetime {
|
||||||
continue;
|
p.alive = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p.velocity.y -= p.gravity * dt;
|
||||||
|
p.position += p.velocity * dt;
|
||||||
}
|
}
|
||||||
p.velocity.y -= p.gravity * dt;
|
|
||||||
p.position += p.velocity * dt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,99 +134,66 @@ tick_emitter_instance :: (inst: *Particle_Emitter_Instance, dt: float) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add_particle_render_tasks :: () {
|
add_particle_render_tasks :: () {
|
||||||
Batch :: struct {
|
buf := *g_particle_render_buffer;
|
||||||
anim_name : string;
|
|
||||||
blend_mode : Particle_Blend_Mode;
|
|
||||||
anim : *Animation;
|
|
||||||
sheet : sg_image;
|
|
||||||
count : s32;
|
|
||||||
pos_size : *[MAX_PARTICLES]Vector4;
|
|
||||||
uv_rects : *[MAX_PARTICLES]Vector4;
|
|
||||||
colors : *[MAX_PARTICLES]Vector4;
|
|
||||||
}
|
|
||||||
|
|
||||||
batches : [..] Batch;
|
|
||||||
batches.allocator = temp;
|
|
||||||
|
|
||||||
for *p: g_particles {
|
|
||||||
if !p.alive then continue;
|
|
||||||
if p.definition == null then continue;
|
|
||||||
def := p.definition;
|
|
||||||
if def.animation_name.count == 0 then continue;
|
|
||||||
|
|
||||||
batch : *Batch = null;
|
|
||||||
for *b: batches {
|
|
||||||
if b.anim_name == def.animation_name && b.blend_mode == def.blend_mode {
|
|
||||||
batch = b;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if batch == null {
|
|
||||||
anim := get_animation_from_string(def.animation_name);
|
|
||||||
if anim == null then continue;
|
|
||||||
if anim.frames.count == 0 then continue;
|
|
||||||
array_add(*batches, .{
|
|
||||||
anim_name = def.animation_name,
|
|
||||||
blend_mode = def.blend_mode,
|
|
||||||
anim = anim,
|
|
||||||
sheet = anim.sheet,
|
|
||||||
pos_size = New([MAX_PARTICLES]Vector4,, temp),
|
|
||||||
uv_rects = New([MAX_PARTICLES]Vector4,, temp),
|
|
||||||
colors = New([MAX_PARTICLES]Vector4,, temp),
|
|
||||||
});
|
|
||||||
batch = *batches[batches.count - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if batch.count >= MAX_PARTICLES then continue;
|
|
||||||
|
|
||||||
t := p.age / p.lifetime;
|
|
||||||
size := def.size_start + (def.size_end - def.size_start) * t;
|
|
||||||
col := lerp_color(def.color_start, def.color_end, t);
|
|
||||||
|
|
||||||
idx := batch.count;
|
|
||||||
batch.pos_size.*[idx] = .{p.position.x, p.position.y, p.position.z, size};
|
|
||||||
|
|
||||||
anim := batch.anim;
|
|
||||||
frame_count := anim.frames.count;
|
|
||||||
frame := cast(s32)(t * cast(float)frame_count);
|
|
||||||
if frame < 0 then frame = 0;
|
|
||||||
if frame >= frame_count then frame = cast(s32)(frame_count - 1);
|
|
||||||
f := anim.frames[frame];
|
|
||||||
batch.uv_rects.*[idx] = .{
|
|
||||||
cast(float)f.x / cast(float)anim.sheet_w,
|
|
||||||
cast(float)f.y / cast(float)anim.sheet_h,
|
|
||||||
cast(float)f.w / cast(float)anim.sheet_w,
|
|
||||||
cast(float)f.h / cast(float)anim.sheet_h,
|
|
||||||
};
|
|
||||||
|
|
||||||
batch.colors.*[idx] = col;
|
|
||||||
batch.count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf_task := New(Rendering_Task_Particles_Buffer,, temp);
|
|
||||||
total_count : s32 = 0;
|
total_count : s32 = 0;
|
||||||
|
|
||||||
for *b: batches {
|
for *bucket: g_particle_buckets {
|
||||||
if b.count <= 0 then continue;
|
if !bucket.in_use then continue;
|
||||||
|
|
||||||
|
def := get_emitter_def(bucket.name);
|
||||||
|
if def == null then continue;
|
||||||
|
if def.animation_name.count == 0 then continue;
|
||||||
|
|
||||||
|
anim := get_animation_from_string(def.animation_name);
|
||||||
|
if anim == null then continue;
|
||||||
|
if anim.frames.count == 0 then continue;
|
||||||
|
|
||||||
instance_offset := total_count;
|
instance_offset := total_count;
|
||||||
memcpy(*buf_task.pos_size[instance_offset], cast(*void)b.pos_size, b.count * size_of(Vector4));
|
bucket_count : s32 = 0;
|
||||||
memcpy(*buf_task.uv_rects[instance_offset], cast(*void)b.uv_rects, b.count * size_of(Vector4));
|
|
||||||
memcpy(*buf_task.colors[instance_offset], cast(*void)b.colors, b.count * size_of(Vector4));
|
|
||||||
total_count += b.count;
|
|
||||||
|
|
||||||
draw_task : Rendering_Task_Particles;
|
for *p: bucket.particles {
|
||||||
draw_task.count = b.count;
|
if !p.alive then continue;
|
||||||
draw_task.instance_offset = instance_offset;
|
if total_count + bucket_count >= MAX_PARTICLES then break;
|
||||||
draw_task.blend_mode = b.blend_mode;
|
|
||||||
draw_task.sheet = b.sheet;
|
t := p.age / p.lifetime;
|
||||||
add_rendering_task(draw_task);
|
size := def.size_start + (def.size_end - def.size_start) * t;
|
||||||
|
col := lerp_color(def.color_start, def.color_end, t);
|
||||||
|
|
||||||
|
idx := instance_offset + bucket_count;
|
||||||
|
buf.pos_size[idx] = .{p.position.x, p.position.y, p.position.z, size};
|
||||||
|
|
||||||
|
frame_count := anim.frames.count;
|
||||||
|
frame := cast(s32)(t * cast(float)frame_count);
|
||||||
|
if frame < 0 then frame = 0;
|
||||||
|
if frame >= frame_count then frame = cast(s32)(frame_count - 1);
|
||||||
|
f := anim.frames[frame];
|
||||||
|
buf.uv_rects[idx] = .{
|
||||||
|
cast(float)f.x / cast(float)anim.sheet_w,
|
||||||
|
cast(float)f.y / cast(float)anim.sheet_h,
|
||||||
|
cast(float)f.w / cast(float)anim.sheet_w,
|
||||||
|
cast(float)f.h / cast(float)anim.sheet_h,
|
||||||
|
};
|
||||||
|
buf.colors[idx] = col;
|
||||||
|
bucket_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if bucket_count > 0 {
|
||||||
|
draw_task : Rendering_Task_Particles;
|
||||||
|
draw_task.count = bucket_count;
|
||||||
|
draw_task.instance_offset = instance_offset;
|
||||||
|
draw_task.blend_mode = def.blend_mode;
|
||||||
|
draw_task.sheet = anim.sheet;
|
||||||
|
add_rendering_task(draw_task);
|
||||||
|
total_count += bucket_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf.total_count = total_count;
|
||||||
|
|
||||||
if total_count > 0 {
|
if total_count > 0 {
|
||||||
buf_task.total_count = total_count;
|
upload_task : Rendering_Task_Particles_Buffer;
|
||||||
add_rendering_task(buf_task.*);
|
upload_task.total_count = total_count;
|
||||||
|
add_rendering_task(upload_task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,8 +249,24 @@ rng :: inline (lo: float, hi: float) -> float {
|
|||||||
return lo + Random.random_get_zero_to_one() * (hi - lo);
|
return lo + Random.random_get_zero_to_one() * (hi - lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
find_or_claim_bucket :: (name: string) -> *Particle_Bucket {
|
||||||
|
free_slot : *Particle_Bucket = null;
|
||||||
|
for *bucket: g_particle_buckets {
|
||||||
|
if bucket.in_use && bucket.name == name then return bucket;
|
||||||
|
if !bucket.in_use && free_slot == null then free_slot = bucket;
|
||||||
|
}
|
||||||
|
if free_slot {
|
||||||
|
free_slot.in_use = true;
|
||||||
|
free_slot.name = name;
|
||||||
|
}
|
||||||
|
return free_slot;
|
||||||
|
}
|
||||||
|
|
||||||
spawn_one_particle :: (position: Vector3, def: *Particle_Emitter_Config) {
|
spawn_one_particle :: (position: Vector3, def: *Particle_Emitter_Config) {
|
||||||
for *p: g_particles {
|
bucket := find_or_claim_bucket(def.name);
|
||||||
|
if bucket == null then return;
|
||||||
|
|
||||||
|
for *p: bucket.particles {
|
||||||
if p.alive then continue;
|
if p.alive then continue;
|
||||||
p.alive = true;
|
p.alive = true;
|
||||||
p.age = 0;
|
p.age = 0;
|
||||||
|
|||||||
@ -110,9 +110,6 @@ Render_Command_Update_Particles :: struct {
|
|||||||
#as using c : Render_Command;
|
#as using c : Render_Command;
|
||||||
c.type = .UPDATE_PARTICLES;
|
c.type = .UPDATE_PARTICLES;
|
||||||
total_count : s32;
|
total_count : s32;
|
||||||
pos_size : [MAX_PARTICLES]Vector4;
|
|
||||||
uv_rects : [MAX_PARTICLES]Vector4;
|
|
||||||
colors : [MAX_PARTICLES]Vector4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Render_Command_Draw_Particles :: struct {
|
Render_Command_Draw_Particles :: struct {
|
||||||
|
|||||||
@ -544,9 +544,9 @@ backend_update_particle_buffers :: (cmd: *Render_Command_Update_Particles) {
|
|||||||
inst_buf1 := gPipelines.particle_additive.bind.vertex_buffers[1];
|
inst_buf1 := gPipelines.particle_additive.bind.vertex_buffers[1];
|
||||||
inst_buf2 := gPipelines.particle_additive.bind.vertex_buffers[2];
|
inst_buf2 := gPipelines.particle_additive.bind.vertex_buffers[2];
|
||||||
inst_buf3 := gPipelines.particle_additive.bind.vertex_buffers[3];
|
inst_buf3 := gPipelines.particle_additive.bind.vertex_buffers[3];
|
||||||
sg_update_buffer(inst_buf1, *(sg_range.{ ptr = cmd.pos_size.data, size = byte_size }));
|
sg_update_buffer(inst_buf1, *(sg_range.{ ptr = g_particle_render_buffer.pos_size.data, size = byte_size }));
|
||||||
sg_update_buffer(inst_buf2, *(sg_range.{ ptr = cmd.uv_rects.data, size = byte_size }));
|
sg_update_buffer(inst_buf2, *(sg_range.{ ptr = g_particle_render_buffer.uv_rects.data, size = byte_size }));
|
||||||
sg_update_buffer(inst_buf3, *(sg_range.{ ptr = cmd.colors.data, size = byte_size }));
|
sg_update_buffer(inst_buf3, *(sg_range.{ ptr = g_particle_render_buffer.colors.data, size = byte_size }));
|
||||||
}
|
}
|
||||||
|
|
||||||
backend_draw_particles :: (cmd: *Render_Command_Draw_Particles) {
|
backend_draw_particles :: (cmd: *Render_Command_Draw_Particles) {
|
||||||
|
|||||||
@ -102,9 +102,11 @@ create_world_rendering_tasks :: (world: *World, camera: Camera, plane_height: fl
|
|||||||
|
|
||||||
gmin := group.bounding_min;
|
gmin := group.bounding_min;
|
||||||
gmax := group.bounding_max;
|
gmax := group.bounding_max;
|
||||||
|
gavg := group.average_pos;
|
||||||
|
|
||||||
gmin += Vector3.{cast(float)chunk.coord.x * 32, cast(float)chunk.coord.y * 32, cast(float)chunk.coord.z * 32};
|
gmin += Vector3.{cast(float)chunk.coord.x * 32, cast(float)chunk.coord.y * 32, cast(float)chunk.coord.z * 32};
|
||||||
gmax += Vector3.{cast(float)chunk.coord.x * 32, cast(float)chunk.coord.y * 32, cast(float)chunk.coord.z * 32};
|
gmax += Vector3.{cast(float)chunk.coord.x * 32, cast(float)chunk.coord.y * 32, cast(float)chunk.coord.z * 32};
|
||||||
|
gavg += Vector3.{cast(float)chunk.coord.x * 32, cast(float)chunk.coord.y * 32, cast(float)chunk.coord.z * 32};
|
||||||
in_cam := aabb_in_frustum(cam_planes, gmin, gmax);
|
in_cam := aabb_in_frustum(cam_planes, gmin, gmax);
|
||||||
in_reflect := aabb_in_frustum(reflect_planes, gmin, gmax);
|
in_reflect := aabb_in_frustum(reflect_planes, gmin, gmax);
|
||||||
in_shad := aabb_in_frustum(shadow_planes, gmin, gmax);
|
in_shad := aabb_in_frustum(shadow_planes, gmin, gmax);
|
||||||
@ -112,7 +114,7 @@ create_world_rendering_tasks :: (world: *World, camera: Camera, plane_height: fl
|
|||||||
|
|
||||||
if !vis then continue;
|
if !vis then continue;
|
||||||
|
|
||||||
diff := group.average_pos - camera.position;
|
diff := gavg - camera.position;
|
||||||
dist := length(diff);
|
dist := length(diff);
|
||||||
lod_index : s32 = 0;
|
lod_index : s32 = 0;
|
||||||
for lod_dist : LOD_DISTANCES {
|
for lod_dist : LOD_DISTANCES {
|
||||||
|
|||||||
@ -98,9 +98,6 @@ Rendering_Task_Particles_Buffer :: struct {
|
|||||||
#as using t : Rendering_Task;
|
#as using t : Rendering_Task;
|
||||||
t.type = .PARTICLES_BUFFER;
|
t.type = .PARTICLES_BUFFER;
|
||||||
total_count : s32;
|
total_count : s32;
|
||||||
pos_size : [MAX_PARTICLES]Vector4;
|
|
||||||
uv_rects : [MAX_PARTICLES]Vector4;
|
|
||||||
colors : [MAX_PARTICLES]Vector4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rendering_Task_Set_Camera :: struct {
|
Rendering_Task_Set_Camera :: struct {
|
||||||
@ -216,9 +213,6 @@ tasks_to_commands :: () {
|
|||||||
bufTask := cast(*Rendering_Task_Particles_Buffer)it;
|
bufTask := cast(*Rendering_Task_Particles_Buffer)it;
|
||||||
uploadCmd := New(Render_Command_Update_Particles,, temp);
|
uploadCmd := New(Render_Command_Update_Particles,, temp);
|
||||||
uploadCmd.total_count = bufTask.total_count;
|
uploadCmd.total_count = bufTask.total_count;
|
||||||
memcpy(uploadCmd.pos_size.data, bufTask.pos_size.data, bufTask.total_count * size_of(Vector4));
|
|
||||||
memcpy(uploadCmd.uv_rects.data, bufTask.uv_rects.data, bufTask.total_count * size_of(Vector4));
|
|
||||||
memcpy(uploadCmd.colors.data, bufTask.colors.data, bufTask.total_count * size_of(Vector4));
|
|
||||||
array_add(*render_command_buckets.setup, uploadCmd);
|
array_add(*render_command_buckets.setup, uploadCmd);
|
||||||
case .PARTICLES;
|
case .PARTICLES;
|
||||||
particleTask := cast(*Rendering_Task_Particles)it;
|
particleTask := cast(*Rendering_Task_Particles)it;
|
||||||
|
|||||||
149
src/world.jai
149
src/world.jai
@ -52,7 +52,6 @@ Chunk_Trile_Group :: struct {
|
|||||||
average_pos : Vector3;
|
average_pos : Vector3;
|
||||||
|
|
||||||
instances : [..]Trile_Instance;
|
instances : [..]Trile_Instance;
|
||||||
is_buried : [..]bool; // Runtime-only, parallel to instances. Not serialized.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk :: struct {
|
Chunk :: struct {
|
||||||
@ -217,7 +216,6 @@ unload_current_world :: () {
|
|||||||
for *chunk: current_world.world.chunks {
|
for *chunk: current_world.world.chunks {
|
||||||
for *group: chunk.groups {
|
for *group: chunk.groups {
|
||||||
array_free(group.instances);
|
array_free(group.instances);
|
||||||
array_free(group.is_buried);
|
|
||||||
}
|
}
|
||||||
array_free(chunk.groups);
|
array_free(chunk.groups);
|
||||||
}
|
}
|
||||||
@ -232,9 +230,6 @@ set_loaded_world :: (world: World) {
|
|||||||
current_world.world = world;
|
current_world.world = world;
|
||||||
current_world.valid = true;
|
current_world.valid = true;
|
||||||
resolve_emitter_definitions(*current_world.world);
|
resolve_emitter_definitions(*current_world.world);
|
||||||
for *chunk: current_world.world.chunks {
|
|
||||||
recompute_buried_for_chunk(*current_world.world, chunk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_cell_opaque :: (name: string) -> bool {
|
is_cell_opaque :: (name: string) -> bool {
|
||||||
@ -259,81 +254,100 @@ trile_at_world :: (world: *World, wx: s32, wy: s32, wz: s32) -> string {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
BURIED_DIRS :: s32.[ 1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1 ];
|
recompute_group_bounds :: (group: *Chunk_Trile_Group) {
|
||||||
|
if group.instances.count == 0 {
|
||||||
compute_buried_at_world :: (world: *World, wx: s32, wy: s32, wz: s32) -> bool {
|
group.bounding_min = .{};
|
||||||
for axis: 0..5 {
|
group.bounding_max = .{};
|
||||||
nwx := wx + BURIED_DIRS[axis*3+0];
|
group.average_pos = .{};
|
||||||
nwy := wy + BURIED_DIRS[axis*3+1];
|
return;
|
||||||
nwz := wz + BURIED_DIRS[axis*3+2];
|
|
||||||
if !is_cell_opaque(trile_at_world(world, nwx, nwy, nwz)) return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
gmin := Vector3.{31, 31, 31};
|
||||||
|
gmax := Vector3.{0, 0, 0};
|
||||||
|
gavg := Vector3.{0, 0, 0};
|
||||||
|
for i : group.instances {
|
||||||
|
gmin.x = min(gmin.x, xx i.x);
|
||||||
|
gmin.y = min(gmin.y, xx i.y);
|
||||||
|
gmin.z = min(gmin.z, xx i.z);
|
||||||
|
gmax.x = max(gmax.x, xx i.x);
|
||||||
|
gmax.y = max(gmax.y, xx i.y);
|
||||||
|
gmax.z = max(gmax.z, xx i.z);
|
||||||
|
gavg += Vector3.{xx i.x, xx i.y, xx i.z};
|
||||||
|
}
|
||||||
|
gavg /= cast(float) group.instances.count;
|
||||||
|
group.bounding_min = gmin;
|
||||||
|
group.bounding_max = gmax;
|
||||||
|
group.average_pos = gavg;
|
||||||
}
|
}
|
||||||
|
|
||||||
recompute_buried_for_chunk :: (world: *World, chunk: *Chunk) {
|
// Scans every chunk for triles whose 6 axis-aligned neighbors are all opaque,
|
||||||
// Build an O(1) local lookup grid (32^3 trile names) for this chunk so the
|
// and removes them. One-shot — operates against a snapshot of the original
|
||||||
// common in-chunk neighbor case is a single index lookup. Cross-chunk
|
// state so a fully-enclosed cluster is removed in a single pass.
|
||||||
// neighbors fall back to trile_at_world.
|
delete_buried_triles :: (world: *World) -> s32 {
|
||||||
|
NEIGHBOR_DIRS :: s32.[ 1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1 ];
|
||||||
GRID :: CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
GRID :: CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
||||||
grid: [GRID] string;
|
|
||||||
grid_data := grid;
|
cell_idx :: (lx: u8, ly: u8, lz: u8) -> int {
|
||||||
for *group: chunk.groups {
|
return cast(int)lx + CHUNK_SIZE * (cast(int)ly + CHUNK_SIZE * cast(int)lz);
|
||||||
for inst: group.instances {
|
}
|
||||||
idx := cast(int)inst.x + CHUNK_SIZE * (cast(int)inst.y + CHUNK_SIZE * cast(int)inst.z);
|
|
||||||
grid_data[idx] = group.trile_name;
|
build_chunk_grid :: (chunk: *Chunk, grid: *[GRID]string) {
|
||||||
|
for *group : chunk.groups {
|
||||||
|
for inst : group.instances grid.*[cell_idx(inst.x, inst.y, inst.z)] = group.trile_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for *group: chunk.groups {
|
neighbor_trile_name :: (world: *World, chunk_coord: Chunk_Key, grid: *[GRID]string, wx: s32, wy: s32, wz: s32) -> string {
|
||||||
array_resize(*group.is_buried, group.instances.count);
|
if world_to_chunk_coord(wx, wy, wz) == chunk_coord {
|
||||||
for inst, i: group.instances {
|
lx, ly, lz := world_to_local(wx, wy, wz);
|
||||||
wx, wy, wz := chunk_local_to_world(chunk.coord, inst.x, inst.y, inst.z);
|
return grid.*[cell_idx(lx, ly, lz)];
|
||||||
buried := true;
|
}
|
||||||
for axis: 0..5 {
|
return trile_at_world(world, wx, wy, wz);
|
||||||
nwx := wx + BURIED_DIRS[axis*3+0];
|
}
|
||||||
nwy := wy + BURIED_DIRS[axis*3+1];
|
|
||||||
nwz := wz + BURIED_DIRS[axis*3+2];
|
is_buried :: (world: *World, chunk_coord: Chunk_Key, grid: *[GRID]string, lx: u8, ly: u8, lz: u8) -> bool {
|
||||||
neighbor_name: string;
|
wx0, wy0, wz0 := chunk_local_to_world(chunk_coord, lx, ly, lz);
|
||||||
nkey := world_to_chunk_coord(nwx, nwy, nwz);
|
for axis : 0..5 {
|
||||||
if nkey == chunk.coord {
|
name := neighbor_trile_name(world, chunk_coord, grid,
|
||||||
nlx, nly, nlz := world_to_local(nwx, nwy, nwz);
|
wx0 + NEIGHBOR_DIRS[axis*3+0],
|
||||||
nidx := cast(int)nlx + CHUNK_SIZE * (cast(int)nly + CHUNK_SIZE * cast(int)nlz);
|
wy0 + NEIGHBOR_DIRS[axis*3+1],
|
||||||
neighbor_name = grid_data[nidx];
|
wz0 + NEIGHBOR_DIRS[axis*3+2]);
|
||||||
} else {
|
if !is_cell_opaque(name) then return false;
|
||||||
neighbor_name = trile_at_world(world, nwx, nwy, nwz);
|
}
|
||||||
}
|
return true;
|
||||||
if !is_cell_opaque(neighbor_name) {
|
}
|
||||||
buried = false;
|
|
||||||
break;
|
Pending :: struct {
|
||||||
}
|
group : *Chunk_Trile_Group;
|
||||||
|
indices : [..]s32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pending : [..]Pending;
|
||||||
|
pending.allocator = temp;
|
||||||
|
|
||||||
|
for *chunk : world.chunks {
|
||||||
|
grid : [GRID]string;
|
||||||
|
build_chunk_grid(chunk, *grid);
|
||||||
|
|
||||||
|
for *group : chunk.groups {
|
||||||
|
pr : Pending;
|
||||||
|
pr.group = group;
|
||||||
|
pr.indices.allocator = temp;
|
||||||
|
for inst, i : group.instances {
|
||||||
|
if is_buried(world, chunk.coord, *grid, inst.x, inst.y, inst.z) then array_add(*pr.indices, cast(s32) i);
|
||||||
}
|
}
|
||||||
group.is_buried[i] = buried;
|
if pr.indices.count > 0 then array_add(*pending, pr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
recompute_buried_at_cell :: (world: *World, wx: s32, wy: s32, wz: s32) {
|
total : s32 = 0;
|
||||||
key := world_to_chunk_coord(wx, wy, wz);
|
for pr : pending {
|
||||||
chunk := table_find_pointer(*world.chunks, key);
|
for < k : 0..pr.indices.count - 1 {
|
||||||
if !chunk return;
|
array_unordered_remove_by_index(*pr.group.instances, pr.indices[k]);
|
||||||
lx, ly, lz := world_to_local(wx, wy, wz);
|
total += 1;
|
||||||
for *group: chunk.groups {
|
|
||||||
for inst, i: group.instances {
|
|
||||||
if inst.x == lx && inst.y == ly && inst.z == lz {
|
|
||||||
if group.is_buried.count != group.instances.count array_resize(*group.is_buried, group.instances.count);
|
|
||||||
group.is_buried[i] = compute_buried_at_world(world, wx, wy, wz);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
recompute_group_bounds(pr.group);
|
||||||
}
|
}
|
||||||
}
|
return total;
|
||||||
|
|
||||||
invalidate_buried_around :: (world: *World, wx: s32, wy: s32, wz: s32) {
|
|
||||||
recompute_buried_at_cell(world, wx, wy, wz);
|
|
||||||
for axis: 0..5 {
|
|
||||||
recompute_buried_at_cell(world, wx + BURIED_DIRS[axis*3+0], wy + BURIED_DIRS[axis*3+1], wz + BURIED_DIRS[axis*3+2]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve_emitter_definitions :: (world: *World) {
|
resolve_emitter_definitions :: (world: *World) {
|
||||||
@ -347,7 +361,6 @@ clear_world :: () {
|
|||||||
for *chunk: current_world.world.chunks {
|
for *chunk: current_world.world.chunks {
|
||||||
for *group: chunk.groups {
|
for *group: chunk.groups {
|
||||||
array_free(group.instances);
|
array_free(group.instances);
|
||||||
array_free(group.is_buried);
|
|
||||||
}
|
}
|
||||||
array_free(chunk.groups);
|
array_free(chunk.groups);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user