Compare commits

...

5 Commits

Author SHA1 Message Date
28a4c44478 add configuration for settings menu 2026-09-29 21:02:42 +03:00
0d44c75fa9 world fixes and water improvements 2026-09-29 21:02:08 +03:00
279b7ca81d fix bounds bug 2026-09-29 21:01:02 +03:00
c1bba2ee48 Add ogg_vorbis loading from packs 2026-09-29 21:00:52 +03:00
e8f6dad025 add stb_vorbis 2026-09-29 20:55:49 +03:00
34 changed files with 12781 additions and 854 deletions

View File

@ -238,6 +238,7 @@ wasm_build :: (opts: Build_Options, trueno_opts: Trueno_Build_Options) {
"emcc", "emcc",
"src/platform_specific/main.c", "dist/main.o", "modules/sokol-jai/sokol/gfx/sokol_gfx_wasm_gl_release.a", "modules/sokol-jai/sokol/log/sokol_log_wasm_gl_release.a", "modules/sokol-jai/sokol/audio/sokol_audio_wasm_gl_release.a", "modules/sokol-jai/sokol/time/sokol_time_wasm_gl_release.a", "modules/sokol-jai/sokol/app/sokol_app_wasm_gl_release.a", "modules/sokol-jai/sokol/glue/sokol_glue_wasm_gl_release.a", "modules/sokol-jai/sokol/fetch/sokol_fetch_wasm_gl_release.a", "modules/sokol-jai/sokol/gl/sokol_gl_wasm_gl_release.a", "modules/sokol-jai/sokol/fontstash/sokol_fontstash_wasm_gl_release.a", "src/platform_specific/main.c", "dist/main.o", "modules/sokol-jai/sokol/gfx/sokol_gfx_wasm_gl_release.a", "modules/sokol-jai/sokol/log/sokol_log_wasm_gl_release.a", "modules/sokol-jai/sokol/audio/sokol_audio_wasm_gl_release.a", "modules/sokol-jai/sokol/time/sokol_time_wasm_gl_release.a", "modules/sokol-jai/sokol/app/sokol_app_wasm_gl_release.a", "modules/sokol-jai/sokol/glue/sokol_glue_wasm_gl_release.a", "modules/sokol-jai/sokol/fetch/sokol_fetch_wasm_gl_release.a", "modules/sokol-jai/sokol/gl/sokol_gl_wasm_gl_release.a", "modules/sokol-jai/sokol/fontstash/sokol_fontstash_wasm_gl_release.a",
"modules/sokol-jai/sokol/stbi/stb_image.a", "modules/sokol-jai/sokol/stbi/stb_image.a",
"modules/sokol-jai/sokol/stbv/stb_vorbis.a",
"-o", "dist/index.html", "-o", "dist/index.html",
"-sSTACK_SIZE=10MB", "-sSTACK_SIZE=10MB",
"-sALLOW_MEMORY_GROWTH", "-sALLOW_MEMORY_GROWTH",

View File

@ -1,6 +1,6 @@
_______________ _______________
Vulkan Version: Vulkan Version:
- available: 1.3.296 - available: 1.4.309
- requesting: 1.3.0 - requesting: 1.3.0
______________________ ______________________
Used Instance Layers : Used Instance Layers :
@ -8,17 +8,15 @@ VK_LAYER_KHRONOS_validation
Used Instance Extensions : Used Instance Extensions :
____________________ ____________________
Devices : 2 Devices : 1
0: AMD Radeon RX 6700 XT (RADV NAVI22) 0: AMD Radeon RX 6950 XT
- Compatible - Compatible
1: llvmpipe (LLVM 20.1.2, 256 bits) Compatible physical devices found : 1
- Compatible
Compatible physical devices found : 2
Using Device: Using Device:
- Device Name : AMD Radeon RX 6700 XT (RADV NAVI22) - Device Name : AMD Radeon RX 6950 XT
- Vendor : AMD - Vendor : AMD
- Driver Version : 25.2.8 - Driver Version : 2.0.341
- API Version : 1.4.318 - API Version : 1.4.308
- Device Type : Discrete GPU - Device Type : Discrete GPU
________________________ ________________________
Used Device Extensions : Used Device Extensions :
@ -26,4 +24,139 @@ VK_KHR_deferred_host_operations
VK_KHR_acceleration_structure VK_KHR_acceleration_structure
VK_KHR_ray_query VK_KHR_ray_query
BLAS Compaction: 0.3MB -> 0.2MB (0.1MB saved, 32.1% smaller) BLAS Compaction: 0.7MB -> 0.2MB (0.5MB saved, 65.9% 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: 0.8MB -> 0.3MB (0.5MB saved, 66.0% 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: 0.8MB -> 0.3MB (0.5MB saved, 66.0% 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: 0.8MB -> 0.3MB (0.5MB saved, 66.0% 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: 0.8MB -> 0.3MB (0.5MB saved, 65.9% 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: 0.8MB -> 0.3MB (0.5MB saved, 65.9% smaller)

View File

@ -32,6 +32,7 @@ build_lib_wasm_release sokol_fetch fetch/sokol_fetch_wasm_gl_release SOKOL
build_lib_wasm_release sokol_audio audio/sokol_audio_wasm_gl_release SOKOL_GLES3 build_lib_wasm_release sokol_audio audio/sokol_audio_wasm_gl_release SOKOL_GLES3
build_lib_wasm_release sokol_gl gl/sokol_gl_wasm_gl_release SOKOL_GLES3 build_lib_wasm_release sokol_gl gl/sokol_gl_wasm_gl_release SOKOL_GLES3
build_lib_wasm_release stb_image stbi/stb_image SOKOL_GLES3 build_lib_wasm_release stb_image stbi/stb_image SOKOL_GLES3
build_lib_wasm_release stb_vorbis stbv/stb_vorbis SOKOL_GLES3
# wasm + GL + Debug # wasm + GL + Debug
build_lib_wasm_debug sokol_log log/sokol_log_wasm_gl_debug SOKOL_GLES3 build_lib_wasm_debug sokol_log log/sokol_log_wasm_gl_debug SOKOL_GLES3
@ -47,5 +48,6 @@ build_lib_wasm_debug sokol_fetch fetch/sokol_fetch_wasm_gl_debug SOKOL_G
build_lib_wasm_debug sokol_audio audio/sokol_audio_wasm_gl_debug SOKOL_GLES3 build_lib_wasm_debug sokol_audio audio/sokol_audio_wasm_gl_debug SOKOL_GLES3
build_lib_wasm_debug sokol_gl gl/sokol_gl_wasm_gl_debug SOKOL_GLES3 build_lib_wasm_debug sokol_gl gl/sokol_gl_wasm_gl_debug SOKOL_GLES3
build_lib_wasm_debug stb_image stbi/stb_image SOKOL_GLES3 build_lib_wasm_debug stb_image stbi/stb_image SOKOL_GLES3
build_lib_wasm_debug stb_vorbis stbv/stb_vorbis SOKOL_GLES3
rm *.o rm *.o

View File

@ -0,0 +1,9 @@
#ifdef WIN32
#define __EXPORT __declspec(dllexport)
#else
#define __EXPORT
#endif
#define extern extern __EXPORT
#include "stb_vorbis_impl.c"

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,273 @@
//
// This file was auto-generated using the following command:
//
// jai modules/stb_vorbis/generate.jai
//
// normally stb_vorbis uses malloc() to allocate memory at startup,
// and alloca() to allocate temporary memory during a frame on the
// stack. (Memory consumption will depend on the amount of setup
// data in the file and how you set the compile flags for speed
// vs. size. In my test files the maximal-size usage is ~150KB.)
//
// You can modify the wrapper functions in the source (setup_malloc,
// setup_temp_malloc, temp_malloc) to change this behavior, or you
// can use a simpler allocation model: you pass in a buffer from
// which stb_vorbis will allocate _all_ its memory (including the
// temp memory). "open" may fail with a VORBIS_outofmem if you
// do not pass in enough data; there is no way to determine how
// much you do need except to succeed (at which point you can
// query get_info to find the exact amount required. yes I know
// this is lame).
//
// If you pass in a non-NULL buffer of the type below, allocation
// will occur from it as described above. Otherwise just pass NULL
// to use malloc()/alloca()
stb_vorbis_alloc :: struct {
alloc_buffer: *u8;
alloc_buffer_length_in_bytes: s32;
}
stb_vorbis :: struct {}
stb_vorbis_info :: struct {
sample_rate: u32;
channels: s32;
setup_memory_required: u32;
setup_temp_memory_required: u32;
temp_memory_required: u32;
max_frame_size: s32;
}
stb_vorbis_comment :: struct {
vendor: *u8;
comment_list_length: s32;
comment_list: **u8;
}
// get general information about the file
stb_vorbis_get_info :: (f: *stb_vorbis) -> stb_vorbis_info #foreign lib_stb_vorbis;
// get ogg comments
stb_vorbis_get_comment :: (f: *stb_vorbis) -> stb_vorbis_comment #foreign lib_stb_vorbis;
// get the last error detected (clears it, too)
stb_vorbis_get_error :: (f: *stb_vorbis) -> s32 #foreign lib_stb_vorbis;
// close an ogg vorbis file and free all memory in use
stb_vorbis_close :: (f: *stb_vorbis) -> void #foreign lib_stb_vorbis;
// this function returns the offset (in samples) from the beginning of the
// file that will be returned by the next decode, if it is known, or -1
// otherwise. after a flush_pushdata() call, this may take a while before
// it becomes valid again.
// NOT WORKING YET after a seek with PULLDATA API
stb_vorbis_get_sample_offset :: (f: *stb_vorbis) -> s32 #foreign lib_stb_vorbis;
// returns the current seek point within the file, or offset from the beginning
// of the memory buffer. In pushdata mode it returns 0.
stb_vorbis_get_file_offset :: (f: *stb_vorbis) -> u32 #foreign lib_stb_vorbis;
// this API allows you to get blocks of data from any source and hand
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
// you how much it used, and you have to give it the rest next time;
// and stb_vorbis may not have enough data to work with and you will
// need to give it the same data again PLUS more. Note that the Vorbis
// specification does not bound the size of an individual frame.
stb_vorbis_open_pushdata :: (datablock: *u8, datablock_length_in_bytes: s32, datablock_memory_consumed_in_bytes: *s32, error: *s32, alloc_buffer: *stb_vorbis_alloc) -> *stb_vorbis #foreign lib_stb_vorbis;
// create a vorbis decoder by passing in the initial data block containing
// the ogg&vorbis headers (you don't need to do parse them, just provide
// the first N bytes of the file--you're told if it's not enough, see below)
// on success, returns an stb_vorbis *, does not set error, returns the amount of
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
// incomplete and you need to pass in a larger block from the start of the file
stb_vorbis_decode_frame_pushdata :: (f: *stb_vorbis, datablock: *u8, datablock_length_in_bytes: s32, channels: *s32, output: ***float, samples: *s32) -> s32 #foreign lib_stb_vorbis;
// decode a frame of audio sample data if possible from the passed-in data block
//
// return value: number of bytes we used from datablock
//
// possible cases:
// 0 bytes used, 0 samples output (need more data)
// N bytes used, 0 samples output (resynching the stream, keep going)
// N bytes used, M samples output (one frame of data)
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
// frame, because Vorbis always "discards" the first frame.
//
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
// instead only datablock_length_in_bytes-3 or less. This is because it wants
// to avoid missing parts of a page header if they cross a datablock boundary,
// without writing state-machiney code to record a partial detection.
//
// The number of channels returned are stored in *channels (which can be
// NULL--it is always the same as the number of channels reported by
// get_info). *output will contain an array of float* buffers, one per
// channel. In other words, (*output)[0][0] contains the first sample from
// the first channel, and (*output)[1][0] contains the first sample from
// the second channel.
//
// *output points into stb_vorbis's internal output buffer storage; these
// buffers are owned by stb_vorbis and application code should not free
// them or modify their contents. They are transient and will be overwritten
// once you ask for more data to get decoded, so be sure to grab any data
// you need before then.
stb_vorbis_flush_pushdata :: (f: *stb_vorbis) -> void #foreign lib_stb_vorbis;
stb_vorbis_decode_filename :: (filename: *u8, channels: *s32, sample_rate: *s32, output: **s16) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_decode_memory :: (mem: *u8, len: s32, channels: *s32, sample_rate: *s32, output: **s16) -> s32 #foreign lib_stb_vorbis;
// decode an entire file and output the data interleaved into a malloc()ed
// buffer stored in *output. The return value is the number of samples
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
// When you're done with it, just free() the pointer returned in *output.
stb_vorbis_open_memory :: (data: *u8, len: s32, error: *s32, alloc_buffer: *stb_vorbis_alloc) -> *stb_vorbis #foreign lib_stb_vorbis;
stb_vorbis_open_filename :: (filename: *u8, error: *s32, alloc_buffer: *stb_vorbis_alloc) -> *stb_vorbis #foreign lib_stb_vorbis;
// create an ogg vorbis decoder from a filename via fopen(). on failure,
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
stb_vorbis_open_file :: (f: *FILE, close_handle_on_close: s32, error: *s32, alloc_buffer: *stb_vorbis_alloc) -> *stb_vorbis #foreign lib_stb_vorbis;
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Moreover, if you attempt to
// perform stb_vorbis_seek_*() operations on this file, it will assume it
// owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it.
stb_vorbis_open_file_section :: (f: *FILE, close_handle_on_close: s32, error: *s32, alloc_buffer: *stb_vorbis_alloc, len: u32) -> *stb_vorbis #foreign lib_stb_vorbis;
stb_vorbis_seek_frame :: (f: *stb_vorbis, sample_number: u32) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_seek :: (f: *stb_vorbis, sample_number: u32) -> s32 #foreign lib_stb_vorbis;
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
// after calling seek_frame(), the next call to get_frame_*() will include
// the specified sample. after calling stb_vorbis_seek(), the next call to
// stb_vorbis_get_samples_* will start with the specified sample. If you
// do not need to seek to EXACTLY the target sample when using get_samples_*,
// you can also use seek_frame().
stb_vorbis_seek_start :: (f: *stb_vorbis) -> s32 #foreign lib_stb_vorbis;
// this function is equivalent to stb_vorbis_seek(f,0)
stb_vorbis_stream_length_in_samples :: (f: *stb_vorbis) -> u32 #foreign lib_stb_vorbis;
stb_vorbis_stream_length_in_seconds :: (f: *stb_vorbis) -> float #foreign lib_stb_vorbis;
// these functions return the total length of the vorbis stream
stb_vorbis_get_frame_float :: (f: *stb_vorbis, channels: *s32, output: ***float) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_get_frame_short_interleaved :: (f: *stb_vorbis, num_c: s32, buffer: *s16, num_shorts: s32) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_get_frame_short :: (f: *stb_vorbis, num_c: s32, buffer: **s16, num_samples: s32) -> s32 #foreign lib_stb_vorbis;
// Channel coercion rules:
// Let M be the number of channels requested, and N the number of channels present,
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
// and stereo R be the sum of all R and center channels (channel assignment from the
// vorbis spec).
// M N output
// 1 k sum(Ck) for all k
// 2 * stereo L, stereo R
// k l k > l, the first l channels, then 0s
// k l k <= l, the first k channels
// Note that this is not _good_ surround etc. mixing at all! It's just so
// you get something useful.
stb_vorbis_get_samples_float_interleaved :: (f: *stb_vorbis, channels: s32, buffer: *float, num_floats: s32) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_get_samples_float :: (f: *stb_vorbis, channels: s32, buffer: **float, num_samples: s32) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_get_samples_short_interleaved :: (f: *stb_vorbis, channels: s32, buffer: *s16, num_shorts: s32) -> s32 #foreign lib_stb_vorbis;
stb_vorbis_get_samples_short :: (f: *stb_vorbis, channels: s32, buffer: **s16, num_samples: s32) -> s32 #foreign lib_stb_vorbis;
//////// ERROR CODES
STBVorbisError :: enum u32 {
no_error :: 0;
need_more_data :: 1;
invalid_api_mixing :: 2;
outofmem :: 3;
feature_not_supported :: 4;
too_many_channels :: 5;
file_open_failure :: 6;
seek_without_length :: 7;
unexpected_eof :: 10;
seek_invalid :: 11;
invalid_setup :: 20;
invalid_stream :: 21;
missing_capture_pattern :: 30;
invalid_stream_structure_version :: 31;
continued_packet_flag_invalid :: 32;
incorrect_stream_serial_number :: 33;
invalid_first_page :: 34;
bad_packet_type :: 35;
cant_find_last_page :: 36;
seek_failed :: 37;
ogg_skeleton_not_supported :: 38;
VORBIS__no_error :: no_error;
VORBIS_need_more_data :: need_more_data;
VORBIS_invalid_api_mixing :: invalid_api_mixing;
VORBIS_outofmem :: outofmem;
VORBIS_feature_not_supported :: feature_not_supported;
VORBIS_too_many_channels :: too_many_channels;
VORBIS_file_open_failure :: file_open_failure;
VORBIS_seek_without_length :: seek_without_length;
VORBIS_unexpected_eof :: unexpected_eof;
VORBIS_seek_invalid :: seek_invalid;
VORBIS_invalid_setup :: invalid_setup;
VORBIS_invalid_stream :: invalid_stream;
VORBIS_missing_capture_pattern :: missing_capture_pattern;
VORBIS_invalid_stream_structure_version :: invalid_stream_structure_version;
VORBIS_continued_packet_flag_invalid :: continued_packet_flag_invalid;
VORBIS_incorrect_stream_serial_number :: incorrect_stream_serial_number;
VORBIS_invalid_first_page :: invalid_first_page;
VORBIS_bad_packet_type :: bad_packet_type;
VORBIS_cant_find_last_page :: cant_find_last_page;
VORBIS_seek_failed :: seek_failed;
VORBIS_ogg_skeleton_not_supported :: ogg_skeleton_not_supported;
}
#scope_file
#if OS == .WINDOWS {
lib_stb_vorbis :: #library "windows/stb_vorbis";
} else #if OS == .LINUX {
lib_stb_vorbis :: #library "linux/stb_vorbis";
} else #if OS == .MACOS {
lib_stb_vorbis :: #library "macos/stb_vorbis";
} else #if OS == .ANDROID {
#if CPU == .X64 {
lib_stb_vorbis :: #library "android/x64/stb_vorbis";
} else #if CPU == .ARM64 {
lib_stb_vorbis :: #library "android/arm64/stb_vorbis";
}
} else #if OS == .PS5 {
lib_stb_vorbis :: #library "ps5/stb_vorbis";
} else #if OS == .NN_SWITCH2 {
#if CPU == .X64 {
lib_stb_vorbis :: #library "windows/stb_vorbis";
} else #if CPU == .ARM64 {
lib_stb_vorbis :: #library "switch2/stb_vorbis";
}
} else #if OS == .WASM {
lib_stb_vorbis :: #library "wasm/stb_vorbis";
} else {
#assert false;
}

