so much work on lighting

This commit is contained in:
Tuomas Katajisto 2026-02-19 22:53:11 +02:00
parent 81b1a407ae
commit afcafce59c
30 changed files with 6815 additions and 4052 deletions

Binary file not shown.

View File

@ -1,621 +0,0 @@
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)
_______________
Vulkan Version:
- available: 1.4.309
- requesting: 1.3.0
______________________
Used Instance Layers :
VK_LAYER_KHRONOS_validation
Used Instance Extensions :
____________________
Devices : 1
0: AMD Radeon RX 6950 XT
- Compatible
Compatible physical devices found : 1
Using Device:
- Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD
- Driver Version : 2.0.341
- API Version : 1.4.308
- Device Type : Discrete GPU
________________________
Used Device Extensions :
VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure
VK_KHR_ray_query
BLAS Compaction: 1.0MB -> 0.3MB (0.6MB saved, 66.2% smaller)

Binary file not shown.

View File

@ -3,51 +3,52 @@
#scope_export
Sky_Config :: struct {
skyBase : Vector3 = .{0.5, 0.5, 1.0};
skyTop : Vector3 = .{0.8, 0.8, 1.0};
sunDisk : Vector3;
horizonHalo : Vector3;
sunHalo : Vector3;
sunLightColor : Vector3 = .{1.0, 1.0, 1.0};
sunPosition : Vector3 = #run normalize(Vector3.{0.5, 0.5, 0.5});
sunIntensity : float = 1.0;
skyIntensity : float = 10.0;
skyBase : Vector3 = .{0.5, 0.5, 1.0};
skyTop : Vector3 = .{0.8, 0.8, 1.0};
sunDisk : Vector3;
horizonHalo : Vector3;
sunHalo : Vector3;
sunLightColor : Vector3 = .{1.0, 1.0, 1.0};
sunPosition : Vector3 = #run normalize(Vector3.{0.5, 0.5, 0.5});
sunIntensity : float = 1.0;
skyIntensity : float = 10.0;
}
Trixel_Data :: struct {
empty : bool = false;
color : Vector3 = .{1.0, 0.0, 0.0};
material : float = 1.0;
empty : bool = false;
color : Vector3 = .{1.0, 0.0, 0.0};
material : float = 1.0;
}
Trile_Data :: struct {
trixels : [16][16][16]Trixel_Data;
vertices : *float;
vertexCount : s32;
trixels : [16][16][16]Trixel_Data;
vertices : *float;
vertexCount : s32;
}
Trile_Set :: struct {
triles : *Trile_Data;
count : s32;
triles : *Trile_Data;
count : s32;
}
World_Trile :: struct {
index : s32;
position : Vector3;
index : s32;
position : Vector3;
}
World :: struct {
triles : *World_Trile;
count : s32;
triles : *World_Trile;
count : s32;
}
Gen_Config :: struct {
target : Vector3 = .{0.0, 0.0, 0.0};
eye : Vector3 = .{5.0, 5.0, 5.0};
samples : s32 = 100;
render_water : bool = false;
}
Tacoma_Context :: struct {}
do_gen :: (path: *u8, rwidth: s32, rheight: s32, sky: Sky_Config, ts: Trile_Set, world: World, config: Gen_Config) -> *float #foreign libtacoma "do_gen";
tacoma_init :: (base_path: *u8) -> *Tacoma_Context #foreign libtacoma;
tacoma_destroy :: (ctx: *Tacoma_Context) #foreign libtacoma;
tacoma_load_scene :: (ctx: *Tacoma_Context, sky: Sky_Config, ts: Trile_Set, world: World, include_water: s32) #foreign libtacoma;
tacoma_render_rdm :: (ctx: *Tacoma_Context, world_trile_index: s32, roughness: s32, quality: s32, out_width: *s32, out_height: *s32) -> *float #foreign libtacoma;
tacoma_render_reference :: (ctx: *Tacoma_Context, width: s32, height: s32, eye: Vector3, target: Vector3, roughness: float, quality: s32) -> *float #foreign libtacoma;
tacoma_free_result :: (data: *float) #foreign libtacoma;
libtacoma :: #library "libtacoma";

View File

