trueno/src/trile.jai
2026-04-30 22:45:04 +03:00

307 lines
9.7 KiB
Plaintext

#scope_file
trile_gfx_table : Table(string, Trile_GFX);
trile_table : Table(string, Trile);
#scope_export
editor_current_trile : *Trile = null;
Trile_GFX_LOD :: struct {
vertex_buffer : sg_buffer;
normal_buffer : sg_buffer;
color_buffer : sg_buffer;
vertex_count : s64;
}
Trile_GFX :: struct {
trixel_colors : sg_image;
vertex_buffer : sg_buffer;
normal_buffer : sg_buffer;
centre_buffer : sg_buffer;
vertices : []float;
vertex_count : s64;
lod_4 : Trile_GFX_LOD; // 4^3 cube grid
lod_2 : Trile_GFX_LOD; // 2^3 cube grid
};
get_trile_table_ptr :: () -> *Table(string, Trile) {
return *trile_table;
}
// @Note: Creates the gfx things if they are not yet created.
// Could be a bad idea to do this implicitly. Think about it
// once it's more clear how this whole trile storage thing
// will pan out. -ktjst
get_trile_gfx :: (name: string) -> (Trile_GFX, success: bool) {
success, value := table_find(*trile_gfx_table, name);
if !success {
// Check if such a trile exists.
trile, success_with_trile := get_trile(name);
if success_with_trile {
// Okay, so we have the trile, let's generate the GFX stuff for it.
gfx := generate_trile_gfx_matias(trile);
set_trile_gfx(name, gfx, true);
return gfx, true;
} else {
return .{}, false;
}
}
return value, success;
}
set_trile_gfx :: (name: string, gfx: Trile_GFX, skip_preexist_check: bool = false) {
if !skip_preexist_check {
old_gfx, success := get_trile_gfx(name);
if success {
sg_destroy_buffer(old_gfx.vertex_buffer);
sg_destroy_buffer(old_gfx.normal_buffer);
sg_destroy_buffer(old_gfx.centre_buffer);
sg_destroy_image(old_gfx.trixel_colors);
destroy_trile_gfx_lod(*old_gfx.lod_4);
destroy_trile_gfx_lod(*old_gfx.lod_2);
array_reset(*old_gfx.vertices);
log_debug("Destroyed old GFX buffers for trile: %", name);
}
}
table_set(*trile_gfx_table, name, gfx);
}
set_trile :: (name: string, trile: Trile) {
log_debug("Setting trile with name: %", name);
// Destroy and remove any cached GFX so it gets regenerated from new data.
gfx_exists, old_gfx := table_find(*trile_gfx_table, name);
if gfx_exists {
sg_destroy_buffer(old_gfx.vertex_buffer);
sg_destroy_buffer(old_gfx.normal_buffer);
sg_destroy_buffer(old_gfx.centre_buffer);
sg_destroy_image(old_gfx.trixel_colors);
destroy_trile_gfx_lod(*old_gfx.lod_4);
destroy_trile_gfx_lod(*old_gfx.lod_2);
array_reset(*old_gfx.vertices);
table_remove(*trile_gfx_table, name);
}
saved_editor_name: string;
if editor_current_trile then saved_editor_name = editor_current_trile.name;
table_set(*trile_table, name, trile);
if saved_editor_name.count > 0 {
editor_current_trile = table_find_pointer(*trile_table, saved_editor_name);
}
}
get_trile :: (name: string) -> (*Trile, success: bool) {
trileptr := table_find_pointer(*trile_table, name);
if !trileptr {
log_error("Failed to get trile with name: %", name);
return null, false;
}
return trileptr, true;
}
rename_trile :: (old_name: string, new_name: string) {
trile := get_trile(old_name);
if !trile return;
was_current := editor_current_trile != null && editor_current_trile.name == old_name;
gfx_exists, old_gfx := table_find(*trile_gfx_table, old_name);
if gfx_exists {
sg_destroy_buffer(old_gfx.vertex_buffer);
sg_destroy_buffer(old_gfx.normal_buffer);
sg_destroy_buffer(old_gfx.centre_buffer);
sg_destroy_image(old_gfx.trixel_colors);
destroy_trile_gfx_lod(*old_gfx.lod_4);
destroy_trile_gfx_lod(*old_gfx.lod_2);
array_reset(*old_gfx.vertices);
table_remove(*trile_gfx_table, old_name);
}
copy := trile.*;
copy.name = sprint("%", new_name);
set_trile(copy.name, copy);
table_remove(*trile_table, old_name);
if was_current editor_current_trile = table_find_pointer(*trile_table, new_name);
}
delete_trile :: (name: string) {
gfx_exists, old_gfx := table_find(*trile_gfx_table, name);
if gfx_exists {
sg_destroy_buffer(old_gfx.vertex_buffer);
sg_destroy_buffer(old_gfx.normal_buffer);
sg_destroy_buffer(old_gfx.centre_buffer);
sg_destroy_image(old_gfx.trixel_colors);
destroy_trile_gfx_lod(*old_gfx.lod_4);
destroy_trile_gfx_lod(*old_gfx.lod_2);
array_reset(*old_gfx.vertices);
table_remove(*trile_gfx_table, name);
}
table_remove(*trile_table, name);
if editor_current_trile != null && editor_current_trile.name == name {
editor_current_trile = null;
}
}
lstrile :: () -> string {
count := 0;
for v : trile_table {
console_add_output_line(sprint("%", v.name));
count += 1;
}
return tprint("% triles", count);
} @Command
striles :: () {
Jaison :: #import "Jaison";
triles : [..]TrileSerialize;
triles.allocator = temp;
for v : trile_table {
array_add(*triles, trile_to_serialize_form(v));
}
#if OS != .WASM {
file :: #import "File";
json := Jaison.json_write_string(triles, " ");
file.write_entire_file(tprint("%/game_core/triles.json", GAME_RESOURCES_DIR), json);
}
} @Command
ltriles :: () {
Jaison :: #import "Jaison";
s := load_string_from_pack("game_core", "triles.json");
success, triles := Jaison.json_parse_string(s, [..]TrileSerialize,, temp);
for triles {
set_trile(sprint("%",it.name), trile_from_serialize_form(it));
log_debug("Loaded %", it.name);
}
} @Command
Material :: struct {
roughness : u8 = 4;
metallic : u8 = 0;
emittance : u8 = 0; // 0 = not emissive; 1-127 = emissive (replaces roughness/metallic in encoding)
color : Vector3 = .{1.0, 0.0, 1.0};
}
Palette_Entry :: struct {
name : string;
r : float = 1.0;
g : float = 0.0;
b : float = 1.0;
roughness : int = 4;
metallic : int = 0;
emittance : int = 0;
}
Loaded_Palette :: struct {
name : string;
entries : [..]Palette_Entry;
}
g_palettes : [..]Loaded_Palette;
Trixel :: struct {
material : Material;
empty : bool = false;
};
Trile :: struct {
name : string = "test";
is_opaque : bool = true;
trixels : [16][16][16] Trixel;
};
TrixelSerialize :: [5]u8;
TrileSerialize :: struct {
name : string = "test";
version : int = 0;
is_opaque : u8 = 1;
trixels : [16][16][16] TrixelSerialize;
};
trile_to_serialize_form :: (t: Trile) -> TrileSerialize {
ts := TrileSerialize.{
name = t.name,
version = 2,
is_opaque = ifx t.is_opaque then cast(u8)1 else cast(u8)0,
};
for i: 0..15 {
for j: 0..15 {
for k: 0..15 {
r,g,b,a := material_to_rgba(t.trixels[i][j][k].material);
ts.trixels[i][j][k] = .[ifx t.trixels[i][j][k].empty then cast(u8)0 else cast(u8)1, r,g,b,a];
}
}
}
return ts;
}
trile_from_serialize_form :: (ts: TrileSerialize) -> Trile {
t := Trile.{ name = sprint("%", ts.name) };
if ts.version >= 2 t.is_opaque = ts.is_opaque != 0;
else t.is_opaque = true;
for i: 0..15 {
for j: 0..15 {
for k: 0..15 {
matinfo := ts.trixels[i][j][k];
mat : Material;
if ts.version == 0 {
// Old format: bit 0=addRoughness(unused), bits 1-2=emittance(0-3), bits 3-4=metallic, bits 5-7=roughness
packed := matinfo[4];
old_emittance := (packed >> 1) & 0x3;
mat.metallic = (packed >> 3) & 0x3;
mat.roughness = (packed >> 5) & 0x7;
mat.emittance = old_emittance * 42; // scale 0-3 → 0,42,84,126
mat.color.x = cast(float) matinfo[1] / 255.0;
mat.color.y = cast(float) matinfo[2] / 255.0;
mat.color.z = cast(float) matinfo[3] / 255.0;
} else {
mat = material_from_rgba(matinfo[1], matinfo[2], matinfo[3], matinfo[4]);
}
t.trixels[i][j][k].material = mat;
t.trixels[i][j][k].empty = matinfo[0] == 0;
}
}
}
return t;
}
material_encode_to_char :: (mat: Material) -> u8 {
if mat.emittance > 0 {
// Emissive mode: bit 0 = 1, bits 1-7 = emittance (0-127)
return 0x1 | ((mat.emittance & 0x7F) << 1);
}
// Material mode: bit 0 = 0, bits 3-4 = metallic, bits 5-7 = roughness
return ((mat.metallic & 0x3) << 3) | ((mat.roughness & 0x7) << 5);
}
material_encode_to_float :: (mat: Material) -> float {
return cast(float)(material_encode_to_char(mat)) / 255.0;
}
material_decode_from_char :: (packedMaterial: u8) -> Material {
mat : Material;
if packedMaterial & 0x1 {
mat.emittance = (packedMaterial >> 1) & 0x7F;
} else {
mat.roughness = (packedMaterial >> 5) & 7;
mat.metallic = (packedMaterial >> 3) & 3;
}
return mat;
}
material_to_rgba :: (mat: Material) -> (r: u8, g: u8, b: u8, a: u8) {
r : u8 = cast(u8) (mat.color.x * 255.0);
g : u8 = cast(u8) (mat.color.y * 255.0);
b : u8 = cast(u8) (mat.color.z * 255.0);
a : u8 = material_encode_to_char(mat);
return r,g,b,a;
}
material_from_rgba :: (r: u8, g: u8, b: u8, a: u8) -> Material {
mat := material_decode_from_char(a);
mat.color.x = (cast(float) r)/255.0;
mat.color.y = (cast(float) g)/255.0;
mat.color.z = (cast(float) b)/255.0;
return mat;
}