View File

@ -0,0 +1,180 @@
AT_COMPILE_TIME :: true;
PS5_SUPPORT :: false;
NINTENDO_SUPPORT :: #run to_string(getenv("NINTENDO_SDK_ROOT")) != "";
SOURCE_PATH :: "source";
LIB_BASE_NAME :: "stb_vorbis";
LIB_DECLARATION_NAME :: "lib_stb_vorbis";
DECLARATIONS_TO_OMIT :: string.[
"STB_VORBIS_HEADER_ONLY", // No reason to export this.
];
#if AT_COMPILE_TIME {
#run,stallable {
set_build_options_dc(.{do_output=false});
options := get_build_options();
args := options.compile_time_command_line;
if !generate_bindings(args, options.minimum_os_version) {
compiler_set_workspace_status(.FAILED);
}
}
} else {
#import "System";
main :: () {
set_working_directory(path_strip_filename(get_path_of_running_executable()));
if !generate_bindings(get_command_line_arguments(), #run get_build_options().minimum_os_version) {
exit(1);
}
}
}
generate_bindings :: (args: [] string, minimum_os_version: type_of(Build_Options.minimum_os_version)) -> bool {
using BG;
target_android := array_find(args, "-android");
target_switch2 := array_find(args, "-switch2");
target_ps5 := array_find(args, "-ps5");
target_x64 := array_find(args, "-x64");
target_arm := array_find(args, "-arm64");
compile := array_find(args, "-compile");
compile_debug := array_find(args, "-debug");
os_target := OS;
cpu_target := CPU;
if target_android os_target = .ANDROID;
if target_switch2 os_target = .NN_SWITCH2;
if target_ps5 os_target = .PS5;
if target_x64 cpu_target = .X64;
if target_arm cpu_target = .ARM64;
build_dynamic_lib := true;
lib_directory: string;
if os_target == {
case .WINDOWS;
lib_directory = "windows";
case .LINUX;
lib_directory = "linux";
case .MACOS;
lib_directory = "macos";
case .ANDROID;
lib_directory = ifx cpu_target == .X64 then "android/x64" else "android/arm64";
case .PS5;
build_dynamic_lib = false;
lib_directory = "ps5";
case .NN_SWITCH2;
build_dynamic_lib = false;
lib_directory = "switch2";
case;
assert(false);
}
if compile {
source_file := tprint("%/stb_vorbis_custom.c", SOURCE_PATH);
make_directory_if_it_does_not_exist(lib_directory, recursive = true);
lib_path := tprint("%/%", lib_directory, LIB_BASE_NAME);
success := true;
if os_target == .MACOS {
success &&= Build_Cpp.build_universal_macos_binary(lib_path, source_file, type = .DYNAMIC_LIBRARY, debug = compile_debug);
success &&= Build_Cpp.build_universal_macos_binary(lib_path, source_file, type = .STATIC_LIBRARY, debug = compile_debug);
} else {
extra: [..] string;
if os_target == .ANDROID {
_, target_triple_with_sdk := get_android_target_triple(cpu_target);
array_add(*extra, "-target", target_triple_with_sdk);
}
if os_target != .WINDOWS {
array_add(*extra, "-fPIC");
}
if build_dynamic_lib {
success &&= Build_Cpp.build_cpp_dynamic_lib(lib_path, source_file, target = os_target, debug = compile_debug, extra = extra);
}
success &&= Build_Cpp.build_cpp_static_lib(lib_path, source_file, target = os_target, debug = compile_debug, extra = extra);
}
if !success return false;
}
options: Generate_Bindings_Options;
options.os = os_target;
options.cpu = cpu_target;
{
using options;
array_add(*extra_clang_arguments, "-DSTB_VORBIS_HEADER_ONLY");
array_add(*library_search_paths, lib_directory);
array_add(*libraries, .{filename=LIB_BASE_NAME, identifier=LIB_DECLARATION_NAME});
array_add(*source_files, tprint("%/stb_vorbis.c", SOURCE_PATH));
generate_library_declarations = false;
footer = tprint(FOOTER_TEMPLATE, LIB_BASE_NAME, LIB_DECLARATION_NAME);
auto_detect_enum_prefixes = true;
log_stripped_declarations = false;
generate_compile_time_struct_checks = false;
visitor = stb_visitor;
}
output_filename := "bindings.jai";
return generate_bindings(options, output_filename);
}
FOOTER_TEMPLATE :: #string END
#if OS == .WINDOWS {
%2 :: #library "windows/%1";
} else #if OS == .LINUX {
%2 :: #library "linux/%1";
} else #if OS == .MACOS {
%2 :: #library "macos/%1";
} else #if OS == .ANDROID {
#if CPU == .X64 {
%2 :: #library "android/x64/%1";
} else #if CPU == .ARM64 {
%2 :: #library "android/arm64/%1";
}
} else #if OS == .PS5 {
%2 :: #library "ps5/%1";
} else #if OS == .NN_SWITCH2 {
#if CPU == .X64 {
%2 :: #library "windows/%1";
} else #if CPU == .ARM64 {
%2 :: #library "switch2/%1";
}
} else {
#assert false;
}
END
stb_visitor :: (decl: *BG.Declaration, parent_decl: *BG.Declaration) -> BG.Declaration_Visit_Result {
if !parent_decl {
if array_find(DECLARATIONS_TO_OMIT, decl.name) {
decl.decl_flags |= .OMIT_FROM_OUTPUT;
return .STOP;
}
}
return .RECURSE;
}
#import "Basic";
BG :: #import "Bindings_Generator"(NINTENDO_SUPPORT = NINTENDO_SUPPORT);
Build_Cpp :: #import "BuildCpp"()(PS5_SUPPORT = PS5_SUPPORT, NINTENDO_SUPPORT = NINTENDO_SUPPORT);
#import "Compiler";
#import "File";
#import "Android/Toolchain";
#if OS == .WINDOWS {
#import "Windows";
} else {
#import "POSIX";
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,11 @@
#load "bindings.jai";
#if OS == .WINDOWS || OS == .PS5 || OS == .NN_SWITCH2 || OS == .WASM {
#scope_module
FILE :: void;
} else #if OS_IS_UNIX {
#import "POSIX";
#library,system,link_always "libm";
} else {
#assert false;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
#ifdef WIN32
#define __EXPORT __declspec(dllexport)
#else
#define __EXPORT
#endif
#define extern extern __EXPORT
#include "stb_vorbis.c"

Binary file not shown.

Binary file not shown.

View File

@ -306,6 +306,9 @@ add_resources_from_pack :: (pack: *Loaded_Pack) {
case "wav"; case "wav";
audio := load_wav_from_memory(v.data); audio := load_wav_from_memory(v.data);
table_set(*pack.audio, name, audio); table_set(*pack.audio, name, audio);
case "ogg";
audio := load_ogg_from_memory(v.data);
table_set(*pack.audio, name, audio);
case "json"; case "json";
if name == "particles" { if name == "particles" {
s := create_string_from_memory(v.data); s := create_string_from_memory(v.data);

View File

@ -64,6 +64,29 @@ load_hex_palette_from_memory :: (data: []u8) -> [..]Palette_Entry {
return entries; return entries;
} }
// Decoded in full up front, so the mixer sees the same float samples as from a wav;
// only the pack stays small.
load_ogg_from_memory :: (data: []u8) -> Audio_Data {
Vorbis :: #import "stb_vorbis";
audio : Audio_Data;
error : s32;
v := Vorbis.stb_vorbis_open_memory(data.data, cast(s32) data.count, *error, null);
if !v {
log_error("Failed to load ogg file! (stb_vorbis error %)", error);
return audio;
}
defer Vorbis.stb_vorbis_close(v);
info := Vorbis.stb_vorbis_get_info(v);
frames := cast(s64) Vorbis.stb_vorbis_stream_length_in_samples(v);
array_resize(*audio.data, frames * info.channels);
got := Vorbis.stb_vorbis_get_samples_float_interleaved(v, info.channels, audio.data.data, cast(s32) audio.data.count);
audio.data.count = got * info.channels;
audio.channels = cast(s16) info.channels;
audio.sample_rate = cast(s32) info.sample_rate;
return audio;
}
load_wav_from_memory :: (data: []u8) -> Audio_Data { load_wav_from_memory :: (data: []u8) -> Audio_Data {
Wav :: #import "Wav_File"; Wav :: #import "Wav_File";
audio : Audio_Data; audio : Audio_Data;

View File

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

View File

@ -487,6 +487,7 @@ add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
for *group: chunk.groups { for *group: chunk.groups {
if group.trile_name == name { if group.trile_name == name {
array_add(*group.instances, inst); array_add(*group.instances, inst);
recompute_group_bounds(group);
added = true; added = true;
break; break;
} }
@ -495,6 +496,7 @@ add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
group: Chunk_Trile_Group; group: Chunk_Trile_Group;
group.trile_name = sprint("%", name); group.trile_name = sprint("%", name);
array_add(*group.instances, inst); array_add(*group.instances, inst);
recompute_group_bounds(*group);
array_add(*chunk.groups, group); array_add(*chunk.groups, group);
} }
invalidate_buried_around(*curworld.world, x, y, z); invalidate_buried_around(*curworld.world, x, y, z);
@ -520,6 +522,7 @@ remove_trile :: (x: s32, y: s32, z: s32) {
if group.is_buried.count > idx { if group.is_buried.count > idx {
array_unordered_remove_by_index(*group.is_buried, idx); array_unordered_remove_by_index(*group.is_buried, idx);
} }
recompute_group_bounds(group);
removed = true; removed = true;
break; break;
} }

View File

@ -302,6 +302,7 @@ entity_saved_members :: (type: Type) -> []Type_Info_Struct_Member {
result.allocator = temp; result.allocator = temp;
for (cast(*Type_Info_Struct) type).members { for (cast(*Type_Info_Struct) type).members {
if it.flags & (.CONSTANT | .USING) continue; if it.flags & (.CONSTANT | .USING) continue;
if array_find(it.notes, "NoSave") continue;
array_add(*result, it); array_add(*result, it);
} }
return result; return result;

View File

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

View File

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

View File

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

View File

@ -58,8 +58,17 @@ AUDIO_LABELS :: string.["Master Volume", "Music Volume", "Sound Effects"];
GRAPHICS_ITEMS :: string.["Fullscreen"]; GRAPHICS_ITEMS :: string.["Fullscreen"];
} }
main_items :: () -> []string {
result : [..]string;
result.allocator = temp;
array_add(*result, MAIN_ITEMS[0]);
for g_settings_config.main_items array_add(*result, it.label);
for 1..MAIN_ITEMS.count-1 array_add(*result, MAIN_ITEMS[it]);
return result;
}
page_items :: () -> []string { page_items :: () -> []string {
if g_settings.page == .MAIN return MAIN_ITEMS; if g_settings.page == .MAIN return main_items();
if g_settings.page == .SETTINGS return SETTINGS_ITEMS; if g_settings.page == .SETTINGS return SETTINGS_ITEMS;
if g_settings.page == .AUDIO return AUDIO_LABELS; if g_settings.page == .AUDIO return AUDIO_LABELS;
if g_settings.page == .GRAPHICS return GRAPHICS_ITEMS; if g_settings.page == .GRAPHICS return GRAPHICS_ITEMS;
@ -224,9 +233,17 @@ handle_enter :: (index: s32 = -1) {
i := ifx index >= 0 then index else g_settings.cursor; i := ifx index >= 0 then index else g_settings.cursor;
if g_settings.page == { if g_settings.page == {
case .MAIN; case .MAIN;
game_items := cast(s32) g_settings_config.main_items.count;
if i == 0 { save_settings(); g_settings.open = false; } if i == 0 { save_settings(); g_settings.open = false; }
if i == 1 then navigate_to(.SETTINGS); else if i <= game_items {
if i == 2 { save_settings(); sapp_request_quit(); } save_settings();
g_settings.open = false;
g_settings_config.main_items[i - 1].on_select();
} else {
i -= game_items;
if i == 1 then navigate_to(.SETTINGS);
if i == 2 { save_settings(); sapp_request_quit(); }
}
case .SETTINGS; case .SETTINGS;
if i == 0 then navigate_to(.AUDIO); if i == 0 then navigate_to(.AUDIO);
if i == 1 then navigate_to(.GRAPHICS); if i == 1 then navigate_to(.GRAPHICS);
@ -255,10 +272,17 @@ Phosphene_Config :: struct {
palette : []Vector3; palette : []Vector3;
} }
// An entry the game adds to the pause menu. Choosing it closes the menu first.
Settings_Menu_Item :: struct {
label : string;
on_select : ();
}
Settings_Menu_Config :: struct { Settings_Menu_Config :: struct {
game_title : string = "TRUENO"; game_title : string = "TRUENO";
credits : string = "Trueno engine by Tuomas Katajisto 2026"; credits : string = "Trueno engine by Tuomas Katajisto 2026";
phosphenes : Phosphene_Config; phosphenes : Phosphene_Config;
main_items : []Settings_Menu_Item; // must outlive the config, e.g. a constant array
} }
set_settings_config :: (config: Settings_Menu_Config) { set_settings_config :: (config: Settings_Menu_Config) {

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

Binary file not shown.