307 lines
9.7 KiB
Plaintext
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;
|
|
}
|
|
|