world fixes and water improvements

This commit is contained in:
Tuomas Katajisto 2026-09-29 21:02:08 +03:00
parent 279b7ca81d
commit 0d44c75fa9
8 changed files with 928 additions and 841 deletions

View File

@ -26,6 +26,10 @@ current_editor_view : Editor_View = .Trile_Editor;
in_editor_view : bool = false;
editor_shows_water :: () -> bool {
return current_editor_view == .Level_Editor;
}
init_editor :: () {
#if !FLAG_RELEASE_BUILD {
#if OS != .WASM {

View File

@ -65,8 +65,15 @@ Key_Combo :: struct {
shift : bool;
}
MAX_BINDINGS_PER_ACTION :: 4;
Action_Bindings :: struct {
combos : [MAX_BINDINGS_PER_ACTION]Key_Combo;
count : s32;
}
// 5000 different actions ought to be enough for anything right?
keys : [5000]Key_Combo;
keys : [5000]Action_Bindings;
check_action :: (action: $T, status: Key_Current_State) -> bool {
offset := 0;
@ -75,12 +82,16 @@ check_action :: (action: $T, status: Key_Current_State) -> bool {
}
if console_open_ignore_input then return false;
if ui_keyboard_captured then return false;
combo := keys[cast(s32)action + offset];
bindings := *keys[cast(s32)action + offset];
ctrl_down := cast(bool)(input_button_states[Key_Code.CTRL] & .DOWN);
shift_down := cast(bool)(input_button_states[Key_Code.SHIFT] & .DOWN);
if combo.ctrl != ctrl_down then return false;
if combo.shift != shift_down then return false;
return cast(bool)(input_button_states[combo.key] & status);
for 0..bindings.count-1 {
combo := bindings.combos[it];
if combo.ctrl != ctrl_down then continue;
if combo.shift != shift_down then continue;
if input_button_states[combo.key] & status then return true;
}
return false;
}
@ -92,7 +103,17 @@ set_binding :: (action: $T, combo: Key_Combo) {
offset = EDITOR_ACTION_COUNT;
}
keys[cast(s32)action + offset] = combo;
bindings := *keys[cast(s32)action + offset];
for 0..bindings.count-1 {
c := bindings.combos[it];
if c.key == combo.key && c.ctrl == combo.ctrl && c.shift == combo.shift return;
}
if bindings.count >= MAX_BINDINGS_PER_ACTION {
log_warn("Action % already has % bindings, ignoring %", action, MAX_BINDINGS_PER_ACTION, combo);
return;
}
bindings.combos[bindings.count] = combo;
bindings.count += 1;
}
is_action_down :: (action: $T) -> bool {
@ -116,7 +137,7 @@ get_action_combo :: (action: $T) -> Key_Combo {
#if T != Editor_Action {
offset = EDITOR_ACTION_COUNT;
}
return keys[cast(s32)action + offset];
return keys[cast(s32)action + offset].combos[0];
}
keybind_button :: (r: GR.Rect, label: string, action: Editor_Action, theme: *GR.Button_Theme, loc := #caller_location) -> bool {

View File

@ -112,9 +112,12 @@ add_particle_render_tasks :: () {
batches : [..] Batch;
batches.allocator = temp;
has_water, water_y := particle_water_height();
for *p: g_particles {
if !p.alive then continue;
if p.definition == null then continue;
if has_water && p.position.y < water_y then continue;
def := p.definition;
if def.animation_name.count == 0 then continue;
@ -194,6 +197,15 @@ add_particle_render_tasks :: () {
}
}
particle_water_height :: () -> (has_water: bool, height: float) {
#if !FLAG_RELEASE_BUILD {
if in_editor_view && !editor_shows_water() return false, 0;
}
curworld := get_current_world();
if !curworld.valid return false, 0;
return true, effective_plane_height(*curworld.world.conf);
}
get_emitter_def :: (name: string) -> *Particle_Emitter_Config {
for *def: g_emitter_defs {
if def.name == name then return def;
@ -238,14 +250,6 @@ save_particle_defs :: () {
}
}
#scope_file
Random :: #import "Random";
rng :: inline (lo: float, hi: float) -> float {
return lo + Random.random_get_zero_to_one() * (hi - lo);
}
spawn_one_particle :: (position: Vector3, def: *Particle_Emitter_Config) {
for *p: g_particles {
if p.alive then continue;
@ -268,6 +272,14 @@ spawn_one_particle :: (position: Vector3, def: *Particle_Emitter_Config) {
}
}
#scope_file
Random :: #import "Random";
rng :: inline (lo: float, hi: float) -> float {
return lo + Random.random_get_zero_to_one() * (hi - lo);
}
lerp_color :: (a: Vector4, b: Vector4, t: float) -> Vector4 {
return a * (1.0 - t) + b * t;
}

View File

@ -468,7 +468,7 @@ backend_draw_ground :: (wc: *World_Config) {
plane_data.screen_w = w;
plane_data.screen_h = h;
plane_data.cameraPosition = camera.position.component;
plane_data.reflectionDistortion = 0.1;
plane_data.reflectionDistortion = wc.waterDistortion;
plane_data.shininess = wc.waterShininess;
world_config_to_shader_type(wc, *world_conf);

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@ layout(binding=1) uniform plane_world_config {
vec3 waterColor;
vec3 deepColor;
float time;
float waterReflectivity;
};
layout(binding=2) uniform plane_data {
@ -136,12 +137,12 @@ void main() {
vec2 screen_uv = gl_FragCoord.xy / vec2(screen_w, screen_h);
screen_uv.y = 1.0 - screen_uv.y;
vec2 distortion = normal.xz * 0.007;
vec2 distortion = normal.xz * reflectionDistortion;
vec3 reflected_color = texture(sampler2D(reftex, refsmp), screen_uv + distortion).rgb;
vec3 surface_color = mix(refracted_color, reflected_color, fresnel);
vec3 surface_color = mix(refracted_color, reflected_color, mix(fresnel, 1.0, waterReflectivity));
vec3 final_color = surface_color + specular_highlight;
float alpha = mix(0.3, 0.5, fresnel);
float alpha = mix(mix(0.3, 0.5, fresnel), 1.0, waterReflectivity);
vec3 fog = skyIntensity * sky(normalize(pos.xyz), sunPosition);
float fogFactor = smoothstep(750.0, 1000.0, length(pos.xz));

View File

@ -149,6 +149,7 @@ autoedit :: (rect: GR.Rect, value: *$T, theme: *GR.Overall_Theme, identifier: s3
for ti.members {
if it.flags & .CONSTANT continue;
if it.flags & .USING continue; // e.g. an entity's Entity base
if array_find(it.notes, "NoSave") continue; // runtime state, not for editing
if !autoedit_supports_type(it.type) continue;
print_to_builder(*builder, "%\n", input_code_from_type_and_notes(it.name, it.type, it.notes, it_index));
}

View File

@ -55,6 +55,36 @@ Chunk_Trile_Group :: struct {
is_buried : [..]bool; // Runtime-only, parallel to instances. Not serialized.
}
// Chunk-local, like the instances. Call after changing group.instances.
recompute_group_bounds :: (group: *Chunk_Trile_Group) {
if group.instances.count == 0 {
group.bounding_min = .{};
group.bounding_max = .{};
group.average_pos = .{};
return;
}
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;
}
Chunk :: struct {
coord: Chunk_Key;
groups: [..]Chunk_Trile_Group;
@ -524,6 +554,8 @@ World_Json_Config :: struct {
waterColor : [3]float;
deepColor : [3]float;
waterShininess : float;
waterReflectivity : float = 0.0;
waterDistortion : float = 0.007;
}
World_Json_Chunk :: struct {
@ -685,6 +717,8 @@ world_config_to_json :: (conf: *World_Config) -> World_Json_Config {
jc.waterColor = conf.waterColor.component;
jc.deepColor = conf.deepColor.component;
jc.waterShininess = conf.waterShininess;
jc.waterReflectivity = conf.waterReflectivity;
jc.waterDistortion = conf.waterDistortion;
return jc;
}
@ -705,6 +739,8 @@ world_config_from_json :: (jc: *World_Json_Config) -> World_Config {
conf.waterColor.component = jc.waterColor;
conf.deepColor.component = jc.deepColor;
conf.waterShininess = ifx jc.waterShininess > 0 then jc.waterShininess else 64.0;
conf.waterReflectivity = jc.waterReflectivity;
conf.waterDistortion = jc.waterDistortion;
return conf;
}
@ -837,25 +873,7 @@ load_world_from_json :: (json_str: string, chunk_bin: []u8) -> (World, bool) {
inst := read_value(chunk_data, *chunk_cursor, Trile_Instance);
array_add(*group.instances, inst);
}
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_group_bounds(*group);
array_add(*chunk.groups, group);
}
calculate_and_set_chunk_occupancy_mask(*chunk);
@ -915,6 +933,8 @@ World_Config :: struct {
waterColor : Vector3 = .{1.0, 1.0, 1.0}; @Color // @ToDo: sensible default values.
deepColor : Vector3 = .{1.0, 1.0, 1.0}; @Color // @ToDo: sensible default values.
waterShininess : float = 64.0; @Slider,1,512,8
waterReflectivity : float = 0.0; @Slider,0,1,0.05
waterDistortion : float = 0.007; @Slider,0,0.05,0.001
hsv_lighting : s32 = 1; @Slider,0,1,1
// ambientColor : Vector3 = .{1.0, 1.0, 1.0}; @Color