@ -6,7 +6,8 @@ hash :: #import "Hash";
#load "loaders.jai";
MAX_FILE_SIZE :: 200_000_000;
buf : [MAX_FILE_SIZE]u8;
buf : [MAX_FILE_SIZE]u8;
world_buf : [MAX_FILE_SIZE]u8;
Pack_Request :: struct {
name : string;
@ -15,10 +16,16 @@ Pack_Request :: struct {
shouldBlockEngine : bool; // Means that the engine loop should do nothing while this is loading...
}
World_Load_Request :: struct {
name : string;
pending : bool = false;
loading : bool = false;
}
Asset_Manager :: struct {
packQueue : [..]Pack_Request;
loadedPacks : [..]Loaded_Pack;
packQueue : [..]Pack_Request;
loadedPacks : [..]Loaded_Pack;
worldRequest : World_Load_Request;
}
g_asset_manager : Asset_Manager;
@ -38,6 +45,26 @@ packcb :: (res: *sfetch_response_t) #c_call {
array_unordered_remove_by_index(*g_asset_manager.packQueue, 0);
}
worldcb :: (res: *sfetch_response_t) #c_call {
push_context,defer_pop default_context;
if res.failed {
print("Failed to load world '%'\n", g_asset_manager.worldRequest.name);
g_asset_manager.worldRequest = .{};
return;
}
data: []u8;
data.data = res.data.ptr;
data.count = res.data.size.(s64);
world, ok := load_world_from_data(data);
if ok {
set_loaded_world(world);
print("Loaded world: %\n", world.name);
} else {
print("Failed to parse world '%'\n", g_asset_manager.worldRequest.name);
}
g_asset_manager.worldRequest = .{};
}
Loaded_Pack :: struct {
name : string;
nameHash : u32 = 0;
@ -158,6 +185,7 @@ mandatory_loads_done :: () -> bool {
}
show_loading_screen :: () -> bool {
if g_asset_manager.worldRequest.pending return true;
for g_asset_manager.packQueue {
if it.shouldBlock return true;
}
@ -176,9 +204,30 @@ asset_manager_tick :: () {
}));
g_asset_manager.packQueue[0].loading = true;
}
if g_asset_manager.worldRequest.pending && !g_asset_manager.worldRequest.loading {
sfetch_send(*(sfetch_request_t.{
path = to_c_string(tprint("./game/resources/worlds/%/index.world", g_asset_manager.worldRequest.name)),
callback = worldcb,
buffer = .{
ptr = world_buf.data,
size = world_buf.count
}
}));
g_asset_manager.worldRequest.loading = true;
}
sfetch_dowork();
}
load_world :: (name: string) {
unload_current_world();
g_asset_manager.worldRequest = .{
name = name,
pending = true,
};
}
load_pack :: (name: string, shouldBlock: bool = true, shouldBlockEngine: bool = false) {
array_add(*g_asset_manager.packQueue, .{
name = name,

View File

@ -17,6 +17,7 @@ Mixer_Play_Task :: struct {
audio : *Audio_Data;
bus : Mixer_Bus;
mode : Play_Mode;
unique : bool = true;
curSample : s64 = 0;
startTime : float64 = 0;
@ -28,12 +29,13 @@ Mixer_Config :: struct {
musicVolume : float = 0.5; @Slider,0,1,0.1
masterVolume : float = 0.5; @Slider,0,1,0.1
dialogueVolume : float = 0.5; @Slider,0,1,0.1
soundEffectVolume : float = 0.5; @Slider,0,1,0.1
soundEffectVolume : float = 0.3; @Slider,0,1,0.1
}
g_mixer : Mixer;
Mixer :: struct {
paused : bool = false;
#if OS != .WASM {
// If we are on WASM, the Thread module mutex does not work.
// Fortunately we don't need a mutex for this, since sokol does
@ -53,6 +55,11 @@ Mixer :: struct {
mixer_add_task :: (task: Mixer_Play_Task) {
mixer_lock(*g_mixer);
defer mixer_unlock(*g_mixer);
if task.unique {
for g_mixer.tasks {
if it.audio == task.audio then return;
}
}
array_add(*g_mixer.tasks, task);
}
@ -71,6 +78,7 @@ mixer_get_samples :: (buffer: *float, frame_count: s32, channel_count: s32) {
total_samples := frame_count * channel_count;
memset(buffer, 0, total_samples * size_of(float));
if g_mixer.paused then return;
if g_mixer.tasks.count < 1 then return;
for < i : 0..g_mixer.tasks.count-1 {
@ -105,24 +113,23 @@ mixer_get_samples :: (buffer: *float, frame_count: s32, channel_count: s32) {
}
}
cursor := task.curSample;
for ch : 0..channel_count-1 {
out_index := (f * channel_count) + ch;
offset := ifx source_channels == 1 then 0 else ch;
sample : float = 0;
if cursor + offset < source_data.count {
sample = source_data[cursor + offset];
if task.curSample + f + offset < source_data.count {
sample = source_data[task.curSample + f + offset];
}
buffer[out_index] += sample * vol;
}
task.curSample += source_channels;
}
task.curSample += frame_count;
if task_finished {
array_unordered_remove_by_index(*g_mixer.tasks, i);
}

View File

@ -87,6 +87,7 @@ draw_editor :: () {
tick_editor_ui :: () {
if input_button_states[Key_Code.F3] & .START {
in_editor_view = !in_editor_view;
g_mixer.paused = in_editor_view;
}
#if OS != .WASM {

View File

@ -178,15 +178,30 @@ draw_tacoma_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
#if HAS_TACOMA {
if GR.button(r, "Render with Tacoma", *theme.button_theme) {
cam := get_level_editor_camera();
gen_reference(tacomaResolution, tacomaResolution, .{cam.target, cam.position, tacomaSamples, true}, curworld.world.*);
gen_reference(tacomaResolution, tacomaResolution, cam.position, cam.target, tacomaSamples, true, curworld.world);
}
r.y += r.h;
if GR.button(r, "Render a RDM", *theme.button_theme) {
gen_rdm(tacomaSamples, true, curworld.world);
}
r.y += r.h;
if GR.button(r, "Bake all chunk RDMs", *theme.button_theme) {
if curworld.valid then rdm_bake_all_chunks(curworld.world, tacomaSamples, true);
}
r.y += r.h;
if rdm_bake.active {
total := cast(s32) rdm_bake.jobs.count;
done := rdm_bake.current_job;
pct := ifx total > 0 then done * 100 / total else 0;
GR.label(r, tprint("Baking RDMs: %/% (\%%)", done, total, pct), *t_label_left(theme));
r.y += r.h;
}
if current_screenshot.valid {
aspect := cast(float)current_screenshot.width / cast(float)current_screenshot.height;
r.h = r.w / aspect;
uiTex := New(Ui_Texture,, temp);
uiTex.tex = *current_screenshot.image;
uiTex.tex = current_screenshot.image;
set_shader_for_images(uiTex);
immediate_quad(.{r.x, r.y}, .{r.x + r.w, r.y}, .{r.x + r.w, r.y + r.h}, .{r.x, r.y + r.h});
set_shader_for_color();
@ -239,61 +254,58 @@ draw_tools_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
handle_tool_click :: (x: int, y: int, z: int, delete: bool = false) {
curworld := get_current_world();
if delete {
remove_trile(cast(float)x, cast(float)y, cast(float)z);
remove_trile(cast(s32)x, cast(s32)y, cast(s32)z);
} else {
if editor_current_trile != null then add_trile(editor_current_trile.name, cast(float)x, cast(float)y, cast(float)z);
if editor_current_trile != null then add_trile(editor_current_trile.name, cast(s32)x, cast(s32)y, cast(s32)z);
}
}
}
add_trile :: (name: string, x: float, y: float, z: float) {
add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
curworld := get_current_world();
loose_float_comp :: (a: float, b: float) -> bool {
return abs(a-b) < 0.001;
// Remove any existing trile at this position first.
remove_trile(x, y, z);
// Find or create the chunk.
key := world_to_chunk_coord(x, y, z);
chunk := table_find_pointer(*curworld.world.chunks, key);
if !chunk {
new_chunk: Chunk;
new_chunk.coord = key;
table_set(*curworld.world.chunks, key, new_chunk);
chunk = table_find_pointer(*curworld.world.chunks, key);
}
// Check if the position is already occupied. @ToDo: we would probably like to
// have some acceleration structure like a hashmap to speed up this check when
// we are checking for collisions.
for curworld.world.positions {
for v, idx: it.positions {
if loose_float_comp(v.x, x)
&& loose_float_comp(v.y, y)
&& loose_float_comp(v.z, z) {
array_unordered_remove_by_index(*it.positions, idx);
break;
}
}
}
for curworld.world.positions {
if it.trileName == name {
array_add(*it.positions, Vector4.{x,y,z,1});
lx, ly, lz := world_to_local(x, y, z);
inst := Trile_Instance.{x = lx, y = ly, z = lz, orientation = orientation};
// Find existing group for this trile type, or create one.
for *group: chunk.groups {
if group.trile_name == name {
array_add(*group.instances, inst);
return;
}
}
poses := TrilePositions.{
trileName = sprint("%", name),
};
array_add(*poses.positions, Vector4.{x,y,z,1});
array_add(*curworld.world.positions, poses);
group: Chunk_Trile_Group;
group.trile_name = sprint("%", name);
array_add(*group.instances, inst);
array_add(*chunk.groups, group);
} @Command
remove_trile :: (x: float, y: float, z: float) {
remove_trile :: (x: s32, y: s32, z: s32) {
curworld := get_current_world();
loose_float_comp :: (a: float, b: float) -> bool {
return abs(a-b) < 0.001;
}
key := world_to_chunk_coord(x, y, z);
chunk := table_find_pointer(*curworld.world.chunks, key);
if !chunk then return;
for curworld.world.positions {
for v, idx: it.positions {
if loose_float_comp(v.x, x)
&& loose_float_comp(v.y, y)
&& loose_float_comp(v.z, z) {
array_unordered_remove_by_index(*it.positions, idx);
break;
lx, ly, lz := world_to_local(x, y, z);
for *group: chunk.groups {
for inst, idx: group.instances {
if inst.x == lx && inst.y == ly && inst.z == lz {
array_unordered_remove_by_index(*group.instances, idx);
return;
}
}
}
@ -302,6 +314,7 @@ remove_trile :: (x: float, y: float, z: float) {
tick_level_editor :: () {
#if HAS_TACOMA { rdm_bake_tick(); }
tick_level_editor_camera();
ray := get_mouse_ray(*get_level_editor_camera());
hit, point := ray_plane_collision_point(ray, xx editY, 20);
@ -326,7 +339,7 @@ draw_level_editor :: () {
curworld := get_current_world();
if !curworld.valid then return;
create_set_cam_rendering_task(get_level_editor_camera(), curworld.world.conf.planeHeight);
create_world_rendering_tasks(curworld.world);
create_world_rendering_tasks(*curworld.world);
}
draw_level_editor_ui :: (theme: *GR.Overall_Theme) {

View File

@ -14,7 +14,399 @@ Tacoma_Screenshot :: struct {
current_screenshot : Tacoma_Screenshot;
gen_reference :: (w: s32, h: s32, conf: Tacoma.Gen_Config, world: World) {
RDM_Atlas_Entry :: struct {
world_pos: Vector3;
roughness: s32;
x, y: s32; // position in atlas (pixels)
w, h: s32; // size of this RDM
}
// Per-chunk atlas bake state (CPU-side, used during baking only).
RDM_Chunk_Bake :: struct {
data: *float; // CPU atlas buffer (RGBA32F)
width: s32;
height: s32;
cursor_x: s32;
cursor_y: s32;
row_height: s32;
entries: [..]RDM_Atlas_Entry;
}
RDM_ATLAS_SIZE :: 4096;
RDM_LOOKUP_SIZE :: 512; // 512x512 = 32*32*32*8 = 262144 texels
rdm_chunk_bakes : Table(Chunk_Key, RDM_Chunk_Bake, chunk_key_hash, chunk_key_compare);
ctx : *Tacoma.Tacoma_Context;
// --- Chunk RDM bake queue ---
// A single RDM render job: one world_trile at one roughness level.
RDM_Bake_Job :: struct {
world_trile_index: s32;
roughness: s32;
world_pos: Vector3;
}
RDM_Bake_State :: struct {
active : bool = false;
quality : s32 = 100;
jobs : [..]RDM_Bake_Job;
current_job : s32 = 0;
}
rdm_bake : RDM_Bake_State;
// Get the set of roughness values present in a trile's trixels.
// Always includes 7 (used for diffuse light). Returns a bitmask.
get_trile_roughness_set :: (trile_name: string) -> u8 {
trile := get_trile(trile_name);
mask : u8 = 1 << 7; // Always include roughness 7.
for x: 0..15 {
for y: 0..15 {
for z: 0..15 {
if !trile.trixels[x][y][z].empty {
mask |= cast(u8)(1 << trile.trixels[x][y][z].material.roughness);
}
}
}
}
return mask;
}
// Build the Tacoma scene from the world, and emit bake jobs for selected chunks.
// If chunk_keys is null, all chunks are queued.
rdm_bake_start :: (world: World, quality: s32, include_water: bool, chunk_keys: []Chunk_Key = .[]) {
if rdm_bake.active then return;
trile_list : [..]Tacoma.Trile_Data;
trile_list.allocator = temp;
world_triles : [..]Tacoma.World_Trile;
world_triles.allocator = temp;
trile_name_to_index: Table(string, s32);
trile_name_to_index.allocator = temp;
// Per world_trile: which roughnesses to bake.
world_trile_roughnesses : [..]u8;
world_trile_roughnesses.allocator = temp;
// Cache roughness sets per trile type.
roughness_cache: Table(string, u8);
roughness_cache.allocator = temp;
bake_all := chunk_keys.count == 0;
// Build a set of chunk keys to bake if specific ones were requested.
chunk_key_set: Table(Chunk_Key, bool, chunk_key_hash, chunk_key_compare);
chunk_key_set.allocator = temp;
if !bake_all {
for key: chunk_keys {
table_set(*chunk_key_set, key, true);
}
}
for chunk: world.chunks {
should_bake := bake_all || table_contains(*chunk_key_set, chunk.coord);
for group: chunk.groups {
success, idx := table_find(*trile_name_to_index, group.trile_name);
if !success {
trile := get_trile(group.trile_name);
ttrile : Tacoma.Trile_Data;
for x: 0..15 {
for y: 0..15 {
for z: 0..15 {
ttrile.trixels[x][y][z] = .{
trile.trixels[x][y][z].empty,
trile.trixels[x][y][z].material.color,
material_encode_to_float(trile.trixels[x][y][z].material)
};
}
}
}
gfx := get_trile_gfx(group.trile_name);
ttrile.vertices = gfx.vertices.data;
ttrile.vertexCount = cast(s32) (gfx.vertices.count / 3);
idx = cast(s32) trile_list.count;
array_add(*trile_list, ttrile);
table_set(*trile_name_to_index, group.trile_name, idx);
}
// Get roughness set for this trile type (cached).
roughness_mask : u8;
found_r, cached_mask := table_find(*roughness_cache, group.trile_name);
if found_r {
roughness_mask = cached_mask;
} else {
roughness_mask = get_trile_roughness_set(group.trile_name);
table_set(*roughness_cache, group.trile_name, roughness_mask);
}
for inst: group.instances {
world_trile_idx := cast(s32) world_triles.count;
wx, wy, wz := chunk_local_to_world(chunk.coord, inst.x, inst.y, inst.z);
wpos := Vector3.{cast(float) wx, cast(float) wy, cast(float) wz};
array_add(*world_triles, Tacoma.World_Trile.{idx, wpos});
array_add(*world_trile_roughnesses, roughness_mask);
if should_bake {
// Emit one job per roughness level present.
for r: 0..7 {
if roughness_mask & cast(u8)(1 << r) {
array_add(*rdm_bake.jobs, .{world_trile_index = world_trile_idx, roughness = cast(s32) r, world_pos = wpos});
}
}
}
}
}
}
sky : Tacoma.Sky_Config;
sky.skyBase = world.conf.skyBase;
sky.skyTop = world.conf.skyTop;
sky.sunDisk = world.conf.sunDisk;
sky.horizonHalo = world.conf.horizonHalo;
sky.sunHalo = world.conf.sunHalo;
sky.sunLightColor = world.conf.sunLightColor;
sky.sunPosition = world.conf.sunPosition;
sky.sunIntensity = world.conf.sunIntensity;
sky.skyIntensity = world.conf.skyIntensity;
blases : Tacoma.Trile_Set = .{trile_list.data, cast(s32)trile_list.count};
tlas : Tacoma.World = .{world_triles.data, cast(s32)world_triles.count};
ctx = Tacoma.tacoma_init("./modules/Tacoma/");
Tacoma.tacoma_load_scene(ctx, sky, blases, tlas, cast(s32) include_water);
// Sort jobs by roughness ascending (lowest roughness = biggest images first).
// Simple insertion sort, N is small.
if rdm_bake.jobs.count > 1 {
for i: 1..cast(s32)(rdm_bake.jobs.count - 1) {
key := rdm_bake.jobs[i];
j := i - 1;
while j >= 0 && rdm_bake.jobs[j].roughness > key.roughness {
rdm_bake.jobs[j + 1] = rdm_bake.jobs[j];
j -= 1;
}
rdm_bake.jobs[j + 1] = key;
}
}
// Clean up any previous per-chunk bake data.
rdm_cleanup_chunk_bakes();
// Clean up any previous RDM results stored in chunks.
curworld := get_current_world();
for *chunk: curworld.world.chunks {
if chunk.rdm_valid {
sg_destroy_image(chunk.rdm_atlas);
sg_destroy_image(chunk.rdm_lookup);
chunk.rdm_valid = false;
}
}
// Pre-allocate per-chunk atlas CPU buffers.
atlas_bytes := cast(s64) RDM_ATLAS_SIZE * cast(s64) RDM_ATLAS_SIZE * 4 * size_of(float);
for job: rdm_bake.jobs {
chunk_key := world_to_chunk_coord(cast(s32) job.world_pos.x, cast(s32) job.world_pos.y, cast(s32) job.world_pos.z);
if !table_contains(*rdm_chunk_bakes, chunk_key) {
bake : RDM_Chunk_Bake;
bake.width = RDM_ATLAS_SIZE;
bake.height = RDM_ATLAS_SIZE;
bake.data = cast(*float) alloc(atlas_bytes);
memset(bake.data, 0, atlas_bytes);
table_set(*rdm_chunk_bakes, chunk_key, bake);
}
}
rdm_bake.active = true;
rdm_bake.quality = quality;
if rdm_bake.jobs.count == 0 {
rdm_bake_finish();
}
}
// Queue all chunks for RDM baking.
rdm_bake_all_chunks :: (world: World, quality: s32, include_water: bool) {
rdm_bake_start(world, quality, include_water);
}
// Queue specific chunks for RDM baking.
rdm_bake_chunks :: (chunk_keys: []Chunk_Key, world: World, quality: s32, include_water: bool) {
rdm_bake_start(world, quality, include_water, chunk_keys);
}
// Called once per frame to process at most one RDM.
rdm_bake_tick :: () {
if !rdm_bake.active then return;
if rdm_bake.current_job >= cast(s32) rdm_bake.jobs.count {
rdm_bake_finish();
return;
}
job := rdm_bake.jobs[rdm_bake.current_job];
w, h : s32;
ptr := Tacoma.tacoma_render_rdm(ctx, job.world_trile_index, job.roughness, rdm_bake.quality, *w, *h);
// Find this job's per-chunk bake state.
chunk_key := world_to_chunk_coord(cast(s32) job.world_pos.x, cast(s32) job.world_pos.y, cast(s32) job.world_pos.z);
bake := table_find_pointer(*rdm_chunk_bakes, chunk_key);
if bake != null {
// Shelf-pack this RDM into the chunk's atlas.
if bake.cursor_x + w > bake.width {
bake.cursor_y += bake.row_height;
bake.cursor_x = 0;
bake.row_height = 0;
}
ax := bake.cursor_x;
ay := bake.cursor_y;
if ay + h <= bake.height {
// Copy pixels row-by-row into the chunk's atlas CPU buffer.
src := cast(*u8) ptr;
row_bytes := cast(s64) w * 4 * size_of(float);
for row: 0..h-1 {
dst_offset := (cast(s64)(ay + row) * cast(s64) bake.width + cast(s64) ax) * 4 * size_of(float);
src_offset := cast(s64) row * row_bytes;
memcpy(cast(*u8) bake.data + dst_offset, src + src_offset, row_bytes);
}
entry : RDM_Atlas_Entry;
entry.world_pos = job.world_pos;
entry.roughness = job.roughness;
entry.x = ax;
entry.y = ay;
entry.w = w;
entry.h = h;
array_add(*bake.entries, entry);
} else {
print("Warning: RDM atlas overflow for chunk %, skipping (pos=%, roughness=%)\n", chunk_key, job.world_pos, job.roughness);
}
bake.cursor_x += w;
if h > bake.row_height then bake.row_height = h;
}
// Still update the preview screenshot.
tacoma_handle_result(ptr, w, h);
rdm_bake.current_job += 1;
}
rdm_bake_finish :: () {
if ctx != null then tacoma_stop();
curworld := get_current_world();
total_entries : s64 = 0;
chunk_count : s64 = 0;
// Collect unique chunk keys from jobs.
bake_chunk_keys : [..]Chunk_Key;
bake_chunk_keys.allocator = temp;
for job: rdm_bake.jobs {
ck := world_to_chunk_coord(cast(s32) job.world_pos.x, cast(s32) job.world_pos.y, cast(s32) job.world_pos.z);
already := false;
for bake_chunk_keys { if it == ck { already = true; break; } }
if !already then array_add(*bake_chunk_keys, ck);
}
lookup_texels :: RDM_LOOKUP_SIZE * RDM_LOOKUP_SIZE;
lookup_bytes :: lookup_texels * 4 * size_of(float);
for chunk_key: bake_chunk_keys {
bake := table_find_pointer(*rdm_chunk_bakes, chunk_key);
if bake == null || bake.entries.count == 0 then continue;
// a) Upload per-chunk atlas to GPU.
atlas_imgdata : sg_image_data;
atlas_byte_size := cast(u64) bake.width * cast(u64) bake.height * 4 * size_of(float);
atlas_imgdata.subimage[0][0] = .{bake.data, atlas_byte_size};
atlas_desc : sg_image_desc = .{
render_target = false,
width = bake.width,
height = bake.height,
pixel_format = sg_pixel_format.RGBA32F,
sample_count = 1,
data = atlas_imgdata
};
atlas_image := sg_make_image(*atlas_desc);
// b) Generate lookup texture (512x512 RGBA32F).
lookup_data := cast(*float) alloc(lookup_bytes);
memset(lookup_data, 0, lookup_bytes);
atlas_w := cast(float) bake.width;
atlas_h := cast(float) bake.height;
for entry: bake.entries {
lx, ly, lz := world_to_local(cast(s32) entry.world_pos.x, cast(s32) entry.world_pos.y, cast(s32) entry.world_pos.z);
index := cast(s32) lx + cast(s32) ly * 32 + cast(s32) lz * 32 * 32 + entry.roughness * 32 * 32 * 32;
tx := index % RDM_LOOKUP_SIZE;
ty := index / RDM_LOOKUP_SIZE;
pixel_offset := (ty * RDM_LOOKUP_SIZE + tx) * 4;
lookup_data[pixel_offset + 0] = cast(float) entry.x / atlas_w;
lookup_data[pixel_offset + 1] = cast(float) entry.y / atlas_h;
lookup_data[pixel_offset + 2] = cast(float) entry.w / atlas_w;
lookup_data[pixel_offset + 3] = cast(float) entry.h / atlas_h;
}
lookup_imgdata : sg_image_data;
lookup_imgdata.subimage[0][0] = .{lookup_data, lookup_bytes};
lookup_desc : sg_image_desc = .{
render_target = false,
width = RDM_LOOKUP_SIZE,
height = RDM_LOOKUP_SIZE,
pixel_format = sg_pixel_format.RGBA32F,
sample_count = 1,
data = lookup_imgdata
};
lookup_image := sg_make_image(*lookup_desc);
free(lookup_data);
// c) Store in Chunk.
chunk := table_find_pointer(*curworld.world.chunks, chunk_key);
if chunk != null {
if chunk.rdm_valid {
sg_destroy_image(chunk.rdm_atlas);
sg_destroy_image(chunk.rdm_lookup);
}
chunk.rdm_atlas = atlas_image;
chunk.rdm_lookup = lookup_image;
chunk.rdm_valid = true;
}
total_entries += cast(s64) bake.entries.count;
chunk_count += 1;
}
print("RDM bake complete: % chunks, % total entries\n", chunk_count, total_entries);
// Save baked RDM data to disk.
rdm_save_all_chunks_to_disk();
// Clean up CPU bake data.
rdm_cleanup_chunk_bakes();
array_free(rdm_bake.jobs);
rdm_bake = .{};
}
rdm_cleanup_chunk_bakes :: () {
for *bake: rdm_chunk_bakes {
if bake.data != null then free(bake.data);
array_free(bake.entries);
}
deinit(*rdm_chunk_bakes);
rdm_chunk_bakes = .{};
}
tacoma_start :: (world: World, include_water: bool) {
// Trile BLASes.
trile_list : [..]Tacoma.Trile_Data;
trile_list.allocator = temp;
@ -22,32 +414,43 @@ gen_reference :: (w: s32, h: s32, conf: Tacoma.Gen_Config, world: World) {
world_triles : [..]Tacoma.World_Trile;
world_triles.allocator = temp;
for world.positions {
print("World positions for: %\n", it.trileName);
trile := get_trile(it.trileName);
ttrile : Tacoma.Trile_Data;
for x: 0..15 {
for y: 0..15 {
for z: 0..15 {
ttrile.trixels[x][y][z] = .{
trile.trixels[x][y][z].empty,
trile.trixels[x][y][z].material.color,
material_encode_to_float(trile.trixels[x][y][z].material)
};
// Build trile type list and gather world positions from chunks.
trile_name_to_index: Table(string, s32);
trile_name_to_index.allocator = temp;
for chunk: world.chunks {
for group: chunk.groups {
// Ensure this trile type is in the list.
success, idx := table_find(*trile_name_to_index, group.trile_name);
if !success {
trile := get_trile(group.trile_name);
ttrile : Tacoma.Trile_Data;
for x: 0..15 {
for y: 0..15 {
for z: 0..15 {
ttrile.trixels[x][y][z] = .{
trile.trixels[x][y][z].empty,
trile.trixels[x][y][z].material.color,
material_encode_to_float(trile.trixels[x][y][z].material)
};
}
}
}
gfx := get_trile_gfx(group.trile_name);
ttrile.vertices = gfx.vertices.data;
ttrile.vertexCount = cast(s32) (gfx.vertices.count / 3);
idx = cast(s32) trile_list.count;
array_add(*trile_list, ttrile);
table_set(*trile_name_to_index, group.trile_name, idx);
}
for inst: group.instances {
wx, wy, wz := chunk_local_to_world(chunk.coord, inst.x, inst.y, inst.z);
array_add(*world_triles, Tacoma.World_Trile.{idx, Vector3.{cast(float) wx, cast(float) wy, cast(float) wz}});
}
}
gfx := get_trile_gfx(it.trileName);
ttrile.vertices = gfx.vertices.data;
ttrile.vertexCount = cast(s32) (gfx.vertices.count / 3);
array_add(*trile_list, ttrile);
for pos, posi: it.positions {
array_add(*world_triles, Tacoma.World_Trile.{cast(s32)it_index, pos.xyz});
}
}
sky : Tacoma.Sky_Config;
sky.skyBase = world.conf.skyBase;
@ -66,37 +469,202 @@ gen_reference :: (w: s32, h: s32, conf: Tacoma.Gen_Config, world: World) {
}
tlas : Tacoma.World = .{world_triles.data, cast(s32)world_triles.count};
ptr := Tacoma.do_gen("./modules/Tacoma/", w, h, sky, blases, tlas, conf);
ctx = Tacoma.tacoma_init("./modules/Tacoma/");
print("CTX: %\n\n", ctx);
Tacoma.tacoma_load_scene(ctx, sky, blases, tlas, cast(s32) include_water);
}
tacoma_stop :: () {
Tacoma.tacoma_destroy(ctx);
}
tacoma_handle_result :: (ptr: *float, w: s32, h: s32) {
data := cast(*float) talloc(w*h*4*size_of(float));
memcpy(data, ptr, w*h*4*4);
for 0..(w*h) {
color : Vector3;
color.x = data[it * 4 + 0];
color.y = data[it * 4 + 1];
color.z = data[it * 4 + 2];
color.x = data[it * 4 + 0];
color.y = data[it * 4 + 1];
color.z = data[it * 4 + 2];
data[it * 4 + 0] = color.x;
data[it * 4 + 1] = color.y;
data[it * 4 + 2] = color.z;
}
imgdata : sg_image_data;
imgdata.subimage[0][0] = .{data, cast(u64) (w*h*4*4)};
texdesc : sg_image_desc = .{
render_target = false,
width = w,
height = h,
height = h,
pixel_format = sg_pixel_format.RGBA32F,
sample_count = 1,
data = imgdata
};
if current_screenshot.valid {
sg_destroy_image(current_screenshot.image);
}
current_screenshot = .{
sg_make_image(*texdesc),
w,
h,
true
};
Tacoma.tacoma_free_result(ptr);
}
gen_reference :: (w: s32, h: s32, eye: Vector3, target: Vector3, quality: s32, include_water: bool, world: World) {
tacoma_start(world, include_water);
ptr := Tacoma.tacoma_render_reference(ctx, w, h, eye, target, 0.01, quality);
tacoma_handle_result(ptr, w, h);
tacoma_stop();
}
gen_rdm :: (quality: s32, include_water: bool, world: World) {
tacoma_start(world, include_water);
w, h : s32;
ptr := Tacoma.tacoma_render_rdm(ctx, 0, 0, quality, *w, *h);
tacoma_handle_result(ptr, w, h);
tacoma_stop();
}
// --- RDM disk persistence ---
#if OS != .WASM {
rdm_file :: #import "File";
}
RDM_File_Header :: struct {
magic: u32;
width: s32;
height: s32;
}
RDM_FILE_MAGIC :: u32.[0x4D445254][0]; // "TRDM" as little-endian u32
rdm_chunk_filename :: (world_name: string, chunk_key: Chunk_Key, suffix: string) -> string {
return tprint("./game/resources/worlds/%/%_%_%.%", world_name, chunk_key.x, chunk_key.y, chunk_key.z, suffix);
}
rdm_save_image_to_file :: (path: string, data: *float, width: s32, height: s32) {
#if OS != .WASM {
builder: String_Builder;
header := RDM_File_Header.{
magic = RDM_FILE_MAGIC,
width = width,
height = height,
};
write_bytes(*builder, *header, size_of(RDM_File_Header));
pixel_bytes := cast(s64) width * cast(s64) height * 4 * size_of(float);
write_bytes(*builder, data, pixel_bytes);
rdm_file.write_entire_file(path, builder_to_string(*builder));
}
}
rdm_save_all_chunks_to_disk :: () {
#if OS != .WASM {
curworld := get_current_world();
if !curworld.valid then return;
world_name := curworld.world.name;
for *bake, chunk_key: rdm_chunk_bakes {
if bake.entries.count == 0 then continue;
// Save atlas.
atlas_path := rdm_chunk_filename(world_name, chunk_key, "rdm_atlas");
rdm_save_image_to_file(atlas_path, bake.data, bake.width, bake.height);
// Regenerate and save lookup.
lookup_texels :: RDM_LOOKUP_SIZE * RDM_LOOKUP_SIZE;
lookup_floats :: lookup_texels * 4;
lookup_data : [lookup_floats]float;
memset(lookup_data.data, 0, size_of(type_of(lookup_data)));
atlas_w := cast(float) bake.width;
atlas_h := cast(float) bake.height;
for entry: bake.entries {
lx, ly, lz := world_to_local(cast(s32) entry.world_pos.x, cast(s32) entry.world_pos.y, cast(s32) entry.world_pos.z);
index := cast(s32) lx + cast(s32) ly * 32 + cast(s32) lz * 32 * 32 + entry.roughness * 32 * 32 * 32;
tx := index % RDM_LOOKUP_SIZE;
ty := index / RDM_LOOKUP_SIZE;
pixel_offset := (ty * RDM_LOOKUP_SIZE + tx) * 4;
lookup_data[pixel_offset + 0] = cast(float) entry.x / atlas_w;
lookup_data[pixel_offset + 1] = cast(float) entry.y / atlas_h;
lookup_data[pixel_offset + 2] = cast(float) entry.w / atlas_w;
lookup_data[pixel_offset + 3] = cast(float) entry.h / atlas_h;
}
lookup_path := rdm_chunk_filename(world_name, chunk_key, "rdm_lookup");
rdm_save_image_to_file(lookup_path, lookup_data.data, RDM_LOOKUP_SIZE, RDM_LOOKUP_SIZE);
print("Saved RDM data for chunk % to disk\n", chunk_key);
}
}
}
rdm_load_from_disk :: () {
#if OS != .WASM {
curworld := get_current_world();
if !curworld.valid then return;
world_name := curworld.world.name;
for *chunk: curworld.world.chunks {
if chunk.rdm_valid then continue;
atlas_path := rdm_chunk_filename(world_name, chunk.coord, "rdm_atlas");
lookup_path := rdm_chunk_filename(world_name, chunk.coord, "rdm_lookup");
atlas_data, atlas_ok := rdm_file.read_entire_file(atlas_path);
if !atlas_ok then continue;
lookup_data, lookup_ok := rdm_file.read_entire_file(lookup_path);
if !lookup_ok then continue;
header_size := cast(s64) size_of(RDM_File_Header);
if atlas_data.count < header_size || lookup_data.count < header_size then continue;
atlas_header := cast(*RDM_File_Header) atlas_data.data;
lookup_header := cast(*RDM_File_Header) lookup_data.data;
if atlas_header.magic != RDM_FILE_MAGIC || lookup_header.magic != RDM_FILE_MAGIC then continue;
// Create atlas GPU image.
atlas_imgdata : sg_image_data;
atlas_pixel_bytes := cast(u64) atlas_header.width * cast(u64) atlas_header.height * 4 * size_of(float);
atlas_imgdata.subimage[0][0] = .{atlas_data.data + header_size, atlas_pixel_bytes};
atlas_desc : sg_image_desc = .{
render_target = false,
width = atlas_header.width,
height = atlas_header.height,
pixel_format = sg_pixel_format.RGBA32F,
sample_count = 1,
data = atlas_imgdata,
};
chunk.rdm_atlas = sg_make_image(*atlas_desc);
// Create lookup GPU image.
lookup_imgdata : sg_image_data;
lookup_pixel_bytes := cast(u64) lookup_header.width * cast(u64) lookup_header.height * 4 * size_of(float);
lookup_imgdata.subimage[0][0] = .{lookup_data.data + header_size, lookup_pixel_bytes};
lookup_desc : sg_image_desc = .{
render_target = false,
width = lookup_header.width,
height = lookup_header.height,
pixel_format = sg_pixel_format.RGBA32F,
sample_count = 1,
data = lookup_imgdata,
};
chunk.rdm_lookup = sg_make_image(*lookup_desc);
chunk.rdm_valid = true;
print("Loaded RDM data for chunk % from disk\n", chunk.coord);
}
}
}

View File

@ -10,7 +10,7 @@ theme_ptr : GR.Overall_Theme;
current_pipeline : s32 = 0;
current_slot : s32 = 0;
pipeline_names : []string = .["shadowmap", "reflection", "main", "position", "normal", "ssao"];
pipeline_names : []string = .["shadowmap", "reflection", "main", "position", "normal", "ssao", "rdm_atlas (chunk)", "rdm_lookup (chunk)"];
draw_subwindow_texture_debug :: (state: *GR.Subwindow_State, r: GR.Rect, data: *void) {
r2 := r;
@ -33,6 +33,16 @@ draw_subwindow_texture_debug :: (state: *GR.Subwindow_State, r: GR.Rect, data: *
case 3; image = g_gbuf_position;
case 4; image = g_gbuf_normal;
case 5; image = g_ssaobuf;
case 6; #through;
case 7;
cw := get_current_world();
for chunk: cw.world.chunks {
if chunk.rdm_valid {
if current_pipeline == 6 then image = chunk.rdm_atlas;
else image = chunk.rdm_lookup;
break;
}
}
}
uiTex.tex = image;
@ -55,8 +65,7 @@ draw_subwindow_post_process :: (state: *GR.Subwindow_State, r: GR.Rect, data: *v
if GR.button(r3, "Save postprocessing", *theme_ptr.button_theme) {
#if OS != .WASM {
file :: #import "File";
json := Jaison.json_write_string(current_post_process, " ");
file.write_entire_file("./game/resources/postprocess.json", json);
save_post_process();
}
}
r3.y += r3.h;

View File

@ -123,6 +123,7 @@ init_after_mandatory :: () {
init_after_core :: () {
init_plane_textures();
init_brdf_lut();
add_font_from_pack("boot", "DroidSerif-Regular.ttf");
ui_init_font_fields(*state.font_default);
@ -139,7 +140,6 @@ init_after_core :: () {
}
}
init_editor();
lworlds();
init_rendering();
load_post_process_from_pack();
@ -192,8 +192,8 @@ frame :: () {
#if OS != .WASM { tick_profiler(); }
delta_time_accumulator += delta_time;
if !in_editor_view then delta_time_accumulator += delta_time;
if !in_editor_view {
while delta_time_accumulator > (1.0/60.0) {
game_tick(1.0/60.0);

View File

@ -1,13 +1,18 @@
#import "String";
should_ignore_file :: (name: string) -> bool {
ok, left, right := split_from_right(name, #char ".");
if right == "aseprite" {
print("Ignoring % as aseprite file...\n", name);
return true;
}
return false;
}
should_ignore_path :: (full_name: string) -> bool {
if contains(full_name, "/worlds/") return true;
return false;
}
@ -19,6 +24,7 @@ packs : Table(string, Create_Package);
file_visit_handler :: (info: *util.File_Visit_Info, user_data: bool) {
if should_ignore_file(info.short_name) then return;
if should_ignore_path(info.full_name) then return;
_, _, packPath := split_from_left(info.full_name, "/resources/");
_, packName, fileName := split_from_left(packPath, "/");

View File

@ -57,7 +57,7 @@ animation_set_if_not :: (player: *Animation_Player, animation: string) {
}
animation_is :: (player: *Animation_Player, animation: string) -> bool {
pack, anim := split_from_left(animation, ".");
_, pack, anim := split_from_left(animation, ".");
return player.current_animation.name == anim;
}

View File

@ -50,6 +50,7 @@ Render_Command_Draw_Trile_Positions :: struct {
#as using c : Render_Command;
c.type = .DRAW_TRILE_POSITIONS;
trile : string;
chunk_key : Chunk_Key;
amount : s32;
conf : *World_Config;
}

View File

@ -18,7 +18,7 @@ backend_handle_command :: (cmd: *Render_Command) {
backend_add_trile_positions(add_command.positions);
case .DRAW_TRILE_POSITIONS;
draw_command := cast(*Render_Command_Draw_Trile_Positions)cmd;
backend_draw_trile_positions(draw_command.trile, draw_command.amount, draw_command.conf);
backend_draw_trile_positions(draw_command.trile, draw_command.amount, draw_command.conf, draw_command.chunk_key);
case .DRAW_SKY;
sky_command := cast(*Render_Command_Sky)cmd;
backend_draw_sky(sky_command.worldConfig);
@ -106,11 +106,11 @@ backend_add_trile_positions :: (positions : []Vector4) {
array_add(*trile_offsets, offset);
}
backend_draw_trile_positions :: (trile : string, amount : s32, worldConf: *World_Config) {
backend_draw_trile_positions :: (trile : string, amount : s32, worldConf: *World_Config, chunk_key: Chunk_Key) {
if in_gbuffer_pass {
backend_draw_trile_positions_gbuffer(trile, amount, worldConf);
} else {
backend_draw_trile_positions_main(trile, amount, worldConf);
backend_draw_trile_positions_main(trile, amount, worldConf, chunk_key);
}
}
@ -142,7 +142,7 @@ backend_draw_trile_positions_gbuffer :: (trile : string, amount : s32, worldConf
sg_draw(0, cast(s32) trilegfx.vertex_count, amount);
}
backend_draw_trile_positions_main :: (trile : string, amount : s32, worldConf: *World_Config) {
backend_draw_trile_positions_main :: (trile : string, amount : s32, worldConf: *World_Config, chunk_key: Chunk_Key) {
start_frame_profiling_group("Draw trile positions");
mvp : Matrix4;
if !in_shadowmap_pass {
@ -181,6 +181,16 @@ backend_draw_trile_positions_main :: (trile : string, amount : s32, worldConf: *
bindings.images[2] = g_rendertex_depth;
}
// Bind RDM textures for this chunk
curworld := get_current_world();
rdm_chunk := table_find_pointer(*curworld.world.chunks, chunk_key);
if rdm_chunk != null && rdm_chunk.rdm_valid {
bindings.images[3] = rdm_chunk.rdm_lookup;
bindings.images[4] = rdm_chunk.rdm_atlas;
}
bindings.images[5] = g_brdf_lut;
bindings.samplers[3] = gPipelines.trile.bind.samplers[3];
fs_params : Trile_Fs_Params;
fs_params.mvp_shadow = shadow_mvp.floats;
fs_params.is_reflection = ifx in_reflection_pass then cast(s32)1 else cast(s32)0;

View File

@ -12,17 +12,52 @@ fill_uniform_with_engine_data :: (uniform: *$A, enginedata: *$B) {
#insert #run,stallable generate_copy_code();
}
Gathered_Positions :: struct {
name: string;
chunk_key: Chunk_Key;
positions: [..]Vector4;
}
create_world_rendering_tasks :: (world: *World) {
create_sky_rendering_task(*world.conf);
create_set_light_rendering_task(*world.conf);
for world.positions {
if it.positions.count < 1 then continue;
triletask := Rendering_Task_Trile.{};
triletask.trile = it.trileName;
triletask.positions = it.positions;
triletask.worldConf = *world.conf;
add_rendering_task(triletask);
}
// Gather all trile positions from chunks, grouped by trile type.
gathered: [..]Gathered_Positions;
gathered.allocator = temp;
for chunk: world.chunks {
for group: chunk.groups {
// Find or create the gathered entry for this (chunk, trile_type) pair.
target: *Gathered_Positions = null;
for *g: gathered {
if g.name == group.trile_name && g.chunk_key == chunk.coord {
target = g;
break;
}
}
if !target {
array_add(*gathered, .{name = group.trile_name, chunk_key = chunk.coord});
target = *gathered[gathered.count - 1];
target.positions.allocator = temp;
}
for inst: group.instances {
wx, wy, wz := chunk_local_to_world(chunk.coord, inst.x, inst.y, inst.z);
array_add(*target.positions, Vector4.{cast(float) wx, cast(float) wy, cast(float) wz, cast(float) inst.orientation});
}
}
}
for g: gathered {
if g.positions.count < 1 then continue;
triletask := Rendering_Task_Trile.{};
triletask.trile = g.name;
triletask.chunk_key = g.chunk_key;
triletask.positions = g.positions;
triletask.worldConf = *world.conf;
add_rendering_task(triletask);
}
create_ground_rendering_task(world);
}
@ -77,8 +112,8 @@ get_low_res :: (width: s32, height: s32, max_dimension: s32 = 720) -> (s32, s32)
get_render_size :: () -> (s32, s32) {
w,h := get_window_size();
wl, hl := get_low_res(w,h, 800);
return wl, hl;
// w, h = get_low_res(w,h, 480);
return w, h;
}
flip_y_if_plat :: inline (v: Vector2) -> Vector2 {

View File

@ -8,6 +8,7 @@ Pipeline_Binding :: struct {
}
g_specular_lut : sg_image;
g_brdf_lut : sg_image;
g_shadowmap : sg_image;
g_shadowmap_img : sg_image;
@ -398,6 +399,12 @@ create_trile_pipeline :: () {
mag_filter = .NEAREST,
}));
gPipelines.trile.bind.vertex_buffers[3] = sg_make_buffer(*instance_buffer);
gPipelines.trile.bind.samplers[3] = sg_make_sampler(*(sg_sampler_desc.{
wrap_u = .CLAMP_TO_EDGE,
wrap_v = .CLAMP_TO_EDGE,
min_filter = .LINEAR,
mag_filter = .LINEAR,
}));
}
create_sky_pipeline :: () {
@ -579,8 +586,8 @@ create_plane_pipeline :: () {
g_shadowmap_sampler = sg_make_sampler(*(sg_sampler_desc.{
wrap_u = .CLAMP_TO_EDGE,
wrap_v = .CLAMP_TO_EDGE,
min_filter = .LINEAR,
mag_filter = .LINEAR,
min_filter = .NEAREST,
mag_filter = .NEAREST,
compare = .LESS,
}));
@ -1066,6 +1073,23 @@ init_plane_textures :: () {
gPipelines.plane.bind.images[2] = get_texture_from_pack("core", "utiltex/water_small.png");
}
init_brdf_lut :: () {
g_brdf_lut = get_texture_from_pack("core", "utiltex/lut.png");
if g_brdf_lut.id == INVALID_ID {
// Create a 1x1 fallback so sokol doesn't drop draw calls
pixels : [4]u8 = .[255, 255, 255, 255];
imgdata : sg_image_data;
imgdata.subimage[0][0] = .{ pixels.data, 4 };
desc := sg_image_desc.{
width = 1,
height = 1,
pixel_format = .RGBA8,
data = imgdata,
};
g_brdf_lut = sg_make_image(*desc);
}
}
g_plane_gbuffer_vertex_buffer : sg_buffer;
g_plane_gbuffer_normal_buffer : sg_buffer;
g_plane_gbuffer_center_buffer : sg_buffer;

View File

@ -27,16 +27,44 @@ Post_Process :: struct {
film_grain_intensity: float = 0.0; @Slider,0,0.5,0.001;
barrel_distortion_intensity: float = 0.0; @Slider,-2,2,0.1;
lut_mode: s32 = 0; @Slider,0,2,1; // 0 -> no LUT, 1 -> LUT with interpolation 2 -> LUT no iterpolate
dither_intensity: float = 0.0; @Slider,0,1,0.05;
}
current_post_process : Post_Process;
Post_Process_Save :: struct {
#as using pp: Post_Process;
lut_name: string;
}
load_post_process_from_pack :: () {
s := load_string_from_pack("game_core", "postprocess.json");
success, pp:= Jaison.json_parse_string(s, Post_Process,, temp);
success, save := Jaison.json_parse_string(s, Post_Process_Save,, temp);
if success {
current_post_process = pp;
current_post_process = save.pp;
// Restore LUT selection by name.
if save.lut_name.count > 0 {
for LUT_list {
if it.name == save.lut_name {
g_current_lut_texture_index = cast(s32) it_index;
break;
}
}
}
}
}
save_post_process :: () {
#if OS != .WASM {
file :: #import "File";
save: Post_Process_Save;
save.pp = current_post_process;
if g_current_lut_texture_index >= 0 && g_current_lut_texture_index < LUT_list.count {
save.lut_name = LUT_list[g_current_lut_texture_index].name;
}
json := Jaison.json_write_string(save, " ");
file.write_entire_file("./game/resources/game_core/postprocess.json", json);
}
}

View File

@ -50,7 +50,7 @@ create_shadow_viewproj :: (cam: *Camera, conf: *World_Config) -> Matrix4 {
avg += it;
}
avg /= 8.0;
sunCameraPosition := avg + 30*A;
sunCameraPosition := -targetToPos * 50.0;
view := Matrix4.{
B.x, C.x, A.x, 0,
@ -58,23 +58,7 @@ create_shadow_viewproj :: (cam: *Camera, conf: *World_Config) -> Matrix4 {
B.z, C.z, A.z, 0,
-dot(B, sunCameraPosition), -dot(C, sunCameraPosition), -dot(A, sunCameraPosition), 1
};
min_v := Vector3.{ 9999, 9999, 9999};
max_v := Vector3.{-9999, -9999, -9999};
for corner: frustum_corners {
transformed_corner := (view * Vector4.{corner.x, corner.y, corner.z, 1.0}).xyz;
min_v.x = min(min_v.x, transformed_corner.x);
min_v.y = min(min_v.y, transformed_corner.y);
min_v.z = min(min_v.z, transformed_corner.z);
max_v.x = max(max_v.x, transformed_corner.x);
max_v.y = max(max_v.y, transformed_corner.y);
max_v.z = max(max_v.z, transformed_corner.z);
}
max_v.xy = avg.xy + Vector2.{20, 20};
min_v.xy = avg.xy - Vector2.{20, 20};
proj := matrix_ortho(min_v.x, max_v.x, min_v.y, max_v.y, -max_v.z-100, -min_v.z);
proj := matrix_ortho(-15, 15, -15, 15, 0, 100);
return view*proj;
}

View File

@ -53,6 +53,7 @@ Rendering_Task_Trile :: struct {
#as using t : Rendering_Task;
t.type = .TRILE;
trile : string;
chunk_key : Chunk_Key;
positions : []Vector4;
worldConf : *World_Config;
}
@ -109,6 +110,7 @@ tasks_to_commands :: () {
array_add(*render_command_buckets.setup, addPositionsCmd);
drawPositionsCmd := New(Render_Command_Draw_Trile_Positions,, temp);
drawPositionsCmd.trile = trileTask.trile;
drawPositionsCmd.chunk_key = trileTask.chunk_key;
drawPositionsCmd.amount = cast(s32)trileTask.positions.count;
drawPositionsCmd.conf = trileTask.worldConf;
array_add(*render_command_buckets.reflection, drawPositionsCmd);

View File

@ -254,20 +254,22 @@ vs_plane_source_glsl430 := u8.[
vec3 _274 = normalize(((((texture(normal_map_normalsmp, (pos.xz * 0.4000000059604644775390625) + (_185 * 1.5)).xzy * 2.0) - vec3(1.0)) + ((texture(normal_map_normalsmp, (pos.xz * 0.100000001490116119384765625) + (_185 * 1.7000000476837158203125)).xzy * 2.0) - vec3(1.0))) + ((texture(normal_map_normalsmp, (pos.xz * 1.0) + (_185 * 2.7000000476837158203125)).xzy * 2.0) - vec3(1.0))) + ((texture(normal_map_normalsmp, (pos.xz * 0.0199999995529651641845703125) + (_185 * 0.100000001490116119384765625)).xzy * 2.0) - vec3(1.0)));
vec3 _285 = normalize(_278.cameraPosition - pos.xyz);
vec3 _290 = normalize(_146.sunPosition);
float _318 = dot(_274, _290) + ((9.9999999747524270787835121154785e-07 * float(_309.is_reflection)) * _278.shininess);
float param = _285.y;
float _335 = min(1.0, fresnelSchlick(param).x + 0.300000011920928955078125);
vec2 _367 = gl_FragCoord.xy / vec2(float(_278.screen_w), float(_278.screen_h));
_367.y = 1.0 - _367.y;
vec3 _380 = texture(reftex_refsmp, _367).xyz;
vec3 param_1 = normalize(pos.xyz);
vec3 param_2 = _146.sunPosition;
float _422 = smoothstep(750.0, 1000.0, length(pos.xz));
frag_color = vec4(mix((mix(((_146.waterColor * (dot(_274, _290) + ((9.9999999747524270787835121154785e-07 * float(_309.is_reflection)) * _278.shininess))) * _146.sunLightColor) * _146.sunIntensity, texture(reftex_refsmp, _367).xyz, vec3(min(1.0, _335 * 1.7999999523162841796875))) + ((_146.sunLightColor * _146.sunIntensity) * pow(max(0.0, dot(normalize(_290 + _285), _274)), 32.0))) * 1.0, sky(param_1, param_2) * _146.skyIntensity, vec3(_422)), mix(mix(0.300000011920928955078125, 0.5, _335), 1.0, _422));
float _429 = smoothstep(750.0, 1000.0, length(pos.xz));
frag_color = vec4(mix(((_380 + (((_146.sunLightColor * _146.sunIntensity) * pow(max(0.0, dot(normalize(_290 + _285), _274)), 32.0)) * 0.20000000298023223876953125)) + vec3(_318 * 0.20000000298023223876953125)) + (mix(((_146.waterColor * _318) * _146.sunLightColor) * _146.sunIntensity, _380, vec3(min(1.0, _335))) * 9.9999997473787516355514526367188e-06), sky(param_1, param_2) * _146.skyIntensity, vec3(_429)), mix(mix(0.4000000059604644775390625, 1.0, _335), 1.0, _429));
}
else
{
vec2 param_3 = (pos.xz * 0.0500000007450580596923828125) + vec2(_146.time * 0.00999999977648258209228515625);
float _452 = fbm(param_3);
frag_color = vec4(_146.deepColor * mix(0.800000011920928955078125, 1.2000000476837158203125, _452), 1.0);
float _459 = fbm(param_3);
frag_color = vec4(_146.deepColor * mix(0.800000011920928955078125, 1.2000000476837158203125, _459), 1.0);
}
}
@ -449,81 +451,90 @@ fs_plane_source_glsl430 := u8.[
0x33,0x20,0x5f,0x32,0x39,0x30,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,
0x7a,0x65,0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x50,0x6f,0x73,0x69,0x74,
0x69,0x6f,0x6e,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,
0x6f,0x61,0x74,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,0x20,0x5f,0x32,0x38,0x35,
0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,
0x74,0x20,0x5f,0x33,0x33,0x35,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,
0x2c,0x20,0x66,0x72,0x65,0x73,0x6e,0x65,0x6c,0x53,0x63,0x68,0x6c,0x69,0x63,0x6b,
0x28,0x70,0x61,0x72,0x61,0x6d,0x29,0x2e,0x78,0x20,0x2b,0x20,0x30,0x2e,0x33,0x30,
0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,
0x30,0x37,0x38,0x31,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x76,0x65,0x63,0x32,0x20,0x5f,0x33,0x36,0x37,0x20,0x3d,0x20,0x67,0x6c,0x5f,
0x46,0x72,0x61,0x67,0x43,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x20,0x2f,0x20,0x76,
0x65,0x63,0x32,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,
0x63,0x72,0x65,0x65,0x6e,0x5f,0x77,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,
0x5f,0x32,0x37,0x38,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,0x68,0x29,0x29,0x3b,
0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x20,
0x3d,0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x3b,0x0a,
0x6f,0x61,0x74,0x20,0x5f,0x33,0x31,0x38,0x20,0x3d,0x20,0x64,0x6f,0x74,0x28,0x5f,
0x32,0x37,0x34,0x2c,0x20,0x5f,0x32,0x39,0x30,0x29,0x20,0x2b,0x20,0x28,0x28,0x39,
0x2e,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x35,0x32,0x34,0x32,0x37,
0x30,0x37,0x38,0x37,0x38,0x33,0x35,0x31,0x32,0x31,0x31,0x35,0x34,0x37,0x38,0x35,
0x65,0x2d,0x30,0x37,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x33,0x30,
0x39,0x2e,0x69,0x73,0x5f,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x29,
0x29,0x20,0x2a,0x20,0x5f,0x32,0x37,0x38,0x2e,0x73,0x68,0x69,0x6e,0x69,0x6e,0x65,
0x73,0x73,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,
0x61,0x74,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,0x20,0x5f,0x32,0x38,0x35,0x2e,
0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,
0x20,0x5f,0x33,0x33,0x35,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,
0x20,0x66,0x72,0x65,0x73,0x6e,0x65,0x6c,0x53,0x63,0x68,0x6c,0x69,0x63,0x6b,0x28,
0x70,0x61,0x72,0x61,0x6d,0x29,0x2e,0x78,0x20,0x2b,0x20,0x30,0x2e,0x33,0x30,0x30,
0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,
0x37,0x38,0x31,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x76,0x65,0x63,0x32,0x20,0x5f,0x33,0x36,0x37,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x46,
0x72,0x61,0x67,0x43,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x20,0x2f,0x20,0x76,0x65,
0x63,0x32,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,0x63,
0x72,0x65,0x65,0x6e,0x5f,0x77,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,
0x32,0x37,0x38,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,0x68,0x29,0x29,0x3b,0x0a,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x20,0x3d,
0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x3b,0x0a,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x33,0x38,0x30,
0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x72,0x65,0x66,0x74,0x65,
0x78,0x5f,0x72,0x65,0x66,0x73,0x6d,0x70,0x2c,0x20,0x5f,0x33,0x36,0x37,0x29,0x2e,
0x78,0x79,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,
0x33,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,
0x61,0x6c,0x69,0x7a,0x65,0x28,0x70,0x6f,0x73,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x33,0x20,0x70,0x61,0x72,
0x61,0x6d,0x5f,0x31,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,
0x28,0x70,0x6f,0x73,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x76,0x65,0x63,0x33,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x32,0x20,
0x3d,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x50,0x6f,0x73,0x69,0x74,0x69,
0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,
0x74,0x20,0x5f,0x34,0x32,0x32,0x20,0x3d,0x20,0x73,0x6d,0x6f,0x6f,0x74,0x68,0x73,
0x74,0x65,0x70,0x28,0x37,0x35,0x30,0x2e,0x30,0x2c,0x20,0x31,0x30,0x30,0x30,0x2e,
0x30,0x2c,0x20,0x6c,0x65,0x6e,0x67,0x74,0x68,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,
0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,
0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x6d,0x69,
0x78,0x28,0x28,0x6d,0x69,0x78,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x77,0x61,
0x74,0x65,0x72,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x28,0x64,0x6f,0x74,0x28,
0x5f,0x32,0x37,0x34,0x2c,0x20,0x5f,0x32,0x39,0x30,0x29,0x20,0x2b,0x20,0x28,0x28,
0x39,0x2e,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x35,0x32,0x34,0x32,
0x37,0x30,0x37,0x38,0x37,0x38,0x33,0x35,0x31,0x32,0x31,0x31,0x35,0x34,0x37,0x38,
0x35,0x65,0x2d,0x30,0x37,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x33,
0x30,0x39,0x2e,0x69,0x73,0x5f,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,
0x29,0x29,0x20,0x2a,0x20,0x5f,0x32,0x37,0x38,0x2e,0x73,0x68,0x69,0x6e,0x69,0x6e,
0x65,0x73,0x73,0x29,0x29,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,
0x6e,0x4c,0x69,0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x29,0x20,0x2a,0x20,0x5f,
0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,
0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x72,0x65,0x66,0x74,0x65,0x78,
0x5f,0x72,0x65,0x66,0x73,0x6d,0x70,0x2c,0x20,0x5f,0x33,0x36,0x37,0x29,0x2e,0x78,
0x79,0x7a,0x2c,0x20,0x76,0x65,0x63,0x33,0x28,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,
0x2c,0x20,0x5f,0x33,0x33,0x35,0x20,0x2a,0x20,0x31,0x2e,0x37,0x39,0x39,0x39,0x39,
0x39,0x39,0x35,0x32,0x33,0x31,0x36,0x32,0x38,0x34,0x31,0x37,0x39,0x36,0x38,0x37,
0x35,0x29,0x29,0x29,0x20,0x2b,0x20,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,
0x6e,0x4c,0x69,0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x31,
0x34,0x36,0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x29,
0x20,0x2a,0x20,0x70,0x6f,0x77,0x28,0x6d,0x61,0x78,0x28,0x30,0x2e,0x30,0x2c,0x20,
0x64,0x6f,0x74,0x28,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x32,
0x39,0x30,0x20,0x2b,0x20,0x5f,0x32,0x38,0x35,0x29,0x2c,0x20,0x5f,0x32,0x37,0x34,
0x29,0x29,0x2c,0x20,0x33,0x32,0x2e,0x30,0x29,0x29,0x29,0x20,0x2a,0x20,0x31,0x2e,
0x30,0x2c,0x20,0x73,0x6b,0x79,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,0x2c,0x20,
0x70,0x61,0x72,0x61,0x6d,0x5f,0x32,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,
0x73,0x6b,0x79,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x76,0x65,
0x63,0x33,0x28,0x5f,0x34,0x32,0x32,0x29,0x29,0x2c,0x20,0x6d,0x69,0x78,0x28,0x6d,
0x69,0x78,0x28,0x30,0x2e,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,
0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x2c,0x20,0x30,
0x2e,0x35,0x2c,0x20,0x5f,0x33,0x33,0x35,0x29,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,
0x5f,0x34,0x32,0x32,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,
0x20,0x20,0x65,0x6c,0x73,0x65,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,
0x33,0x20,0x3d,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x20,0x2a,0x20,0x30,0x2e,
0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x37,0x34,0x35,0x30,0x35,0x38,0x30,
0x35,0x39,0x36,0x39,0x32,0x33,0x38,0x32,0x38,0x31,0x32,0x35,0x29,0x20,0x2b,0x20,
0x76,0x65,0x63,0x32,0x28,0x5f,0x31,0x34,0x36,0x2e,0x74,0x69,0x6d,0x65,0x20,0x2a,
0x20,0x30,0x2e,0x30,0x30,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x37,0x36,0x34,
0x38,0x32,0x35,0x38,0x32,0x30,0x39,0x32,0x32,0x38,0x35,0x31,0x35,0x36,0x32,0x35,
0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,
0x20,0x5f,0x34,0x35,0x32,0x20,0x3d,0x20,0x66,0x62,0x6d,0x28,0x70,0x61,0x72,0x61,
0x6d,0x5f,0x33,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x72,
0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,
0x5f,0x31,0x34,0x36,0x2e,0x64,0x65,0x65,0x70,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,
0x20,0x6d,0x69,0x78,0x28,0x30,0x2e,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,
0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x2c,
0x20,0x31,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x34,0x37,0x36,0x38,0x33,0x37,
0x31,0x35,0x38,0x32,0x30,0x33,0x31,0x32,0x35,0x2c,0x20,0x5f,0x34,0x35,0x32,0x29,
0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x7d,0x0a,
0x0a,0x00,
0x61,0x6d,0x5f,0x32,0x20,0x3d,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x50,
0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,0x32,0x39,0x20,0x3d,0x20,0x73,0x6d,
0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,0x37,0x35,0x30,0x2e,0x30,0x2c,0x20,
0x31,0x30,0x30,0x30,0x2e,0x30,0x2c,0x20,0x6c,0x65,0x6e,0x67,0x74,0x68,0x28,0x70,
0x6f,0x73,0x2e,0x78,0x7a,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,
0x63,0x34,0x28,0x6d,0x69,0x78,0x28,0x28,0x28,0x5f,0x33,0x38,0x30,0x20,0x2b,0x20,
0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,0x68,0x74,
0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,
0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x29,0x20,0x2a,0x20,0x70,0x6f,0x77,
0x28,0x6d,0x61,0x78,0x28,0x30,0x2e,0x30,0x2c,0x20,0x64,0x6f,0x74,0x28,0x6e,0x6f,
0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x32,0x39,0x30,0x20,0x2b,0x20,0x5f,
0x32,0x38,0x35,0x29,0x2c,0x20,0x5f,0x32,0x37,0x34,0x29,0x29,0x2c,0x20,0x33,0x32,
0x2e,0x30,0x29,0x29,0x20,0x2a,0x20,0x30,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,
0x30,0x32,0x39,0x38,0x30,0x32,0x33,0x32,0x32,0x33,0x38,0x37,0x36,0x39,0x35,0x33,
0x31,0x32,0x35,0x29,0x29,0x20,0x2b,0x20,0x76,0x65,0x63,0x33,0x28,0x5f,0x33,0x31,
0x38,0x20,0x2a,0x20,0x30,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x39,
0x38,0x30,0x32,0x33,0x32,0x32,0x33,0x38,0x37,0x36,0x39,0x35,0x33,0x31,0x32,0x35,
0x29,0x29,0x20,0x2b,0x20,0x28,0x6d,0x69,0x78,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,
0x2e,0x77,0x61,0x74,0x65,0x72,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x33,
0x31,0x38,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,
0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,
0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x5f,
0x33,0x38,0x30,0x2c,0x20,0x76,0x65,0x63,0x33,0x28,0x6d,0x69,0x6e,0x28,0x31,0x2e,
0x30,0x2c,0x20,0x5f,0x33,0x33,0x35,0x29,0x29,0x29,0x20,0x2a,0x20,0x39,0x2e,0x39,
0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x33,0x37,0x38,0x37,0x35,0x31,0x36,0x33,
0x35,0x35,0x35,0x31,0x34,0x35,0x32,0x36,0x33,0x36,0x37,0x31,0x38,0x38,0x65,0x2d,
0x30,0x36,0x29,0x2c,0x20,0x73,0x6b,0x79,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,
0x2c,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x32,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,
0x36,0x2e,0x73,0x6b,0x79,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,
0x76,0x65,0x63,0x33,0x28,0x5f,0x34,0x32,0x39,0x29,0x29,0x2c,0x20,0x6d,0x69,0x78,
0x28,0x6d,0x69,0x78,0x28,0x30,0x2e,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x35,
0x39,0x36,0x30,0x34,0x36,0x34,0x34,0x37,0x37,0x35,0x33,0x39,0x30,0x36,0x32,0x35,
0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x33,0x33,0x35,0x29,0x2c,0x20,0x31,0x2e,
0x30,0x2c,0x20,0x5f,0x34,0x32,0x39,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,
0x0a,0x20,0x20,0x20,0x20,0x65,0x6c,0x73,0x65,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x61,0x72,
0x61,0x6d,0x5f,0x33,0x20,0x3d,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x20,0x2a,
0x20,0x30,0x2e,0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x37,0x34,0x35,0x30,
0x35,0x38,0x30,0x35,0x39,0x36,0x39,0x32,0x33,0x38,0x32,0x38,0x31,0x32,0x35,0x29,
0x20,0x2b,0x20,0x76,0x65,0x63,0x32,0x28,0x5f,0x31,0x34,0x36,0x2e,0x74,0x69,0x6d,
0x65,0x20,0x2a,0x20,0x30,0x2e,0x30,0x30,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,
0x37,0x36,0x34,0x38,0x32,0x35,0x38,0x32,0x30,0x39,0x32,0x32,0x38,0x35,0x31,0x35,
0x36,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,
0x6f,0x61,0x74,0x20,0x5f,0x34,0x35,0x39,0x20,0x3d,0x20,0x66,0x62,0x6d,0x28,0x70,
0x61,0x72,0x61,0x6d,0x5f,0x33,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,
0x63,0x34,0x28,0x5f,0x31,0x34,0x36,0x2e,0x64,0x65,0x65,0x70,0x43,0x6f,0x6c,0x6f,
0x72,0x20,0x2a,0x20,0x6d,0x69,0x78,0x28,0x30,0x2e,0x38,0x30,0x30,0x30,0x30,0x30,
0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,
0x32,0x35,0x2c,0x20,0x31,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x34,0x37,0x36,
0x38,0x33,0x37,0x31,0x35,0x38,0x32,0x30,0x33,0x31,0x32,0x35,0x2c,0x20,0x5f,0x34,
0x35,0x39,0x29,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,
0x0a,0x7d,0x0a,0x0a,0x00,
];
/*
#version 300 es
@ -681,20 +692,22 @@ vs_plane_source_glsl300es := u8.[
highp vec3 _274 = normalize(((((texture(normal_map_normalsmp, (pos.xz * 0.4000000059604644775390625) + (_185 * 1.5)).xzy * 2.0) - vec3(1.0)) + ((texture(normal_map_normalsmp, (pos.xz * 0.100000001490116119384765625) + (_185 * 1.7000000476837158203125)).xzy * 2.0) - vec3(1.0))) + ((texture(normal_map_normalsmp, (pos.xz * 1.0) + (_185 * 2.7000000476837158203125)).xzy * 2.0) - vec3(1.0))) + ((texture(normal_map_normalsmp, (pos.xz * 0.0199999995529651641845703125) + (_185 * 0.100000001490116119384765625)).xzy * 2.0) - vec3(1.0)));
highp vec3 _285 = normalize(_278.cameraPosition - pos.xyz);
highp vec3 _290 = normalize(_146.sunPosition);
highp float _318 = dot(_274, _290) + ((9.9999999747524270787835121154785e-07 * float(_309.is_reflection)) * _278.shininess);
highp float param = _285.y;
highp float _335 = min(1.0, fresnelSchlick(param).x + 0.300000011920928955078125);
highp vec2 _367 = gl_FragCoord.xy / vec2(float(_278.screen_w), float(_278.screen_h));
_367.y = 1.0 - _367.y;
highp vec3 _380 = texture(reftex_refsmp, _367).xyz;
highp vec3 param_1 = normalize(pos.xyz);
highp vec3 param_2 = _146.sunPosition;
highp float _422 = smoothstep(750.0, 1000.0, length(pos.xz));
frag_color = vec4(mix((mix(((_146.waterColor * (dot(_274, _290) + ((9.9999999747524270787835121154785e-07 * float(_309.is_reflection)) * _278.shininess))) * _146.sunLightColor) * _146.sunIntensity, texture(reftex_refsmp, _367).xyz, vec3(min(1.0, _335 * 1.7999999523162841796875))) + ((_146.sunLightColor * _146.sunIntensity) * pow(max(0.0, dot(normalize(_290 + _285), _274)), 32.0))) * 1.0, sky(param_1, param_2) * _146.skyIntensity, vec3(_422)), mix(mix(0.300000011920928955078125, 0.5, _335), 1.0, _422));
highp float _429 = smoothstep(750.0, 1000.0, length(pos.xz));
frag_color = vec4(mix(((_380 + (((_146.sunLightColor * _146.sunIntensity) * pow(max(0.0, dot(normalize(_290 + _285), _274)), 32.0)) * 0.20000000298023223876953125)) + vec3(_318 * 0.20000000298023223876953125)) + (mix(((_146.waterColor * _318) * _146.sunLightColor) * _146.sunIntensity, _380, vec3(min(1.0, _335))) * 9.9999997473787516355514526367188e-06), sky(param_1, param_2) * _146.skyIntensity, vec3(_429)), mix(mix(0.4000000059604644775390625, 1.0, _335), 1.0, _429));
}
else
{
highp vec2 param_3 = (pos.xz * 0.0500000007450580596923828125) + vec2(_146.time * 0.00999999977648258209228515625);
highp float _452 = fbm(param_3);
frag_color = vec4(_146.deepColor * mix(0.800000011920928955078125, 1.2000000476837158203125, _452), 1.0);
highp float _459 = fbm(param_3);
frag_color = vec4(_146.deepColor * mix(0.800000011920928955078125, 1.2000000476837158203125, _459), 1.0);
}
}
@ -891,83 +904,93 @@ fs_plane_source_glsl300es := u8.[
0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x31,0x34,0x36,0x2e,
0x73,0x75,0x6e,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x3b,0x0a,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,
0x74,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,0x20,0x5f,0x32,0x38,0x35,0x2e,0x79,
0x74,0x20,0x5f,0x33,0x31,0x38,0x20,0x3d,0x20,0x64,0x6f,0x74,0x28,0x5f,0x32,0x37,
0x34,0x2c,0x20,0x5f,0x32,0x39,0x30,0x29,0x20,0x2b,0x20,0x28,0x28,0x39,0x2e,0x39,
0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x35,0x32,0x34,0x32,0x37,0x30,0x37,
0x38,0x37,0x38,0x33,0x35,0x31,0x32,0x31,0x31,0x35,0x34,0x37,0x38,0x35,0x65,0x2d,
0x30,0x37,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x33,0x30,0x39,0x2e,
0x69,0x73,0x5f,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x29,0x29,0x20,
0x2a,0x20,0x5f,0x32,0x37,0x38,0x2e,0x73,0x68,0x69,0x6e,0x69,0x6e,0x65,0x73,0x73,
0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,
0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,0x20,0x5f,
0x32,0x38,0x35,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,
0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x33,0x35,0x20,
0x3d,0x20,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,0x20,0x66,0x72,0x65,0x73,0x6e,
0x65,0x6c,0x53,0x63,0x68,0x6c,0x69,0x63,0x6b,0x28,0x70,0x61,0x72,0x61,0x6d,0x29,
0x2e,0x78,0x20,0x2b,0x20,0x30,0x2e,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,
0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x29,
0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,
0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x33,0x35,0x20,0x3d,0x20,0x6d,0x69,0x6e,
0x28,0x31,0x2e,0x30,0x2c,0x20,0x66,0x72,0x65,0x73,0x6e,0x65,0x6c,0x53,0x63,0x68,
0x6c,0x69,0x63,0x6b,0x28,0x70,0x61,0x72,0x61,0x6d,0x29,0x2e,0x78,0x20,0x2b,0x20,
0x30,0x2e,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,
0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,
0x5f,0x33,0x36,0x37,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x46,0x72,0x61,0x67,0x43,0x6f,
0x6f,0x72,0x64,0x2e,0x78,0x79,0x20,0x2f,0x20,0x76,0x65,0x63,0x32,0x28,0x66,0x6c,
0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,
0x77,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,
0x63,0x72,0x65,0x65,0x6e,0x5f,0x68,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x20,0x3d,0x20,0x31,0x2e,0x30,0x20,
0x2d,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x70,0x61,0x72,
0x61,0x6d,0x5f,0x31,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,
0x28,0x70,0x6f,0x73,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x76,0x65,0x63,0x32,0x20,0x5f,0x33,0x36,0x37,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x46,
0x72,0x61,0x67,0x43,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x20,0x2f,0x20,0x76,0x65,
0x63,0x32,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,0x63,
0x72,0x65,0x65,0x6e,0x5f,0x77,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,
0x32,0x37,0x38,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,0x68,0x29,0x29,0x3b,0x0a,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x20,0x3d,
0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x3b,0x0a,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,
0x33,0x20,0x5f,0x33,0x38,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,
0x28,0x72,0x65,0x66,0x74,0x65,0x78,0x5f,0x72,0x65,0x66,0x73,0x6d,0x70,0x2c,0x20,
0x5f,0x33,0x36,0x37,0x29,0x2e,0x78,0x79,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x70,0x61,
0x72,0x61,0x6d,0x5f,0x32,0x20,0x3d,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,
0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,
0x32,0x32,0x20,0x3d,0x20,0x73,0x6d,0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,
0x37,0x35,0x30,0x2e,0x30,0x2c,0x20,0x31,0x30,0x30,0x30,0x2e,0x30,0x2c,0x20,0x6c,
0x65,0x6e,0x67,0x74,0x68,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x29,0x29,0x3b,0x0a,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,
0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x6d,0x69,0x78,0x28,0x28,0x6d,
0x69,0x78,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x77,0x61,0x74,0x65,0x72,0x43,
0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x28,0x64,0x6f,0x74,0x28,0x5f,0x32,0x37,0x34,
0x2c,0x20,0x5f,0x32,0x39,0x30,0x29,0x20,0x2b,0x20,0x28,0x28,0x39,0x2e,0x39,0x39,
0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x35,0x32,0x34,0x32,0x37,0x30,0x37,0x38,
0x37,0x38,0x33,0x35,0x31,0x32,0x31,0x31,0x35,0x34,0x37,0x38,0x35,0x65,0x2d,0x30,
0x37,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x33,0x30,0x39,0x2e,0x69,
0x73,0x5f,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x29,0x29,0x20,0x2a,
0x20,0x5f,0x32,0x37,0x38,0x2e,0x73,0x68,0x69,0x6e,0x69,0x6e,0x65,0x73,0x73,0x29,
0x29,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,
0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,
0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x74,0x65,
0x78,0x74,0x75,0x72,0x65,0x28,0x72,0x65,0x66,0x74,0x65,0x78,0x5f,0x72,0x65,0x66,
0x73,0x6d,0x70,0x2c,0x20,0x5f,0x33,0x36,0x37,0x29,0x2e,0x78,0x79,0x7a,0x2c,0x20,
0x76,0x65,0x63,0x33,0x28,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x33,
0x33,0x35,0x20,0x2a,0x20,0x31,0x2e,0x37,0x39,0x39,0x39,0x39,0x39,0x39,0x35,0x32,
0x33,0x31,0x36,0x32,0x38,0x34,0x31,0x37,0x39,0x36,0x38,0x37,0x35,0x29,0x29,0x29,
0x20,0x2b,0x20,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,
0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,
0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x29,0x20,0x2a,0x20,0x70,
0x6f,0x77,0x28,0x6d,0x61,0x78,0x28,0x30,0x2e,0x30,0x2c,0x20,0x64,0x6f,0x74,0x28,
0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x32,0x39,0x30,0x20,0x2b,
0x20,0x5f,0x32,0x38,0x35,0x29,0x2c,0x20,0x5f,0x32,0x37,0x34,0x29,0x29,0x2c,0x20,
0x33,0x32,0x2e,0x30,0x29,0x29,0x29,0x20,0x2a,0x20,0x31,0x2e,0x30,0x2c,0x20,0x73,
0x6b,0x79,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,0x2c,0x20,0x70,0x61,0x72,0x61,
0x6d,0x5f,0x32,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x6b,0x79,0x49,
0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x76,0x65,0x63,0x33,0x28,0x5f,
0x34,0x32,0x32,0x29,0x29,0x2c,0x20,0x6d,0x69,0x78,0x28,0x6d,0x69,0x78,0x28,0x30,
0x2e,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,
0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20,
0x5f,0x33,0x33,0x35,0x29,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x34,0x32,0x32,
0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,0x65,0x6c,
0x73,0x65,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x61,0x72,0x61,
0x6d,0x5f,0x33,0x20,0x3d,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x20,0x2a,0x20,
0x30,0x2e,0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x37,0x34,0x35,0x30,0x35,
0x38,0x30,0x35,0x39,0x36,0x39,0x32,0x33,0x38,0x32,0x38,0x31,0x32,0x35,0x29,0x20,
0x2b,0x20,0x76,0x65,0x63,0x32,0x28,0x5f,0x31,0x34,0x36,0x2e,0x74,0x69,0x6d,0x65,
0x20,0x2a,0x20,0x30,0x2e,0x30,0x30,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x37,
0x36,0x34,0x38,0x32,0x35,0x38,0x32,0x30,0x39,0x32,0x32,0x38,0x35,0x31,0x35,0x36,
0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,
0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,0x35,0x32,0x20,0x3d,0x20,
0x66,0x62,0x6d,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x33,0x29,0x3b,0x0a,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,
0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x31,0x34,0x36,0x2e,0x64,0x65,0x65,
0x70,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x6d,0x69,0x78,0x28,0x30,0x2e,0x38,
0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,
0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x2c,0x20,0x31,0x2e,0x32,0x30,0x30,0x30,0x30,
0x30,0x30,0x34,0x37,0x36,0x38,0x33,0x37,0x31,0x35,0x38,0x32,0x30,0x33,0x31,0x32,
0x35,0x2c,0x20,0x5f,0x34,0x35,0x32,0x29,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,
0x20,0x20,0x20,0x20,0x7d,0x0a,0x7d,0x0a,0x0a,0x00,
0x72,0x61,0x6d,0x5f,0x31,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,
0x65,0x28,0x70,0x6f,0x73,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x70,
0x61,0x72,0x61,0x6d,0x5f,0x32,0x20,0x3d,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,
0x6e,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,
0x34,0x32,0x39,0x20,0x3d,0x20,0x73,0x6d,0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,
0x28,0x37,0x35,0x30,0x2e,0x30,0x2c,0x20,0x31,0x30,0x30,0x30,0x2e,0x30,0x2c,0x20,
0x6c,0x65,0x6e,0x67,0x74,0x68,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x29,0x29,0x3b,
0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,
0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x6d,0x69,0x78,0x28,0x28,
0x28,0x5f,0x33,0x38,0x30,0x20,0x2b,0x20,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,
0x73,0x75,0x6e,0x4c,0x69,0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,
0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,
0x79,0x29,0x20,0x2a,0x20,0x70,0x6f,0x77,0x28,0x6d,0x61,0x78,0x28,0x30,0x2e,0x30,
0x2c,0x20,0x64,0x6f,0x74,0x28,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,
0x5f,0x32,0x39,0x30,0x20,0x2b,0x20,0x5f,0x32,0x38,0x35,0x29,0x2c,0x20,0x5f,0x32,
0x37,0x34,0x29,0x29,0x2c,0x20,0x33,0x32,0x2e,0x30,0x29,0x29,0x20,0x2a,0x20,0x30,
0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x39,0x38,0x30,0x32,0x33,0x32,
0x32,0x33,0x38,0x37,0x36,0x39,0x35,0x33,0x31,0x32,0x35,0x29,0x29,0x20,0x2b,0x20,
0x76,0x65,0x63,0x33,0x28,0x5f,0x33,0x31,0x38,0x20,0x2a,0x20,0x30,0x2e,0x32,0x30,
0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x39,0x38,0x30,0x32,0x33,0x32,0x32,0x33,0x38,
0x37,0x36,0x39,0x35,0x33,0x31,0x32,0x35,0x29,0x29,0x20,0x2b,0x20,0x28,0x6d,0x69,
0x78,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x77,0x61,0x74,0x65,0x72,0x43,0x6f,
0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x33,0x31,0x38,0x29,0x20,0x2a,0x20,0x5f,0x31,
0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,
0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,
0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x5f,0x33,0x38,0x30,0x2c,0x20,0x76,0x65,0x63,
0x33,0x28,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x33,0x33,0x35,0x29,
0x29,0x29,0x20,0x2a,0x20,0x39,0x2e,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,
0x33,0x37,0x38,0x37,0x35,0x31,0x36,0x33,0x35,0x35,0x35,0x31,0x34,0x35,0x32,0x36,
0x33,0x36,0x37,0x31,0x38,0x38,0x65,0x2d,0x30,0x36,0x29,0x2c,0x20,0x73,0x6b,0x79,
0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,0x2c,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,
0x32,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x6b,0x79,0x49,0x6e,0x74,
0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x76,0x65,0x63,0x33,0x28,0x5f,0x34,0x32,
0x39,0x29,0x29,0x2c,0x20,0x6d,0x69,0x78,0x28,0x6d,0x69,0x78,0x28,0x30,0x2e,0x34,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x35,0x39,0x36,0x30,0x34,0x36,0x34,0x34,0x37,
0x37,0x35,0x33,0x39,0x30,0x36,0x32,0x35,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x5f,
0x33,0x33,0x35,0x29,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x34,0x32,0x39,0x29,
0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,0x65,0x6c,0x73,
0x65,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x61,0x72,0x61,0x6d,
0x5f,0x33,0x20,0x3d,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x20,0x2a,0x20,0x30,
0x2e,0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x37,0x34,0x35,0x30,0x35,0x38,
0x30,0x35,0x39,0x36,0x39,0x32,0x33,0x38,0x32,0x38,0x31,0x32,0x35,0x29,0x20,0x2b,
0x20,0x76,0x65,0x63,0x32,0x28,0x5f,0x31,0x34,0x36,0x2e,0x74,0x69,0x6d,0x65,0x20,
0x2a,0x20,0x30,0x2e,0x30,0x30,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x37,0x36,
0x34,0x38,0x32,0x35,0x38,0x32,0x30,0x39,0x32,0x32,0x38,0x35,0x31,0x35,0x36,0x32,
0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,
0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,0x35,0x39,0x20,0x3d,0x20,0x66,
0x62,0x6d,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x33,0x29,0x3b,0x0a,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,
0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x31,0x34,0x36,0x2e,0x64,0x65,0x65,0x70,
0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x6d,0x69,0x78,0x28,0x30,0x2e,0x38,0x30,
0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,
0x30,0x37,0x38,0x31,0x32,0x35,0x2c,0x20,0x31,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,
0x30,0x34,0x37,0x36,0x38,0x33,0x37,0x31,0x35,0x38,0x32,0x30,0x33,0x31,0x32,0x35,
0x2c,0x20,0x5f,0x34,0x35,0x39,0x29,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,
0x20,0x20,0x20,0x7d,0x0a,0x7d,0x0a,0x0a,0x00,
];
/*
#include <metal_stdlib>
@ -1171,20 +1194,22 @@ vs_plane_source_metal_macos := u8.[
float3 _274 = fast::normalize(((((normal_map.sample(normalsmp, ((in.pos.xz * 0.4000000059604644775390625) + (_185 * 1.5))).xzy * 2.0) - float3(1.0)) + ((normal_map.sample(normalsmp, ((in.pos.xz * 0.100000001490116119384765625) + (_185 * 1.7000000476837158203125))).xzy * 2.0) - float3(1.0))) + ((normal_map.sample(normalsmp, ((in.pos.xz * 1.0) + (_185 * 2.7000000476837158203125))).xzy * 2.0) - float3(1.0))) + ((normal_map.sample(normalsmp, ((in.pos.xz * 0.0199999995529651641845703125) + (_185 * 0.100000001490116119384765625))).xzy * 2.0) - float3(1.0)));
float3 _285 = fast::normalize(float3(_278.cameraPosition) - in.pos.xyz);
float3 _290 = fast::normalize(float3(_146.sunPosition));
float _318 = dot(_274, _290) + ((9.9999999747524270787835121154785e-07 * float(_309.is_reflection)) * _278.shininess);
float param = _285.y;
float _335 = fast::min(1.0, fresnelSchlick(param).x + 0.300000011920928955078125);
float2 _367 = gl_FragCoord.xy / float2(float(_278.screen_w), float(_278.screen_h));
_367.y = 1.0 - _367.y;
float3 _380 = reftex.sample(refsmp, _367).xyz;
float3 param_1 = fast::normalize(in.pos.xyz);
float3 param_2 = float3(_146.sunPosition);
float _422 = smoothstep(750.0, 1000.0, length(in.pos.xz));
out.frag_color = float4(mix((mix(((_146.waterColor * (dot(_274, _290) + ((9.9999999747524270787835121154785e-07 * float(_309.is_reflection)) * _278.shininess))) * _146.sunLightColor) * _146.sunIntensity, reftex.sample(refsmp, _367).xyz, float3(fast::min(1.0, _335 * 1.7999999523162841796875))) + ((_146.sunLightColor * _146.sunIntensity) * powr(fast::max(0.0, dot(fast::normalize(_290 + _285), _274)), 32.0))) * 1.0, sky(param_1, param_2, _146) * _146.skyIntensity, float3(_422)), mix(mix(0.300000011920928955078125, 0.5, _335), 1.0, _422));
float _429 = smoothstep(750.0, 1000.0, length(in.pos.xz));
out.frag_color = float4(mix(((_380 + (((_146.sunLightColor * _146.sunIntensity) * powr(fast::max(0.0, dot(fast::normalize(_290 + _285), _274)), 32.0)) * 0.20000000298023223876953125)) + float3(_318 * 0.20000000298023223876953125)) + (mix(((_146.waterColor * _318) * _146.sunLightColor) * _146.sunIntensity, _380, float3(fast::min(1.0, _335))) * 9.9999997473787516355514526367188e-06), sky(param_1, param_2, _146) * _146.skyIntensity, float3(_429)), mix(mix(0.4000000059604644775390625, 1.0, _335), 1.0, _429));
}
else
{
float2 param_3 = (in.pos.xz * 0.0500000007450580596923828125) + float2(_146.time * 0.00999999977648258209228515625);
float _452 = fbm(param_3);
out.frag_color = float4(float3(_146.deepColor) * mix(0.800000011920928955078125, 1.2000000476837158203125, _452), 1.0);
float _459 = fbm(param_3);
out.frag_color = float4(float3(_146.deepColor) * mix(0.800000011920928955078125, 1.2000000476837158203125, _459), 1.0);
}
return out;
}
@ -1417,88 +1442,97 @@ fs_plane_source_metal_macos := u8.[
0x66,0x61,0x73,0x74,0x3a,0x3a,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,
0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x50,
0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,
0x20,0x5f,0x32,0x38,0x35,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x33,0x35,0x20,0x3d,0x20,0x66,0x61,
0x73,0x74,0x3a,0x3a,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,0x20,0x66,0x72,0x65,
0x73,0x6e,0x65,0x6c,0x53,0x63,0x68,0x6c,0x69,0x63,0x6b,0x28,0x70,0x61,0x72,0x61,
0x6d,0x29,0x2e,0x78,0x20,0x2b,0x20,0x30,0x2e,0x33,0x30,0x30,0x30,0x30,0x30,0x30,
0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,
0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,
0x74,0x32,0x20,0x5f,0x33,0x36,0x37,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x46,0x72,0x61,
0x67,0x43,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x20,0x2f,0x20,0x66,0x6c,0x6f,0x61,
0x74,0x32,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,0x63,
0x72,0x65,0x65,0x6e,0x5f,0x77,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,
0x32,0x37,0x38,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,0x68,0x29,0x29,0x3b,0x0a,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x20,0x3d,
0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x3b,0x0a,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20,0x70,0x61,
0x72,0x61,0x6d,0x5f,0x31,0x20,0x3d,0x20,0x66,0x61,0x73,0x74,0x3a,0x3a,0x6e,0x6f,
0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2e,0x78,
0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,
0x61,0x74,0x33,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x32,0x20,0x3d,0x20,0x66,0x6c,
0x6f,0x61,0x74,0x33,0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x50,0x6f,0x73,
0x69,0x74,0x69,0x6f,0x6e,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,0x32,0x32,0x20,0x3d,0x20,0x73,0x6d,0x6f,
0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,0x37,0x35,0x30,0x2e,0x30,0x2c,0x20,0x31,
0x30,0x30,0x30,0x2e,0x30,0x2c,0x20,0x6c,0x65,0x6e,0x67,0x74,0x68,0x28,0x69,0x6e,
0x2e,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,
0x72,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x6d,0x69,0x78,0x28,0x28,
0x6d,0x69,0x78,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x77,0x61,0x74,0x65,0x72,
0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x28,0x64,0x6f,0x74,0x28,0x5f,0x32,0x37,
0x34,0x2c,0x20,0x5f,0x32,0x39,0x30,0x29,0x20,0x2b,0x20,0x28,0x28,0x39,0x2e,0x39,
0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x35,0x32,0x34,0x32,0x37,0x30,0x37,
0x38,0x37,0x38,0x33,0x35,0x31,0x32,0x31,0x31,0x35,0x34,0x37,0x38,0x35,0x65,0x2d,
0x30,0x37,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x33,0x30,0x39,0x2e,
0x69,0x73,0x5f,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x29,0x29,0x20,
0x2a,0x20,0x5f,0x32,0x37,0x38,0x2e,0x73,0x68,0x69,0x6e,0x69,0x6e,0x65,0x73,0x73,
0x29,0x29,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,
0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,
0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x72,
0x65,0x66,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x72,0x65,0x66,
0x73,0x6d,0x70,0x2c,0x20,0x5f,0x33,0x36,0x37,0x29,0x2e,0x78,0x79,0x7a,0x2c,0x20,
0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x66,0x61,0x73,0x74,0x3a,0x3a,0x6d,0x69,0x6e,
0x28,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x33,0x33,0x35,0x20,0x2a,0x20,0x31,0x2e,0x37,
0x39,0x39,0x39,0x39,0x39,0x39,0x35,0x32,0x33,0x31,0x36,0x32,0x38,0x34,0x31,0x37,
0x39,0x36,0x38,0x37,0x35,0x29,0x29,0x29,0x20,0x2b,0x20,0x28,0x28,0x5f,0x31,0x34,
0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,0x68,0x74,0x43,0x6f,0x6c,0x6f,0x72,0x20,
0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,
0x69,0x74,0x79,0x29,0x20,0x2a,0x20,0x70,0x6f,0x77,0x72,0x28,0x66,0x61,0x73,0x74,
0x3a,0x3a,0x6d,0x61,0x78,0x28,0x30,0x2e,0x30,0x2c,0x20,0x64,0x6f,0x74,0x28,0x66,
0x61,0x73,0x74,0x3a,0x3a,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,
0x32,0x39,0x30,0x20,0x2b,0x20,0x5f,0x32,0x38,0x35,0x29,0x2c,0x20,0x5f,0x32,0x37,
0x34,0x29,0x29,0x2c,0x20,0x33,0x32,0x2e,0x30,0x29,0x29,0x29,0x20,0x2a,0x20,0x31,
0x2e,0x30,0x2c,0x20,0x73,0x6b,0x79,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,0x2c,
0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x32,0x2c,0x20,0x5f,0x31,0x34,0x36,0x29,0x20,
0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x6b,0x79,0x49,0x6e,0x74,0x65,0x6e,0x73,
0x69,0x74,0x79,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x5f,0x34,0x32,0x32,
0x29,0x29,0x2c,0x20,0x6d,0x69,0x78,0x28,0x6d,0x69,0x78,0x28,0x30,0x2e,0x33,0x30,
0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,
0x30,0x37,0x38,0x31,0x32,0x35,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20,0x5f,0x33,0x33,
0x35,0x29,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x34,0x32,0x32,0x29,0x29,0x3b,
0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,0x65,0x6c,0x73,0x65,0x0a,
0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,
0x6f,0x61,0x74,0x32,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x33,0x20,0x3d,0x20,0x28,
0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x20,0x2a,0x20,0x30,0x2e,0x30,0x35,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x37,0x34,0x35,0x30,0x35,0x38,0x30,0x35,0x39,
0x36,0x39,0x32,0x33,0x38,0x32,0x38,0x31,0x32,0x35,0x29,0x20,0x2b,0x20,0x66,0x6c,
0x6f,0x61,0x74,0x32,0x28,0x5f,0x31,0x34,0x36,0x2e,0x74,0x69,0x6d,0x65,0x20,0x2a,
0x20,0x30,0x2e,0x30,0x30,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x37,0x36,0x34,
0x38,0x32,0x35,0x38,0x32,0x30,0x39,0x32,0x32,0x38,0x35,0x31,0x35,0x36,0x32,0x35,
0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x31,0x38,0x20,0x3d,0x20,
0x64,0x6f,0x74,0x28,0x5f,0x32,0x37,0x34,0x2c,0x20,0x5f,0x32,0x39,0x30,0x29,0x20,
0x2b,0x20,0x28,0x28,0x39,0x2e,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,
0x35,0x32,0x34,0x32,0x37,0x30,0x37,0x38,0x37,0x38,0x33,0x35,0x31,0x32,0x31,0x31,
0x35,0x34,0x37,0x38,0x35,0x65,0x2d,0x30,0x37,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,
0x74,0x28,0x5f,0x33,0x30,0x39,0x2e,0x69,0x73,0x5f,0x72,0x65,0x66,0x6c,0x65,0x63,
0x74,0x69,0x6f,0x6e,0x29,0x29,0x20,0x2a,0x20,0x5f,0x32,0x37,0x38,0x2e,0x73,0x68,
0x69,0x6e,0x69,0x6e,0x65,0x73,0x73,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,0x20,
0x5f,0x32,0x38,0x35,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x33,0x35,0x20,0x3d,0x20,0x66,0x61,0x73,
0x74,0x3a,0x3a,0x6d,0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,0x20,0x66,0x72,0x65,0x73,
0x6e,0x65,0x6c,0x53,0x63,0x68,0x6c,0x69,0x63,0x6b,0x28,0x70,0x61,0x72,0x61,0x6d,
0x29,0x2e,0x78,0x20,0x2b,0x20,0x30,0x2e,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x31,
0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,
0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,
0x20,0x5f,0x34,0x35,0x32,0x20,0x3d,0x20,0x66,0x62,0x6d,0x28,0x70,0x61,0x72,0x61,
0x6d,0x5f,0x33,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,
0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x66,
0x6c,0x6f,0x61,0x74,0x34,0x28,0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x5f,0x31,0x34,
0x36,0x2e,0x64,0x65,0x65,0x70,0x43,0x6f,0x6c,0x6f,0x72,0x29,0x20,0x2a,0x20,0x6d,
0x69,0x78,0x28,0x30,0x2e,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x31,0x39,0x32,
0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,0x38,0x31,0x32,0x35,0x2c,0x20,0x31,
0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x34,0x37,0x36,0x38,0x33,0x37,0x31,0x35,
0x38,0x32,0x30,0x33,0x31,0x32,0x35,0x2c,0x20,0x5f,0x34,0x35,0x32,0x29,0x2c,0x20,
0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,
0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00,
0x32,0x20,0x5f,0x33,0x36,0x37,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x46,0x72,0x61,0x67,
0x43,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x20,0x2f,0x20,0x66,0x6c,0x6f,0x61,0x74,
0x32,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,0x37,0x38,0x2e,0x73,0x63,0x72,
0x65,0x65,0x6e,0x5f,0x77,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x32,
0x37,0x38,0x2e,0x73,0x63,0x72,0x65,0x65,0x6e,0x5f,0x68,0x29,0x29,0x3b,0x0a,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x20,0x3d,0x20,
0x31,0x2e,0x30,0x20,0x2d,0x20,0x5f,0x33,0x36,0x37,0x2e,0x79,0x3b,0x0a,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20,0x5f,0x33,0x38,
0x30,0x20,0x3d,0x20,0x72,0x65,0x66,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,
0x65,0x28,0x72,0x65,0x66,0x73,0x6d,0x70,0x2c,0x20,0x5f,0x33,0x36,0x37,0x29,0x2e,
0x78,0x79,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,
0x61,0x74,0x33,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x31,0x20,0x3d,0x20,0x66,0x61,
0x73,0x74,0x3a,0x3a,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x69,0x6e,
0x2e,0x70,0x6f,0x73,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,
0x32,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x5f,0x31,0x34,0x36,0x2e,
0x73,0x75,0x6e,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x3b,0x0a,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,0x32,0x39,
0x20,0x3d,0x20,0x73,0x6d,0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,0x37,0x35,
0x30,0x2e,0x30,0x2c,0x20,0x31,0x30,0x30,0x30,0x2e,0x30,0x2c,0x20,0x6c,0x65,0x6e,
0x67,0x74,0x68,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2e,0x78,0x7a,0x29,0x29,0x3b,
0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,
0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,
0x28,0x6d,0x69,0x78,0x28,0x28,0x28,0x5f,0x33,0x38,0x30,0x20,0x2b,0x20,0x28,0x28,
0x28,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,0x68,0x74,0x43,0x6f,
0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x49,0x6e,
0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x29,0x20,0x2a,0x20,0x70,0x6f,0x77,0x72,0x28,
0x66,0x61,0x73,0x74,0x3a,0x3a,0x6d,0x61,0x78,0x28,0x30,0x2e,0x30,0x2c,0x20,0x64,
0x6f,0x74,0x28,0x66,0x61,0x73,0x74,0x3a,0x3a,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,
0x7a,0x65,0x28,0x5f,0x32,0x39,0x30,0x20,0x2b,0x20,0x5f,0x32,0x38,0x35,0x29,0x2c,
0x20,0x5f,0x32,0x37,0x34,0x29,0x29,0x2c,0x20,0x33,0x32,0x2e,0x30,0x29,0x29,0x20,
0x2a,0x20,0x30,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x39,0x38,0x30,
0x32,0x33,0x32,0x32,0x33,0x38,0x37,0x36,0x39,0x35,0x33,0x31,0x32,0x35,0x29,0x29,
0x20,0x2b,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x5f,0x33,0x31,0x38,0x20,0x2a,
0x20,0x30,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x39,0x38,0x30,0x32,
0x33,0x32,0x32,0x33,0x38,0x37,0x36,0x39,0x35,0x33,0x31,0x32,0x35,0x29,0x29,0x20,
0x2b,0x20,0x28,0x6d,0x69,0x78,0x28,0x28,0x28,0x5f,0x31,0x34,0x36,0x2e,0x77,0x61,
0x74,0x65,0x72,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x2a,0x20,0x5f,0x33,0x31,0x38,0x29,
0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,0x6e,0x4c,0x69,0x67,0x68,0x74,
0x43,0x6f,0x6c,0x6f,0x72,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x75,
0x6e,0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x5f,0x33,0x38,0x30,
0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x28,0x66,0x61,0x73,0x74,0x3a,0x3a,0x6d,
0x69,0x6e,0x28,0x31,0x2e,0x30,0x2c,0x20,0x5f,0x33,0x33,0x35,0x29,0x29,0x29,0x20,
0x2a,0x20,0x39,0x2e,0x39,0x39,0x39,0x39,0x39,0x39,0x37,0x34,0x37,0x33,0x37,0x38,
0x37,0x35,0x31,0x36,0x33,0x35,0x35,0x35,0x31,0x34,0x35,0x32,0x36,0x33,0x36,0x37,
0x31,0x38,0x38,0x65,0x2d,0x30,0x36,0x29,0x2c,0x20,0x73,0x6b,0x79,0x28,0x70,0x61,
0x72,0x61,0x6d,0x5f,0x31,0x2c,0x20,0x70,0x61,0x72,0x61,0x6d,0x5f,0x32,0x2c,0x20,
0x5f,0x31,0x34,0x36,0x29,0x20,0x2a,0x20,0x5f,0x31,0x34,0x36,0x2e,0x73,0x6b,0x79,
0x49,0x6e,0x74,0x65,0x6e,0x73,0x69,0x74,0x79,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,
0x33,0x28,0x5f,0x34,0x32,0x39,0x29,0x29,0x2c,0x20,0x6d,0x69,0x78,0x28,0x6d,0x69,
0x78,0x28,0x30,0x2e,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x35,0x39,0x36,0x30,
0x34,0x36,0x34,0x34,0x37,0x37,0x35,0x33,0x39,0x30,0x36,0x32,0x35,0x2c,0x20,0x31,
0x2e,0x30,0x2c,0x20,0x5f,0x33,0x33,0x35,0x29,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,
0x5f,0x34,0x32,0x39,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,
0x20,0x20,0x65,0x6c,0x73,0x65,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70,0x61,0x72,0x61,
0x6d,0x5f,0x33,0x20,0x3d,0x20,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x2e,0x78,0x7a,
0x20,0x2a,0x20,0x30,0x2e,0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x37,0x34,
0x35,0x30,0x35,0x38,0x30,0x35,0x39,0x36,0x39,0x32,0x33,0x38,0x32,0x38,0x31,0x32,
0x35,0x29,0x20,0x2b,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x5f,0x31,0x34,0x36,
0x2e,0x74,0x69,0x6d,0x65,0x20,0x2a,0x20,0x30,0x2e,0x30,0x30,0x39,0x39,0x39,0x39,
0x39,0x39,0x39,0x37,0x37,0x36,0x34,0x38,0x32,0x35,0x38,0x32,0x30,0x39,0x32,0x32,
0x38,0x35,0x31,0x35,0x36,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x34,0x35,0x39,0x20,0x3d,0x20,0x66,
0x62,0x6d,0x28,0x70,0x61,0x72,0x61,0x6d,0x5f,0x33,0x29,0x3b,0x0a,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,
0x6c,0x6f,0x72,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x66,0x6c,0x6f,
0x61,0x74,0x33,0x28,0x5f,0x31,0x34,0x36,0x2e,0x64,0x65,0x65,0x70,0x43,0x6f,0x6c,
0x6f,0x72,0x29,0x20,0x2a,0x20,0x6d,0x69,0x78,0x28,0x30,0x2e,0x38,0x30,0x30,0x30,
0x30,0x30,0x30,0x31,0x31,0x39,0x32,0x30,0x39,0x32,0x38,0x39,0x35,0x35,0x30,0x37,
0x38,0x31,0x32,0x35,0x2c,0x20,0x31,0x2e,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x34,
0x37,0x36,0x38,0x33,0x37,0x31,0x35,0x38,0x32,0x30,0x33,0x31,0x32,0x35,0x2c,0x20,
0x5f,0x34,0x35,0x39,0x29,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,
0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,
0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00,
];
plane_shader_desc :: (backend: sg_backend) -> sg_shader_desc {
desc: sg_shader_desc;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -138,12 +138,13 @@ void main() {
vec2 screen_uv = gl_FragCoord.xy / vec2(screen_w, screen_h);
screen_uv.y = 1.0 - screen_uv.y;
vec3 reflected_color = texture(sampler2D(reftex, refsmp), screen_uv).rgb;
vec3 surface_color = mix(refracted_color, reflected_color, min(1.0, fresnel * 1.8));
vec3 final_color = (surface_color + specular_highlight) * shadow_factor;
float refraction_alpha = 0.3;
float reflection_alpha = 0.5;
vec3 surface_color = mix(refracted_color, reflected_color, min(1.0, fresnel * 1.0));
vec3 final_color = reflected_color + specular_highlight * 0.2 + diffuse * 0.2 + 0.00001 * surface_color;
// vec3 final_color = (surface_color + specular_highlight) * shadow_factor;
float refraction_alpha = 0.4;
float reflection_alpha = 1.0;
float alpha = mix(refraction_alpha, reflection_alpha, fresnel);
// float alpha = 1.0;
vec3 fog = skyIntensity * sky(normalize(pos.xyz), sunPosition);
float fogFactor = smoothstep(750.0, 1000.0, length(pos.xz));

View File

@ -33,6 +33,7 @@ layout(binding=0) uniform post_process_config {
float film_grain_intensity;
float barrel_distortion_intensity;
int lut_mode;
float dither_intensity;
};
vec3 aces(vec3 x) {
@ -48,6 +49,23 @@ float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
float bayer8(vec2 pos) {
ivec2 p = ivec2(pos) % 8;
int index = p.x + p.y * 8;
// Bayer 8x8 matrix, normalized to [0,1]
const int bayer[64] = int[64](
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
);
return (float(bayer[index]) / 64.0) - 0.5;
}
void main() {
vec2 distorted_texcoord = texcoord;
float barrel_dist = length(texcoord - 0.5);
@ -84,7 +102,12 @@ void main() {
color_ldr_linear = mix(brtColor, color_ldr_linear, saturation);
color_ldr_linear = clamp(color_ldr_linear, 0.0, 1.0);
if(dither_intensity > 0.0) {
float dither = bayer8(gl_FragCoord.xy) * dither_intensity * (1.0 / 15.0);
color_ldr_linear = clamp(color_ldr_linear + dither, 0.0, 1.0);
}
if(lut_mode != 0) {
if(lut_mode == 2) {
float u = floor(color_ldr_linear.b * 15.0) * (1.0/16.0);

View File

@ -16,16 +16,18 @@ out vec3 to_center;
out vec3 vpos; // The actual position;
out vec3 ipos; // Trile space position;
out vec4 fnormal;
out vec4 light_proj_pos;
out vec3 trileCenter;
out vec3 cv;
void main() {
gl_Position = mvp * vec4(position.xyz + instance.xyz, 1.0);
light_proj_pos = mvp_shadow * vec4(position.xyz + instance.xyz, 1.0);
fnormal = normal;
to_center = centre.xyz - position.xyz;
vpos = position.xyz + instance.xyz;
ipos = position.xyz;
cam = camera;
cv = normalize(camera - vpos);
trileCenter = vpos - ipos + vec3(0.5);
}
@end
@ -57,7 +59,8 @@ in vec3 to_center;
in vec3 vpos;
in vec3 ipos;
in vec4 fnormal;
in vec4 light_proj_pos;
in vec3 trileCenter;
in vec3 cv;
out vec4 frag_color;
layout(binding=3) uniform trile_fs_params {
@ -73,6 +76,10 @@ layout(binding = 1) uniform texture2D ssaotex;
layout(binding = 1) uniform sampler ssaosmp;
layout(binding = 2) uniform texture2D shadowtex;
layout(binding = 2) uniform sampler shadowsmp;
layout(binding = 3) uniform texture2D rdm_lookup;
layout(binding = 4) uniform texture2D rdm_atlas;
layout(binding = 5) uniform texture2D brdf_lut;
layout(binding = 3) uniform sampler rdmsmp;
const float PI = 3.1412854;
@ -150,7 +157,7 @@ vec3 sky(vec3 skypos, vec3 sunpos) {
final = vec3(final);
// Cirrus Clouds
if(hasClouds == 1) {
if(hasClouds == 1) {
float density = smoothstep(1.0 - cirrus, 1.0, fbm(npos.xyz / npos.y * 2.0 + time * 0.05)) * 0.3;
final.rgb = mix(final.rgb, vec3(1.0, 1.0, 1.0), max(0.0, npos.y) * density * 2.0);
}
@ -160,6 +167,8 @@ vec3 sky(vec3 skypos, vec3 sunpos) {
// ---- SKY END ----
// ---- PBR FUNCTIONS ----
float DistributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness*roughness;
float a2 = a*a;
@ -187,16 +196,250 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
return ggx1 * ggx2;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
// ---- RDM FUNCTIONS ----
float roughness_to_rdm_size(int roughness) {
return pow(2.0, float((7 - roughness) + 1));
}
int rdm_index_from_normal(vec3 N) {
vec3 n_leftright = vec3(0.0, 0.0, 1.0);
vec3 n_updown = vec3(0.0, 1.0, 0.0);
vec3 n_frontback = vec3(1.0, 0.0, 0.0);
int res = 0;
// res += int(dot(n_updown, N) >= 0.98) * 0; unnecessary
res += int(dot(-n_updown, N) >= 0.98) * 1;
res += int(dot(n_leftright, N) >= 0.98) * 2;
res += int(dot(-n_leftright, N) >= 0.98) * 3;
res += int(dot(n_frontback, N) >= 0.98) * 4;
res += int(dot(-n_frontback, N) >= 0.98) * 5;
return res;
}
// Taken from Cigolle2014Vector.pdf
vec2 rdm_get_hemioct(vec3 v, int index, vec2 off) {
vec3 vc = v;
if(index / 2 == 0) {
vc.z = v.y;
vc.y = v.z;
}
if(index / 2 == 2) {
vc.z = v.x;
vc.x = v.z;
}
if(index % 2 == 1) {
vc.z *= -1.0;
}
vc.x += off.x;
vc.y += off.y;
normalize(vc);
vec2 p = vc.xy * (1.0 / (abs(vc.x) + abs(vc.y) + vc.z));
// Rotate and scale the center diamond to the unit square
vec2 res = vec2(p.x + p.y, p.x - p.y);
res.x = (res.x + 1.0) * 0.5;
res.y = (res.y + 1.0) * 0.5;
// res.y = clamp(res.y, 0.0, 1.0);
// res.x = clamp(res.x, 0.0, 1.0);
return res;
}
float rdm_offset_y(int index) {
return float((index / 2)) * (1.0/3.0);
}
float rdm_offset_x(int index) {
return float((index % 2)) * (1.0/2.0);
}
// Look up atlas rect from the lookup texture for a given chunk-local position and roughness.
// Returns atlas_rect: xy = UV offset, zw = UV size. z > 0 means valid.
vec4 rdm_get_atlas_rect(ivec3 local_pos, int roughness) {
int rdm_index = local_pos.x + local_pos.y * 32 + local_pos.z * 1024 + roughness * 32768;
int tx = rdm_index % 512;
int ty = rdm_index / 512;
return texelFetch(sampler2D(rdm_lookup, trilesmp), ivec2(tx, ty), 0);
}
// Compute pixel offset in the atlas for a given face within an atlas rect.
// Returns ivec2(ox, oy) — the top-left pixel of this face's sub-image.
ivec2 rdm_face_pixel_offset(vec4 atlas_rect, int face, int rdmSize) {
ivec2 atlasSize = textureSize(sampler2D(rdm_atlas, rdmsmp), 0);
int col = face % 2;
int row = face / 2;
int ox = int(atlas_rect.x * float(atlasSize.x)) + col * rdmSize;
int oy = int(atlas_rect.y * float(atlasSize.y)) + row * rdmSize;
return ivec2(ox, oy);
}
vec3 sample_rdm(vec3 N, vec3 V, vec3 rdm_center, vec3 diff, int roughness, ivec3 local_pos) {
int face = rdm_index_from_normal(N);
int rdmSizeInt = int(roughness_to_rdm_size(roughness));
float rdmSize = float(rdmSizeInt);
vec4 atlas_rect = rdm_get_atlas_rect(local_pos, roughness);
if (atlas_rect.z <= 0.0) return vec3(1.0, 0.0, 1.0); // No data - magenta
ivec2 faceOffset = rdm_face_pixel_offset(atlas_rect, face, rdmSizeInt);
// Get 2D UV on this face from the fragment's trile-space position
vec2 uv;
if (face == 0 || face == 1) { // +Y / -Y
uv = vec2(ipos.x, ipos.z);
} else if (face == 2 || face == 3) { // +Z / -Z
uv = vec2(ipos.x, ipos.y);
} else { // +X / -X
uv = vec2(ipos.z, ipos.y);
}
// Step 1: flat UV sampling (known working)
// ivec2 texCoord = ivec2(faceOffset.x + int(uv.x * rdmSize),
// faceOffset.y + int(uv.y * rdmSize));
// vec4 rdmSample = texelFetch(sampler2D(rdm_atlas, rdmsmp), texCoord, 0);
// return vec3(rdmSample.a * 0.2);
vec3 reflected = normalize(reflect(V, N));
if (roughness > 1) {
// Low-res mips: sample at fixed distance with bilinear filtering
vec3 samplePos = normalize(diff + 2.0 * reflected);
vec2 hemiUV = rdm_get_hemioct(samplePos, face, vec2(0.0));
vec2 atlasSize = vec2(textureSize(sampler2D(rdm_atlas, rdmsmp), 0));
vec2 texUV = (vec2(faceOffset) + hemiUV * rdmSize) / atlasSize;
return texture(sampler2D(rdm_atlas, rdmsmp), texUV).rgb;
}
// High-res: ray march with depth comparison
float maxDist = 20.0;
int steps = 40;
for (int i = 0; i < steps; i++) {
float t = maxDist * float(i + 1) / float(steps);
vec3 samplePos = diff + t * reflected;
if (dot(samplePos, N) < 0.0) continue;
vec2 hemiUV = rdm_get_hemioct(normalize(samplePos), face, vec2(0.0));
ivec2 texCoord = ivec2(faceOffset.x + int(hemiUV.x * rdmSize),
faceOffset.y + int(hemiUV.y * rdmSize));
vec4 rdmSample = texelFetch(sampler2D(rdm_atlas, rdmsmp), texCoord, 0);
float depth = rdmSample.a;
float dist = length(samplePos);
float stepSize = maxDist / float(steps);
if (depth > 0.0 && depth < dist && depth + stepSize > dist) {
return rdmSample.rgb;
}
}
vec3 skyDir = reflected;
if (skyDir.y < 0.0) skyDir = reflect(skyDir, vec3(0.0, 1.0, 0.0));
return sky(skyDir, sunPosition);
}
// Sample diffuse irradiance from a single probe (roughness=7 RDM face)
vec3 sample_rdm_diff_map(vec3 N, ivec3 local_pos, vec3 fallback) {
vec4 atlas_rect = rdm_get_atlas_rect(local_pos, 7);
if (atlas_rect.z <= 0.0) return fallback;
int face = rdm_index_from_normal(N);
int rdmSize = int(roughness_to_rdm_size(7));
ivec2 faceOffset = rdm_face_pixel_offset(atlas_rect, face, rdmSize);
vec2 pos = rdm_get_hemioct(N, face, vec2(0.0));
ivec2 texCoord = ivec2(faceOffset.x + int(pos.x * float(rdmSize)),
faceOffset.y + int(pos.y * float(rdmSize)));
return texelFetch(sampler2D(rdm_atlas, rdmsmp), texCoord, 0).rgb;
}
int isign(float f) {
return f < 0.0 ? -1 : 1;
}
vec3 smix(vec3 a, vec3 b, float t) {
float power = 1.6;
float smoothT = pow(t, power) / (pow(t, power) + pow(1.0 - t, power));
return mix(a, b, smoothT);
}
// Interpolated diffuse irradiance from 4 nearest neighbor probes
vec3 sample_rdm_diff(vec3 N, vec3 diff, ivec3 local_pos) {
int face = rdm_index_from_normal(N);
vec3 ambientPlaceholder = vec3(0.3, 0.3, 0.4);
// Determine the 2D delta in the face plane
vec2 delta = vec2(0.0);
if (face == 0 || face == 1) {
delta = vec2(diff.x, diff.z);
} else if (face == 2 || face == 3) {
delta = vec2(diff.x, diff.y);
} else {
delta = vec2(diff.z, diff.y);
}
// Compute neighbor offsets in 3D
ivec3 s0 = ivec3(0, 0, 0);
ivec3 s1, s2, s3;
if (face == 0 || face == 1) {
s1 = ivec3(isign(delta.x), 0, 0);
s2 = ivec3(0, 0, isign(delta.y));
s3 = ivec3(isign(delta.x), 0, isign(delta.y));
} else if (face == 2 || face == 3) {
s1 = ivec3(isign(delta.x), 0, 0);
s2 = ivec3(0, isign(delta.y), 0);
s3 = ivec3(isign(delta.x), isign(delta.y), 0);
} else {
s1 = ivec3(0, 0, isign(delta.x));
s2 = ivec3(0, isign(delta.y), 0);
s3 = ivec3(0, isign(delta.y), isign(delta.x));
}
// // Swizzle offsets based on face orientation
// if (face == 2 || face == 3) {
// int temp;
// temp = s1.y; s1.y = s1.z; s1.z = temp;
// temp = s2.y; s2.y = s2.z; s2.z = temp;
// temp = s3.y; s3.y = s3.z; s3.z = temp;
// }
// if (face == 4 || face == 5) {
// int temp;
// temp = s1.y; s1.y = s1.x; s1.x = temp;
// temp = s2.y; s2.y = s2.x; s2.x = temp;
// temp = s3.y; s3.y = s3.x; s3.x = temp;
// }
// Sample the four nearest probes using offset local positions
vec3 p0 = sample_rdm_diff_map(N, ivec3(mod(vec3(local_pos + s0), 32.0)), ambientPlaceholder);
vec3 p1 = sample_rdm_diff_map(N, ivec3(mod(vec3(local_pos + s1), 32.0)), ambientPlaceholder);
vec3 p2 = sample_rdm_diff_map(N, ivec3(mod(vec3(local_pos + s2), 32.0)), ambientPlaceholder);
vec3 p3 = sample_rdm_diff_map(N, ivec3(mod(vec3(local_pos + s3), 32.0)), ambientPlaceholder);
// Bilinear blend with smooth interpolation
return smix(
smix(p0, p1, abs(delta.x)),
smix(p2, p3, abs(delta.x)),
abs(delta.y)
);
}
void main() {
if (vpos.y < planeHeight - 0.01 && is_reflection == 1) {
discard;
}
//frag_color = vec4((fnormal.xyz + vec3(1.0, 1.0, 1.0)) * 0.5, 1.0);
// Trixel material sampling
vec3 pos_after_adjust = ipos - fnormal.xyz * 0.02;
int count = 0;
vec4 trixel_material;
@ -206,58 +449,89 @@ void main() {
int zpos = int(clamp(pos_after_adjust.x, 0.0001, 0.99999) * 16.0);
trixel_material = texelFetch(sampler2D(triletex, trilesmp), ivec2(xpos, ypos + zpos * 16), 0);
if (length(trixel_material) > 0.01) break; // @ToDo: Replace with proper null trixel check.
if (length(trixel_material) > 0.01) break;
pos_after_adjust += to_center * 0.1;
count++;
}
vec3 albedo = trixel_material.xyz;
int packedMaterial = int(round(trixel_material.w*255.0));
int packedMaterial = int(round(trixel_material.w * 255.0));
float emittance = float((packedMaterial >> 1) & 0x3) / 3.0;
int roughnessInt = (packedMaterial >> 5) & 0x7;
float roughness = max(float(roughnessInt) / 7.0, 0.05);
float metallic = float((packedMaterial >> 3) & 0x3) / 3.0;
// Ambient light.
float ssao_sample = texture(sampler2D(ssaotex, trilesmp), vec2(gl_FragCoord.x/screen_w, gl_FragCoord.y/screen_h), 0).r;
vec3 light = 0.35 * albedo * ssao_sample;
vec3 N = normalize(fnormal.xyz);
// Snap normal to nearest axis to avoid interpolation noise
vec3 absN = abs(fnormal.xyz);
vec3 N;
if (absN.x >= absN.y && absN.x >= absN.z) {
N = vec3(sign(fnormal.x), 0.0, 0.0);
} else if (absN.y >= absN.x && absN.y >= absN.z) {
N = vec3(0.0, sign(fnormal.y), 0.0);
} else {
N = vec3(0.0, 0.0, sign(fnormal.z));
}
vec3 V = normalize(cam - vpos.xyz);
vec3 L = normalize(sunPosition);
vec3 H = normalize(V + L);
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
vec3 F = fresnelSchlick(max(dot(H,V), 0.0), F0);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
float NdotL = max(dot(N, L), 0.0);
vec3 kD = vec3(1.0) - F;
kD *= 1.0 - metallic;
// Shadow
vec4 light_proj_pos = mvp_shadow * vec4(floor(vpos.xyz * 16.0) / 16.0, 1.0);
vec3 light_pos = light_proj_pos.xyz / light_proj_pos.w;
light_pos = light_pos * 0.5 + 0.5;
light_pos.z -= 0.0009;
light_pos.z -= 0.001;
float shadowp = texture(sampler2DShadow(shadowtex, shadowsmp), light_pos);
light += shadowp * (kD * albedo / PI + specular) * NdotL * sunLightColor * sunIntensity;
vec3 R = reflect(-V, N);
vec3 modifier = vec3(1.0);
if(R.y < 0.0) {
R = reflect(R, vec3(0.0,1.0,0.0));
modifier = vec3(0.7, 0.9, 0.7);
// Direct lighting
// vec3 light = shadowp * (kD * albedo / PI + specular) * NdotL * sunLightColor * sunIntensity;
vec3 light = vec3(0.0);
// RDM indirect lighting
// vec3 trileCenter = floor(vpos - ipos) + vec3(0.5);
vec3 hemispherePos = trileCenter + N * 0.49;
ivec3 local = ivec3(mod(floor(trileCenter), 32.0));
vec4 atlas_rect_check = rdm_get_atlas_rect(local, roughnessInt);
if (true) {
vec3 indirectSpec = sample_rdm(N, -cv,
hemispherePos, vpos - hemispherePos, roughnessInt, local);
vec3 Frough = FresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness);
vec2 envBRDF = texture(sampler2D(brdf_lut, rdmsmp), vec2(max(dot(N, V), 0.0), roughness)).rg;
// light += indirectSpec * (Frough * envBRDF.x + envBRDF.y);
light += indirectSpec;
// Indirect diffuse (interpolated from neighbor probes)
vec3 indirectDiff = sample_rdm_diff(N, vpos - hemispherePos, local);
vec3 kS = fresnelSchlick(max(dot(N, V), 0.0), F0);
vec3 kDiff = 1.0 - Frough;
kDiff *= 1.0 - metallic;
float ssao_sample = texture(sampler2D(ssaotex, trilesmp), vec2(gl_FragCoord.x / float(screen_w), gl_FragCoord.y / float(screen_h)), 0).r;
// light += (kDiff * indirectDiff / PI * albedo) * ssao_sample;
// light += indirectDiff * albedo;
} else {
float ssao_sample = texture(sampler2D(ssaotex, trilesmp), vec2(gl_FragCoord.x / float(screen_w), gl_FragCoord.y / float(screen_h)), 0).r;
// Fallback: ambient + sky reflection when no RDM data
light += 0.35 * albedo * ssao_sample;
vec3 R = reflect(-V, N);
if (R.y < 0.0) R = reflect(R, vec3(0.0, 1.0, 0.0));
light += F * sky(R, sunPosition) * 0.1;
}
vec3 samp = sky(R, sunPosition);
// light += F * samp * modifier;
frag_color = vec4(mix(deepColor, light, smoothstep(0.0, planeHeight, vpos.y)), 1.0);
}
@end

View File

@ -88,7 +88,7 @@ striles :: () {
#if OS != .WASM {
file :: #import "File";
json := Jaison.json_write_string(triles, " ");
file.write_entire_file("./game/resources/triles.json", json);
file.write_entire_file("./game/resources/game_core/triles.json", json);
}
} @Command

View File

@ -419,7 +419,7 @@ render_ui :: () {
my_theme := proc();
GR.set_default_theme(my_theme);
draw_editor_ui(*my_theme);
game_ui(*my_theme);
if !in_editor_view then game_ui(*my_theme);
}
ui_pass :: () {

View File

@ -2,66 +2,415 @@
Pool :: #import "Pool";
CHUNK_SIZE :: 32;
Current_World :: struct {
world : *World;
world : World;
pool : Pool.Pool; // A memory pool to allocate stuff for the lifetime of this level being active. For example RDMs.
valid : bool = false;
};
current_world : Current_World;
world_table : Table(string, World);
#scope_export
Chunk_Key :: struct {
x: s32;
y: s32;
z: s32;
}
operator == :: (a: Chunk_Key, b: Chunk_Key) -> bool {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
chunk_key_hash :: (key: Chunk_Key) -> u32 {
h := cast(u32) 2166136261;
h = (h ^ (cast,no_check(u32) key.x)) * 16777619;
h = (h ^ (cast,no_check(u32) key.y)) * 16777619;
h = (h ^ (cast,no_check(u32) key.z)) * 16777619;
return h;
}
chunk_key_compare :: (a: Chunk_Key, b: Chunk_Key) -> bool {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
Trile_Instance :: struct {
x: u8; // local position within chunk (0..31)
y: u8;
z: u8;
orientation: u8; // 0..23, index into cube rotation group
}
Chunk_Trile_Group :: struct {
trile_name: string;
instances: [..]Trile_Instance;
}
Chunk :: struct {
coord: Chunk_Key;
groups: [..]Chunk_Trile_Group;
// RDM bake results (populated by tacoma baking)
rdm_atlas: sg_image;
rdm_lookup: sg_image;
rdm_valid: bool;
}
World :: struct {
name : string;
conf : World_Config;
chunks : Table(Chunk_Key, Chunk, chunk_key_hash, chunk_key_compare);
}
// Convert a world-space integer position to chunk coordinate.
world_to_chunk_coord :: (wx: s32, wy: s32, wz: s32) -> Chunk_Key {
return .{
x = floor_div(wx, CHUNK_SIZE),
y = floor_div(wy, CHUNK_SIZE),
z = floor_div(wz, CHUNK_SIZE),
};
}
// Convert a world-space integer position to local position within its chunk (0..31).
world_to_local :: (wx: s32, wy: s32, wz: s32) -> (u8, u8, u8) {
return cast(u8) floor_mod(wx, CHUNK_SIZE),
cast(u8) floor_mod(wy, CHUNK_SIZE),
cast(u8) floor_mod(wz, CHUNK_SIZE);
}
// Convert chunk coord + local position back to world position.
chunk_local_to_world :: (chunk: Chunk_Key, lx: u8, ly: u8, lz: u8) -> (s32, s32, s32) {
return chunk.x * CHUNK_SIZE + cast(s32) lx,
chunk.y * CHUNK_SIZE + cast(s32) ly,
chunk.z * CHUNK_SIZE + cast(s32) lz;
}
// Floor division that handles negatives correctly (rounds toward -infinity).
floor_div :: (a: s32, b: s32) -> s32 {
d := a / b;
r := a % b;
if (r != 0) && ((r ^ b) < 0) then d -= 1;
return d;
}
// Floor modulo that always returns a non-negative result.
floor_mod :: (a: s32, b: s32) -> s32 {
r := a % b;
if (r != 0) && ((r ^ b) < 0) then r += b;
return r;
}
nworld :: (name: string) {
w : World;
w.name = sprint("%", name);
table_set(*world_table, w.name, w);
unload_current_world();
current_world.world = .{};
current_world.world.name = sprint("%", name);
current_world.valid = true;
} @Command;
lworld :: (name: string) {
load_world(name);
} @Command;
unload_current_world :: () {
if current_world.valid {
// Free chunk data.
for *chunk: current_world.world.chunks {
for *group: chunk.groups {
array_free(group.instances);
}
array_free(chunk.groups);
}
deinit(*current_world.world.chunks);
Pool.reset(*current_world.pool);
current_world.valid = false;
} else {
Pool.set_allocators(*current_world.pool);
}
}
worldptr := table_find_pointer(*world_table, name);
if !worldptr {
print("Did not find world: %...\n", name);
return;
}
current_world.world = worldptr;
set_loaded_world :: (world: World) {
unload_current_world();
current_world.world = world;
current_world.valid = true;
} @Command;
#if HAS_TACOMA { rdm_load_from_disk(); }
}
clear_world :: () {
if !current_world.valid then return;
for *chunk: current_world.world.chunks {
for *group: chunk.groups {
array_free(group.instances);
}
array_free(chunk.groups);
}
deinit(*current_world.world.chunks);
current_world.world.chunks = .{};
} @Command
get_current_world :: () -> *Current_World {
return *current_world;
}
sworlds :: () {
worlds : [..]World_Serialized;
worlds.allocator = temp;
for v : world_table {
array_add(*worlds, serialize_world(*v,, temp));
// --- Binary serialization (.world format) ---
WORLD_MAGIC :: u32.[0x4C575254][0]; // "TRWL" as little-endian u32
WORLD_VERSION :: cast(u16) 1;
// World_Config serialized as a fixed-size binary blob.
// We serialize it field-by-field to avoid padding issues.
World_Config_Binary :: struct {
sky_base: [3]float;
sky_top: [3]float;
sun_disk: [3]float;
horizon_halo: [3]float;
sun_halo: [3]float;
sun_light_color: [3]float;
sun_position: [3]float;
sun_intensity: float;
sky_intensity: float;
has_clouds: s32;
plane_height: float;
plane_type: s32;
water_color: [3]float;
deep_color: [3]float;
}
world_config_to_binary :: (conf: *World_Config) -> World_Config_Binary {
b: World_Config_Binary;
b.sky_base = conf.skyBase.component;
b.sky_top = conf.skyTop.component;
b.sun_disk = conf.sunDisk.component;
b.horizon_halo = conf.horizonHalo.component;
b.sun_halo = conf.sunHalo.component;
b.sun_light_color = conf.sunLightColor.component;
b.sun_position = conf.sunPosition.component;
b.sun_intensity = conf.sunIntensity;
b.sky_intensity = conf.skyIntensity;
b.has_clouds = conf.hasClouds;
b.plane_height = conf.planeHeight;
b.plane_type = conf.planeType;
b.water_color = conf.waterColor.component;
b.deep_color = conf.deepColor.component;
return b;
}
world_config_from_binary :: (b: *World_Config_Binary) -> World_Config {
conf: World_Config;
conf.skyBase.component = b.sky_base;
conf.skyTop.component = b.sky_top;
conf.sunDisk.component = b.sun_disk;
conf.horizonHalo.component = b.horizon_halo;
conf.sunHalo.component = b.sun_halo;
conf.sunLightColor.component = b.sun_light_color;
conf.sunPosition.component = b.sun_position;
conf.sunIntensity = b.sun_intensity;
conf.skyIntensity = b.sky_intensity;
conf.hasClouds = b.has_clouds;
conf.planeHeight = b.plane_height;
conf.planeType = b.plane_type;
conf.waterColor.component = b.water_color;
conf.deepColor.component = b.deep_color;
return conf;
}
write_bytes :: (builder: *String_Builder, data: *void, count: s64) {
s: string;
s.data = data;
s.count = count;
append(builder, s);
}
write_value :: (builder: *String_Builder, value: $T) {
v := value;
write_bytes(builder, *v, size_of(T));
}
read_value :: (data: []u8, cursor: *s64, $T: Type) -> T {
result: T;
assert(cursor.* + size_of(T) <= data.count, "read_value: out of bounds");
memcpy(*result, data.data + cursor.*, size_of(T));
cursor.* += size_of(T);
return result;
}
read_string :: (data: []u8, cursor: *s64, len: s64) -> string {
assert(cursor.* + len <= data.count, "read_string: out of bounds");
result := sprint("%", string.{count = len, data = data.data + cursor.*});
cursor.* += len;
return result;
}
sworld :: () {
if !current_world.valid {
print("Cannot save: no world loaded\n");
return;
}
#if OS != .WASM {
file :: #import "File";
json := Jaison.json_write_string(worlds, " ");
file.write_entire_file("./game/resources/worlds.json", json); // @ToDo: it's quite likely that at some point having all of the worlds in one file will not be ok.
name := current_world.world.name;
dir := tprint("./game/resources/worlds/%", name);
file.make_directory_if_it_does_not_exist(dir, recursive = true);
data := save_world(*current_world.world);
file.write_entire_file(tprint("%/index.world", dir), data);
print("Saved world '%' (% bytes)\n", name, data.count);
}
} @Command
lworlds :: () {
s := load_string_from_pack("game_core", "worlds.json");
success, worlds := Jaison.json_parse_string(s, [..]World_Serialized,, temp);
for worlds {
w : World;
deserialize_world(*it, *w);
table_set(*world_table, w.name, w);
print("Loaded world: %\n", w.name);
save_world :: (world: *World) -> string {
builder: String_Builder;
// Header
write_value(*builder, WORLD_MAGIC);
write_value(*builder, WORLD_VERSION);
name_len := cast(u16) world.name.count;
write_value(*builder, name_len);
append(*builder, world.name);
// World config
conf_bin := world_config_to_binary(*world.conf);
write_value(*builder, conf_bin);
// Count non-empty chunks
num_chunks: u32 = 0;
for world.chunks {
if it.groups.count > 0 then num_chunks += 1;
}
} @Command
write_value(*builder, num_chunks);
// We need to write chunk table, then chunk data.
// First pass: serialize all chunk data to get sizes.
Chunk_Data_Entry :: struct {
coord: Chunk_Key;
data: string;
}
chunk_entries: [..]Chunk_Data_Entry;
chunk_entries.allocator = temp;
for chunk: world.chunks {
if chunk.groups.count == 0 then continue;
chunk_builder: String_Builder;
chunk_builder.allocator = temp;
num_types := cast(u16) chunk.groups.count;
write_value(*chunk_builder, num_types);
for group: chunk.groups {
gname_len := cast(u16) group.trile_name.count;
write_value(*chunk_builder, gname_len);
append(*chunk_builder, group.trile_name);
count := cast(u16) group.instances.count;
write_value(*chunk_builder, count);
for inst: group.instances {
write_value(*chunk_builder, inst);
}
}
array_add(*chunk_entries, .{coord = chunk.coord, data = builder_to_string(*chunk_builder,, temp)});
}
// Calculate data offsets.
// Chunk table starts right after what we've written so far.
// header_size = current builder length + chunk_table_size
current_header_size := builder_string_length(*builder);
chunk_table_entry_size : s64 = size_of(s32)*3 + size_of(u32)*2; // chunk_x, chunk_y, chunk_z, data_offset, data_size
chunk_table_size := cast(s64) num_chunks * chunk_table_entry_size;
data_start := current_header_size + chunk_table_size;
// Write chunk table
running_offset := cast(u32) data_start;
for entry: chunk_entries {
write_value(*builder, entry.coord.x);
write_value(*builder, entry.coord.y);
write_value(*builder, entry.coord.z);
write_value(*builder, running_offset);
data_size := cast(u32) entry.data.count;
write_value(*builder, data_size);
running_offset += data_size;
}
// Write chunk data
for entry: chunk_entries {
append(*builder, entry.data);
}
return builder_to_string(*builder);
}
load_world_from_data :: (data: []u8) -> (World, bool) {
world: World;
cursor: s64 = 0;
if data.count < size_of(u32) + size_of(u16) {
print("World file too small\n");
return world, false;
}
// Header
magic := read_value(data, *cursor, u32);
if magic != WORLD_MAGIC {
print("Invalid world file magic\n");
return world, false;
}
version := read_value(data, *cursor, u16);
if version != WORLD_VERSION {
print("Unsupported world version: %\n", version);
return world, false;
}
name_len := cast(s64) read_value(data, *cursor, u16);
world.name = read_string(data, *cursor, name_len);
// World config
conf_bin := read_value(data, *cursor, World_Config_Binary);
world.conf = world_config_from_binary(*conf_bin);
num_chunks := read_value(data, *cursor, u32);
// Read chunk table
Chunk_Table_Entry :: struct {
coord: Chunk_Key;
offset: u32;
size: u32;
}
chunk_table: [..]Chunk_Table_Entry;
chunk_table.allocator = temp;
for i: 0..cast(s64)num_chunks-1 {
entry: Chunk_Table_Entry;
entry.coord.x = read_value(data, *cursor, s32);
entry.coord.y = read_value(data, *cursor, s32);
entry.coord.z = read_value(data, *cursor, s32);
entry.offset = read_value(data, *cursor, u32);
entry.size = read_value(data, *cursor, u32);
array_add(*chunk_table, entry);
}
// Read chunk data
for entry: chunk_table {
chunk_cursor: s64 = cast(s64) entry.offset;
chunk: Chunk;
chunk.coord = entry.coord;
num_types := read_value(data, *chunk_cursor, u16);
for t: 0..cast(s64)num_types-1 {
group: Chunk_Trile_Group;
gname_len := cast(s64) read_value(data, *chunk_cursor, u16);
group.trile_name = read_string(data, *chunk_cursor, gname_len);
count := cast(s64) read_value(data, *chunk_cursor, u16);
for i: 0..count-1 {
inst := read_value(data, *chunk_cursor, Trile_Instance);
array_add(*group.instances, inst);
}
array_add(*chunk.groups, group);
}
table_set(*world.chunks, chunk.coord, chunk);
}
return world, true;
}
World_Config :: struct {
// All of the @Notes are for the autoedit functionality.
@ -80,8 +429,8 @@ World_Config :: struct {
planeHeight : float = 0.0; @Slider,0,3,0.1
planeType : s32 = 1; @Slider,0,1,1
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.
deepColor : Vector3 = .{1.0, 1.0, 1.0}; @Color // @ToDo: sensible default values.
// ambientColor : Vector3 = .{1.0, 1.0, 1.0}; @Color
// ambientIntensity : float = 0.3; @Slider,0,3,0.1
@ -103,76 +452,42 @@ world_config_to_shader_type :: (wc: *World_Config, data: *$T) {
#insert #run,stallable generate_copy_code();
}
TrilePositions :: struct {
trileName: string;
positions: [..]Vector4;
}
World :: struct {
name : string;
conf : World_Config;
positions : [..]TrilePositions;
}
Trile_Positions_Serialized :: struct {
trileName : string;
positions : [..]float;
}
World_Serialized :: struct {
name : string;
conf : World_Config;
positions : [..]Trile_Positions_Serialized;
}
// You should call this function with the temp allocator as context allocator.
serialize_world :: (world: *World) -> World_Serialized {
ws : World_Serialized;
ws.name = world.name;
ws.conf = world.conf;
for world.positions {
tsp : Trile_Positions_Serialized;
tsp.trileName = it.trileName;
for v: it.positions {
array_add(*tsp.positions, v.x);
array_add(*tsp.positions, v.y);
array_add(*tsp.positions, v.z);
array_add(*tsp.positions, v.w);
}
array_add(*ws.positions, tsp);
}
return ws;
}
deserialize_world :: (ws: *World_Serialized, world: *World) {
world.name = sprint("%", ws.name); // It's important that we re-store everything since the serialization is going to temp and gets freed.
world.conf = ws.conf;
for ws.positions {
tp : TrilePositions;
tp.trileName = sprint("%", it.trileName);
for i : 0..it.positions.count/4-1 {
v: Vector4;
v.x = it.positions[i*4+0];
v.y = it.positions[i*4+1];
v.z = it.positions[i*4+2];
v.w = it.positions[i*4+3];
array_add(*tp.positions, v);
}
array_add(*world.positions, tp);
}
}
draw_world_picker :: (r_in: GR.Rect, theme: *GR.Overall_Theme) {
r := r_in;
r.h = ui_h(4,4);
count := 0;
for v : world_table {
if GR.button(r, v.name, *t_button_selectable(theme, current_world.valid && current_world.world.name == v.name), count) {
lworld(v.name);
#if OS != .WASM {
File_Utilities :: #import "File_Utilities";
world_names: [..]string;
world_names.allocator = temp;
dir_visitor :: (info: *File_Utilities.File_Visit_Info, names: *[..]string) {
if info.short_name == "index.world" {
// Extract world name from path: .../worlds/{name}/index.world
#import "String";
_, left, _ := split_from_right(info.full_name, "/index.world");
_, _, name := split_from_right(left, "/");
if name.count > 0 then array_add(names, name);
}
}
File_Utilities.visit_files("./game/resources/worlds", true, *world_names, dir_visitor);
count := 0;
for name: world_names {
is_current := current_world.valid && current_world.world.name == name;
if GR.button(r, name, *t_button_selectable(theme, is_current), count) {
lworld(name);
}
count += 1;
r.y += r.h;
}
} else {
if current_world.valid {
GR.label(r, tprint("Current: %", current_world.world.name), *theme.label_theme);
} else {
GR.label(r, "No world loaded", *theme.label_theme);
}
count += 1;
r.y += r.h;
}
}