work on editor
This commit is contained in:
parent
8668157060
commit
1bfe79fc6b
@ -24,149 +24,4 @@ VK_KHR_deferred_host_operations
|
|||||||
VK_KHR_acceleration_structure
|
VK_KHR_acceleration_structure
|
||||||
VK_KHR_ray_query
|
VK_KHR_ray_query
|
||||||
|
|
||||||
BLAS Compaction: 0.7MB -> 0.2MB (0.4MB saved, 66.0% smaller)
|
BLAS Compaction: 1.9MB -> 0.6MB (1.2MB saved, 66.1% 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.7MB -> 0.2MB (0.4MB 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.7MB -> 0.2MB (0.4MB 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.7MB -> 0.2MB (0.4MB 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.7MB -> 0.2MB (0.4MB 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.7MB -> 0.2MB (0.4MB saved, 66.0% smaller)
|
|
||||||
_______________
|
|
||||||
Vulkan Version:
|
|
||||||
- available: 1.4.309
|
|
||||||
- requesting: 1.3.0
|
|
||||||
______________________
|
|
||||||
Used Instance Layers :
|
|
||||||
VK_LAYER_KHRONOS_validation
|
|
||||||
|
|
||||||
Used Instance Extensions :
|
|
||||||
__________________
|
|
||||||
|
|||||||
@ -20,6 +20,34 @@ cameraCenter : Vector2;
|
|||||||
|
|
||||||
trile_preview_disabled : bool = false;
|
trile_preview_disabled : bool = false;
|
||||||
|
|
||||||
|
Level_Editor_Tool_Mode :: enum {
|
||||||
|
POINT;
|
||||||
|
BRUSH;
|
||||||
|
AREA;
|
||||||
|
LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_tool_mode : Level_Editor_Tool_Mode = .POINT;
|
||||||
|
brush_radius : int = 2;
|
||||||
|
brush_height : int = 0;
|
||||||
|
|
||||||
|
area_active : bool;
|
||||||
|
area_start_x : int;
|
||||||
|
area_start_y : int;
|
||||||
|
area_start_z : int;
|
||||||
|
|
||||||
|
line_active : bool;
|
||||||
|
line_start_x : int;
|
||||||
|
line_start_y : int;
|
||||||
|
line_start_z : int;
|
||||||
|
|
||||||
|
current_orientation_face : u8 = 0;
|
||||||
|
current_orientation_twist : u8 = 0;
|
||||||
|
|
||||||
|
get_current_orientation :: () -> u8 {
|
||||||
|
return current_orientation_face * 4 + current_orientation_twist;
|
||||||
|
}
|
||||||
|
|
||||||
#scope_export
|
#scope_export
|
||||||
|
|
||||||
toggle_preview :: () {
|
toggle_preview :: () {
|
||||||
@ -248,7 +276,74 @@ editMode : Edit_Mode;
|
|||||||
|
|
||||||
draw_tools_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
|
draw_tools_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
|
||||||
r := total_r;
|
r := total_r;
|
||||||
r.h = ui_h(3,0);
|
r.h = ui_h(4, 0);
|
||||||
|
|
||||||
|
// Tool mode buttons
|
||||||
|
if GR.button(r, "Point", *t_button_selectable(theme, current_tool_mode == .POINT)) {
|
||||||
|
current_tool_mode = .POINT;
|
||||||
|
}
|
||||||
|
r.y += r.h;
|
||||||
|
if GR.button(r, "Brush", *t_button_selectable(theme, current_tool_mode == .BRUSH)) {
|
||||||
|
current_tool_mode = .BRUSH;
|
||||||
|
}
|
||||||
|
r.y += r.h;
|
||||||
|
if GR.button(r, "Area", *t_button_selectable(theme, current_tool_mode == .AREA)) {
|
||||||
|
current_tool_mode = .AREA;
|
||||||
|
area_active = false;
|
||||||
|
}
|
||||||
|
r.y += r.h;
|
||||||
|
if GR.button(r, "Line", *t_button_selectable(theme, current_tool_mode == .LINE)) {
|
||||||
|
current_tool_mode = .LINE;
|
||||||
|
line_active = false;
|
||||||
|
}
|
||||||
|
r.y += r.h;
|
||||||
|
|
||||||
|
// Brush radius/height (only for brush mode)
|
||||||
|
if current_tool_mode == .BRUSH {
|
||||||
|
r.h = ui_h(3, 2);
|
||||||
|
GR.label(r, "Brush Radius", *t_label_left(theme));
|
||||||
|
r.y += r.h;
|
||||||
|
r.h = ui_h(4, 0);
|
||||||
|
GR.slider(r, *brush_radius, 1, 8, 1, *theme.slider_theme);
|
||||||
|
r.y += r.h;
|
||||||
|
r.h = ui_h(3, 2);
|
||||||
|
GR.label(r, "Brush Height (±Y layers)", *t_label_left(theme));
|
||||||
|
r.y += r.h;
|
||||||
|
r.h = ui_h(4, 0);
|
||||||
|
GR.slider(r, *brush_height, 0, 8, 1, *theme.slider_theme);
|
||||||
|
r.y += r.h * 2;
|
||||||
|
} else {
|
||||||
|
r.y += r.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status hints for multi-click tools
|
||||||
|
r.h = ui_h(3, 2);
|
||||||
|
if current_tool_mode == .AREA {
|
||||||
|
if area_active {
|
||||||
|
GR.label(r, "Click second corner to fill", *t_label_left(theme));
|
||||||
|
} else {
|
||||||
|
GR.label(r, "Click first corner to start", *t_label_left(theme));
|
||||||
|
}
|
||||||
|
r.y += r.h;
|
||||||
|
} else if current_tool_mode == .LINE {
|
||||||
|
if line_active {
|
||||||
|
GR.label(r, "Click endpoint to draw line", *t_label_left(theme));
|
||||||
|
} else {
|
||||||
|
GR.label(r, "Click start of line", *t_label_left(theme));
|
||||||
|
}
|
||||||
|
r.y += r.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orientation controls
|
||||||
|
r.y += r.h;
|
||||||
|
r.h = ui_h(3, 2);
|
||||||
|
GR.label(r, "-- Orientation --", *t_label_left(theme));
|
||||||
|
r.y += r.h;
|
||||||
|
twist_angle := current_orientation_twist * 90;
|
||||||
|
GR.label(r, tprint("Face: % Twist: %°", current_orientation_face, twist_angle), *t_label_left(theme));
|
||||||
|
r.y += r.h;
|
||||||
|
GR.label(r, "Q/E: twist R: face", *t_label_left(theme));
|
||||||
|
r.y += r.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_tool_click :: (x: int, y: int, z: int, delete: bool = false) {
|
handle_tool_click :: (x: int, y: int, z: int, delete: bool = false) {
|
||||||
@ -256,10 +351,53 @@ handle_tool_click :: (x: int, y: int, z: int, delete: bool = false) {
|
|||||||
if delete {
|
if delete {
|
||||||
remove_trile(cast(s32)x, cast(s32)y, cast(s32)z);
|
remove_trile(cast(s32)x, cast(s32)y, cast(s32)z);
|
||||||
} else {
|
} else {
|
||||||
if editor_current_trile != null then add_trile(editor_current_trile.name, cast(s32)x, cast(s32)y, cast(s32)z);
|
if editor_current_trile != null then add_trile(editor_current_trile.name, cast(s32)x, cast(s32)y, cast(s32)z, get_current_orientation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply_brush :: (cx: int, cy: int, cz: int, delete: bool) {
|
||||||
|
for dy: -brush_height..brush_height {
|
||||||
|
for dx: -brush_radius..brush_radius {
|
||||||
|
for dz: -brush_radius..brush_radius {
|
||||||
|
dist := sqrt(cast(float)(dx*dx + dz*dz));
|
||||||
|
if dist <= cast(float)brush_radius {
|
||||||
|
handle_tool_click(cx + dx, cy + dy, cz + dz, delete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_area :: (x2: int, y2: int, z2: int, delete: bool) {
|
||||||
|
for x: min(area_start_x, x2)..max(area_start_x, x2) {
|
||||||
|
for y: min(area_start_y, y2)..max(area_start_y, y2) {
|
||||||
|
for z: min(area_start_z, z2)..max(area_start_z, z2) {
|
||||||
|
handle_tool_click(x, y, z, delete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_line :: (x2: int, y2: int, z2: int, delete: bool) {
|
||||||
|
x1 := line_start_x; y1 := line_start_y; z1 := line_start_z;
|
||||||
|
dx := abs(x2 - x1); dy := abs(y2 - y1); dz := abs(z2 - z1);
|
||||||
|
sx := ifx x1 < x2 then 1 else -1;
|
||||||
|
sy := ifx y1 < y2 then 1 else -1;
|
||||||
|
sz := ifx z1 < z2 then 1 else -1;
|
||||||
|
// 3D Bresenham: drive along the longest axis
|
||||||
|
dm := max(dx, max(dy, dz));
|
||||||
|
x := x1; y := y1; z := z1;
|
||||||
|
ex := dm / 2; ey := dm / 2; ez := dm / 2;
|
||||||
|
count := 0;
|
||||||
|
while count <= dm && count < 2000 {
|
||||||
|
handle_tool_click(x, y, z, delete);
|
||||||
|
ex -= dx; if ex < 0 { x += sx; ex += dm; }
|
||||||
|
ey -= dy; if ey < 0 { y += sy; ey += dm; }
|
||||||
|
ez -= dz; if ez < 0 { z += sz; ez += dm; }
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
|
add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
|
||||||
curworld := get_current_world();
|
curworld := get_current_world();
|
||||||
|
|
||||||
@ -316,9 +454,25 @@ remove_trile :: (x: s32, y: s32, z: s32) {
|
|||||||
tick_level_editor :: () {
|
tick_level_editor :: () {
|
||||||
#if HAS_TACOMA { rdm_bake_tick(); }
|
#if HAS_TACOMA { rdm_bake_tick(); }
|
||||||
tick_level_editor_camera();
|
tick_level_editor_camera();
|
||||||
|
|
||||||
|
if !console_open_ignore_input {
|
||||||
|
if input_button_states[#char "Q"] & .START {
|
||||||
|
lastInputTime = get_time();
|
||||||
|
current_orientation_twist = (current_orientation_twist + 1) % 4;
|
||||||
|
}
|
||||||
|
if input_button_states[#char "E"] & .START {
|
||||||
|
lastInputTime = get_time();
|
||||||
|
current_orientation_twist = (current_orientation_twist + 3) % 4;
|
||||||
|
}
|
||||||
|
if input_button_states[#char "R"] & .START {
|
||||||
|
lastInputTime = get_time();
|
||||||
|
current_orientation_face = (current_orientation_face + 1) % 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ray := get_mouse_ray(*get_level_editor_camera());
|
ray := get_mouse_ray(*get_level_editor_camera());
|
||||||
hit, point := ray_plane_collision_point(ray, xx editY, 20);
|
hit, point := ray_plane_collision_point(ray, xx editY, 20);
|
||||||
|
|
||||||
show_trile_preview = false;
|
show_trile_preview = false;
|
||||||
if hit {
|
if hit {
|
||||||
show_trile_preview = true;
|
show_trile_preview = true;
|
||||||
@ -326,20 +480,138 @@ tick_level_editor :: () {
|
|||||||
trile_preview_y = editY;
|
trile_preview_y = editY;
|
||||||
trile_preview_z = xx floor(point.y);
|
trile_preview_z = xx floor(point.y);
|
||||||
|
|
||||||
if get_mouse_state(Key_Code.MOUSE_BUTTON_LEFT) & .START {
|
px := trile_preview_x;
|
||||||
handle_tool_click(xx floor(point.x), xx editY, xx floor(point.y));
|
py := trile_preview_y;
|
||||||
}
|
pz := trile_preview_z;
|
||||||
if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .START {
|
|
||||||
handle_tool_click(xx floor(point.x), xx editY, xx floor(point.y), true);
|
if current_tool_mode == .POINT {
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_LEFT) & .START {
|
||||||
|
handle_tool_click(px, py, pz);
|
||||||
|
}
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .START {
|
||||||
|
handle_tool_click(px, py, pz, true);
|
||||||
|
}
|
||||||
|
} else if current_tool_mode == .BRUSH {
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_LEFT) & .DOWN {
|
||||||
|
apply_brush(px, py, pz, false);
|
||||||
|
}
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .DOWN {
|
||||||
|
apply_brush(px, py, pz, true);
|
||||||
|
}
|
||||||
|
} else if current_tool_mode == .AREA {
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_LEFT) & .START {
|
||||||
|
if !area_active {
|
||||||
|
area_active = true;
|
||||||
|
area_start_x = px;
|
||||||
|
area_start_y = py;
|
||||||
|
area_start_z = pz;
|
||||||
|
} else {
|
||||||
|
apply_area(px, py, pz, false);
|
||||||
|
area_active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .START {
|
||||||
|
if area_active then area_active = false;
|
||||||
|
else handle_tool_click(px, py, pz, true);
|
||||||
|
}
|
||||||
|
} else if current_tool_mode == .LINE {
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_LEFT) & .START {
|
||||||
|
if !line_active {
|
||||||
|
line_active = true;
|
||||||
|
line_start_x = px;
|
||||||
|
line_start_y = py;
|
||||||
|
line_start_z = pz;
|
||||||
|
} else {
|
||||||
|
apply_line(px, py, pz, false);
|
||||||
|
line_active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .START {
|
||||||
|
if line_active then line_active = false;
|
||||||
|
else handle_tool_click(px, py, pz, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_level_editor_preview_tasks :: () {
|
||||||
|
curworld := get_current_world();
|
||||||
|
if !curworld.valid then return;
|
||||||
|
if !editor_current_trile then return;
|
||||||
|
|
||||||
|
positions: [..]Vector4;
|
||||||
|
positions.allocator = temp;
|
||||||
|
ori := cast(float) get_current_orientation();
|
||||||
|
|
||||||
|
px := trile_preview_x; py := trile_preview_y; pz := trile_preview_z;
|
||||||
|
|
||||||
|
if current_tool_mode == .POINT {
|
||||||
|
array_add(*positions, .{cast(float)px, cast(float)py, cast(float)pz, ori});
|
||||||
|
} else if current_tool_mode == .BRUSH {
|
||||||
|
for dy: -brush_height..brush_height {
|
||||||
|
for dx: -brush_radius..brush_radius {
|
||||||
|
for dz: -brush_radius..brush_radius {
|
||||||
|
dist := sqrt(cast(float)(dx*dx + dz*dz));
|
||||||
|
if dist <= cast(float)brush_radius {
|
||||||
|
array_add(*positions, .{cast(float)(px+dx), cast(float)(py+dy), cast(float)(pz+dz), ori});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if current_tool_mode == .AREA {
|
||||||
|
if area_active {
|
||||||
|
for x: min(area_start_x, px)..max(area_start_x, px) {
|
||||||
|
for y: min(area_start_y, py)..max(area_start_y, py) {
|
||||||
|
for z: min(area_start_z, pz)..max(area_start_z, pz) {
|
||||||
|
array_add(*positions, .{cast(float)x, cast(float)y, cast(float)z, ori});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
array_add(*positions, .{cast(float)px, cast(float)py, cast(float)pz, ori});
|
||||||
|
}
|
||||||
|
} else if current_tool_mode == .LINE {
|
||||||
|
if line_active {
|
||||||
|
x1 := line_start_x; y1 := line_start_y; z1 := line_start_z;
|
||||||
|
x2 := px; y2 := py; z2 := pz;
|
||||||
|
dx := abs(x2-x1); dy := abs(y2-y1); dz := abs(z2-z1);
|
||||||
|
sx := ifx x1 < x2 then 1 else -1;
|
||||||
|
sy := ifx y1 < y2 then 1 else -1;
|
||||||
|
sz := ifx z1 < z2 then 1 else -1;
|
||||||
|
dm := max(dx, max(dy, dz));
|
||||||
|
x := x1; y := y1; z := z1;
|
||||||
|
ex := dm/2; ey := dm/2; ez := dm/2;
|
||||||
|
count := 0;
|
||||||
|
while count <= dm && count < 2000 {
|
||||||
|
array_add(*positions, .{cast(float)x, cast(float)y, cast(float)z, ori});
|
||||||
|
ex -= dx; if ex < 0 { x += sx; ex += dm; }
|
||||||
|
ey -= dy; if ey < 0 { y += sy; ey += dm; }
|
||||||
|
ez -= dz; if ez < 0 { z += sz; ez += dm; }
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
array_add(*positions, .{cast(float)px, cast(float)py, cast(float)pz, ori});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if positions.count == 0 then return;
|
||||||
|
|
||||||
|
task: Rendering_Task_Trile;
|
||||||
|
task.trile = editor_current_trile.name;
|
||||||
|
task.positions = positions;
|
||||||
|
task.worldConf = *curworld.world.conf;
|
||||||
|
task.is_preview = true;
|
||||||
|
add_rendering_task(task);
|
||||||
|
}
|
||||||
|
|
||||||
draw_level_editor :: () {
|
draw_level_editor :: () {
|
||||||
curworld := get_current_world();
|
curworld := get_current_world();
|
||||||
if !curworld.valid then return;
|
if !curworld.valid then return;
|
||||||
create_set_cam_rendering_task(get_level_editor_camera(), effective_plane_height(*curworld.world.conf));
|
create_set_cam_rendering_task(get_level_editor_camera(), effective_plane_height(*curworld.world.conf));
|
||||||
create_world_rendering_tasks(*curworld.world);
|
create_world_rendering_tasks(*curworld.world);
|
||||||
|
if show_trile_preview && !trile_preview_disabled {
|
||||||
|
create_level_editor_preview_tasks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_level_editor_ui :: (theme: *GR.Overall_Theme) {
|
draw_level_editor_ui :: (theme: *GR.Overall_Theme) {
|
||||||
|
|||||||
@ -74,6 +74,59 @@ get_trile_roughness_set :: (trile_name: string) -> u8 {
|
|||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Predicted pixel dimensions of a single RDM entry at a given roughness level.
|
||||||
|
// roughness 0 → 512×768, roughness 1 → 256×384, ..., roughness 7 → 4×6.
|
||||||
|
rdm_entry_predicted_size :: (roughness: s32) -> (w: s32, h: s32) {
|
||||||
|
size : s32 = cast(s32)(1 << (8 - roughness));
|
||||||
|
return 2 * size, 3 * size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate shelf-pack of jobs into a canvas of given width; return total height used.
|
||||||
|
rdm_simulate_pack_height :: (jobs: []RDM_Bake_Job, canvas_w: s32) -> s32 {
|
||||||
|
cx : s32 = 0;
|
||||||
|
cy : s32 = 0;
|
||||||
|
rh : s32 = 0;
|
||||||
|
for job: jobs {
|
||||||
|
w, h := rdm_entry_predicted_size(job.roughness);
|
||||||
|
if cx + w > canvas_w { cy += rh; cx = 0; rh = 0; }
|
||||||
|
cx += w;
|
||||||
|
if h > rh rh = h;
|
||||||
|
}
|
||||||
|
cy += rh;
|
||||||
|
return cy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate shelf-packing for a chunk's sorted job list and return minimum
|
||||||
|
// power-of-2 atlas dimensions, capped at RDM_ATLAS_SIZE.
|
||||||
|
rdm_calc_chunk_atlas_size :: (jobs: []RDM_Bake_Job) -> (s32, s32) {
|
||||||
|
if jobs.count == 0 return 16, 16;
|
||||||
|
|
||||||
|
// Estimate canvas width from sqrt(total pixel area).
|
||||||
|
total_area : s64 = 0;
|
||||||
|
for job: jobs {
|
||||||
|
w, h := rdm_entry_predicted_size(job.roughness);
|
||||||
|
total_area += cast(s64) w * cast(s64) h;
|
||||||
|
}
|
||||||
|
target_w : s32 = 16;
|
||||||
|
sqrt_area := cast(s32) sqrt(cast(float) total_area) + 1;
|
||||||
|
while target_w < sqrt_area target_w *= 2;
|
||||||
|
|
||||||
|
// Widen until the packed height fits within the width (roughly square).
|
||||||
|
while target_w < RDM_ATLAS_SIZE {
|
||||||
|
if rdm_simulate_pack_height(jobs, target_w) <= target_w break;
|
||||||
|
target_w *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round height up to next power of 2.
|
||||||
|
final_height := rdm_simulate_pack_height(jobs, target_w);
|
||||||
|
target_h : s32 = 16;
|
||||||
|
while target_h < final_height target_h *= 2;
|
||||||
|
|
||||||
|
if target_w > RDM_ATLAS_SIZE target_w = RDM_ATLAS_SIZE;
|
||||||
|
if target_h > RDM_ATLAS_SIZE target_h = RDM_ATLAS_SIZE;
|
||||||
|
return target_w, target_h;
|
||||||
|
}
|
||||||
|
|
||||||
// Build the Tacoma scene from the world, and emit bake jobs for selected chunks.
|
// Build the Tacoma scene from the world, and emit bake jobs for selected chunks.
|
||||||
// If chunk_keys is null, all chunks are queued.
|
// If chunk_keys is null, all chunks are queued.
|
||||||
rdm_bake_start :: (world: World, quality: s32, include_water: bool, chunk_keys: []Chunk_Key = .[]) {
|
rdm_bake_start :: (world: World, quality: s32, include_water: bool, chunk_keys: []Chunk_Key = .[]) {
|
||||||
@ -205,15 +258,38 @@ rdm_bake_start :: (world: World, quality: s32, include_water: bool, chunk_keys:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-allocate per-chunk atlas CPU buffers.
|
// Pre-allocate per-chunk atlas CPU buffers with optimal (minimum) sizes.
|
||||||
atlas_bytes := cast(s64) RDM_ATLAS_SIZE * cast(s64) RDM_ATLAS_SIZE * 4 * size_of(float);
|
{
|
||||||
for job: rdm_bake.jobs {
|
// Collect unique chunk keys.
|
||||||
chunk_key := world_to_chunk_coord(cast(s32) job.world_pos.x, cast(s32) job.world_pos.y, cast(s32) job.world_pos.z);
|
unique_chunk_keys : [..]Chunk_Key;
|
||||||
if !table_contains(*rdm_chunk_bakes, chunk_key) {
|
unique_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 unique_chunk_keys { if it == ck { already = true; break; } }
|
||||||
|
if !already array_add(*unique_chunk_keys, ck);
|
||||||
|
}
|
||||||
|
|
||||||
|
for chunk_key: unique_chunk_keys {
|
||||||
|
// Collect this chunk's jobs (already sorted by roughness ascending).
|
||||||
|
this_jobs : [..]RDM_Bake_Job;
|
||||||
|
this_jobs.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);
|
||||||
|
if ck == chunk_key array_add(*this_jobs, job);
|
||||||
|
}
|
||||||
|
|
||||||
|
atlas_w, atlas_h := rdm_calc_chunk_atlas_size(this_jobs);
|
||||||
|
print("RDM atlas for chunk %: %x% (%.1f MB, was % MB)\n",
|
||||||
|
chunk_key, atlas_w, atlas_h,
|
||||||
|
cast(float)(cast(s64) atlas_w * atlas_h * 4 * size_of(float)) / (1024.0 * 1024.0),
|
||||||
|
RDM_ATLAS_SIZE * RDM_ATLAS_SIZE * 4 * size_of(float) / (1024 * 1024));
|
||||||
|
|
||||||
|
atlas_bytes := cast(s64) atlas_w * cast(s64) atlas_h * 4 * size_of(float);
|
||||||
bake : RDM_Chunk_Bake;
|
bake : RDM_Chunk_Bake;
|
||||||
bake.width = RDM_ATLAS_SIZE;
|
bake.width = atlas_w;
|
||||||
bake.height = RDM_ATLAS_SIZE;
|
bake.height = atlas_h;
|
||||||
bake.data = cast(*float) alloc(atlas_bytes);
|
bake.data = cast(*float) alloc(atlas_bytes);
|
||||||
memset(bake.data, 0, atlas_bytes);
|
memset(bake.data, 0, atlas_bytes);
|
||||||
table_set(*rdm_chunk_bakes, chunk_key, bake);
|
table_set(*rdm_chunk_bakes, chunk_key, bake);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ Render_Command_Draw_Trile_Positions :: struct {
|
|||||||
chunk_key : Chunk_Key;
|
chunk_key : Chunk_Key;
|
||||||
amount : s32;
|
amount : s32;
|
||||||
conf : *World_Config;
|
conf : *World_Config;
|
||||||
|
is_preview : bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Render_Command_Update_Trixels :: struct {
|
Render_Command_Update_Trixels :: struct {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ backend_handle_command :: (cmd: *Render_Command) {
|
|||||||
backend_add_trile_positions(add_command.positions);
|
backend_add_trile_positions(add_command.positions);
|
||||||
case .DRAW_TRILE_POSITIONS;
|
case .DRAW_TRILE_POSITIONS;
|
||||||
draw_command := cast(*Render_Command_Draw_Trile_Positions)cmd;
|
draw_command := cast(*Render_Command_Draw_Trile_Positions)cmd;
|
||||||
backend_draw_trile_positions(draw_command.trile, draw_command.amount, draw_command.conf, draw_command.chunk_key);
|
backend_draw_trile_positions(draw_command.trile, draw_command.amount, draw_command.conf, draw_command.chunk_key, draw_command.is_preview);
|
||||||
case .DRAW_SKY;
|
case .DRAW_SKY;
|
||||||
sky_command := cast(*Render_Command_Sky)cmd;
|
sky_command := cast(*Render_Command_Sky)cmd;
|
||||||
backend_draw_sky(sky_command.worldConfig);
|
backend_draw_sky(sky_command.worldConfig);
|
||||||
@ -115,11 +115,11 @@ backend_add_trile_positions :: (positions : []Vector4) {
|
|||||||
array_add(*trile_offsets, offset);
|
array_add(*trile_offsets, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
backend_draw_trile_positions :: (trile : string, amount : s32, worldConf: *World_Config, chunk_key: Chunk_Key) {
|
backend_draw_trile_positions :: (trile : string, amount : s32, worldConf: *World_Config, chunk_key: Chunk_Key, is_preview: bool = false) {
|
||||||
if in_gbuffer_pass {
|
if in_gbuffer_pass {
|
||||||
backend_draw_trile_positions_gbuffer(trile, amount, worldConf);
|
backend_draw_trile_positions_gbuffer(trile, amount, worldConf);
|
||||||
} else {
|
} else {
|
||||||
backend_draw_trile_positions_main(trile, amount, worldConf, chunk_key);
|
backend_draw_trile_positions_main(trile, amount, worldConf, chunk_key, is_preview);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ backend_draw_trile_positions_gbuffer :: (trile : string, amount : s32, worldConf
|
|||||||
sg_draw(0, cast(s32) trilegfx.vertex_count, amount);
|
sg_draw(0, cast(s32) trilegfx.vertex_count, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
backend_draw_trile_positions_main :: (trile : string, amount : s32, worldConf: *World_Config, chunk_key: Chunk_Key) {
|
backend_draw_trile_positions_main :: (trile : string, amount : s32, worldConf: *World_Config, chunk_key: Chunk_Key, is_preview: bool = false) {
|
||||||
start_frame_profiling_group("Draw trile positions");
|
start_frame_profiling_group("Draw trile positions");
|
||||||
mvp : Matrix4;
|
mvp : Matrix4;
|
||||||
if !in_shadowmap_pass {
|
if !in_shadowmap_pass {
|
||||||
@ -220,6 +220,7 @@ backend_draw_trile_positions_main :: (trile : string, amount : s32, worldConf: *
|
|||||||
fs_params.rdm_diff_scale = lc.rdm_diff_scale;
|
fs_params.rdm_diff_scale = lc.rdm_diff_scale;
|
||||||
fs_params.rdm_spec_scale = lc.rdm_spec_scale;
|
fs_params.rdm_spec_scale = lc.rdm_spec_scale;
|
||||||
fs_params.ambient_color = lc.ambient_color.component;
|
fs_params.ambient_color = lc.ambient_color.component;
|
||||||
|
fs_params.is_preview = ifx is_preview then cast(s32)1 else cast(s32)0;
|
||||||
fs_params.rdm_tint = lc.rdm_tint.component;
|
fs_params.rdm_tint = lc.rdm_tint.component;
|
||||||
|
|
||||||
sg_apply_bindings(*bindings);
|
sg_apply_bindings(*bindings);
|
||||||
|
|||||||
@ -56,6 +56,7 @@ Rendering_Task_Trile :: struct {
|
|||||||
chunk_key : Chunk_Key;
|
chunk_key : Chunk_Key;
|
||||||
positions : []Vector4;
|
positions : []Vector4;
|
||||||
worldConf : *World_Config;
|
worldConf : *World_Config;
|
||||||
|
is_preview : bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rendering_Task_Trixels :: struct {
|
Rendering_Task_Trixels :: struct {
|
||||||
@ -113,10 +114,15 @@ tasks_to_commands :: () {
|
|||||||
drawPositionsCmd.chunk_key = trileTask.chunk_key;
|
drawPositionsCmd.chunk_key = trileTask.chunk_key;
|
||||||
drawPositionsCmd.amount = cast(s32)trileTask.positions.count;
|
drawPositionsCmd.amount = cast(s32)trileTask.positions.count;
|
||||||
drawPositionsCmd.conf = trileTask.worldConf;
|
drawPositionsCmd.conf = trileTask.worldConf;
|
||||||
array_add(*render_command_buckets.reflection, drawPositionsCmd);
|
drawPositionsCmd.is_preview = trileTask.is_preview;
|
||||||
array_add(*render_command_buckets.main, drawPositionsCmd);
|
if trileTask.is_preview {
|
||||||
array_add(*render_command_buckets.gbuffer, drawPositionsCmd);
|
array_add(*render_command_buckets.main, drawPositionsCmd);
|
||||||
array_add(*render_command_buckets.shadow, drawPositionsCmd);
|
} else {
|
||||||
|
array_add(*render_command_buckets.reflection, drawPositionsCmd);
|
||||||
|
array_add(*render_command_buckets.main, drawPositionsCmd);
|
||||||
|
array_add(*render_command_buckets.gbuffer, drawPositionsCmd);
|
||||||
|
array_add(*render_command_buckets.shadow, drawPositionsCmd);
|
||||||
|
}
|
||||||
case .SKY;
|
case .SKY;
|
||||||
command := New(Render_Command_Sky,, temp);
|
command := New(Render_Command_Sky,, temp);
|
||||||
command.worldConfig = (cast(*Rendering_Task_Sky)it).worldConfig;
|
command.worldConfig = (cast(*Rendering_Task_Sky)it).worldConfig;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,24 @@ in vec4 instance;
|
|||||||
out vec3 view_space_pos;
|
out vec3 view_space_pos;
|
||||||
out vec3 view_space_normal;
|
out vec3 view_space_normal;
|
||||||
|
|
||||||
|
mat3 gbuf_rot_x(float a) { float c=cos(a),s=sin(a); return mat3(1,0,0, 0,c,-s, 0,s,c); }
|
||||||
|
mat3 gbuf_rot_z(float a) { float c=cos(a),s=sin(a); return mat3(c,-s,0, s,c,0, 0,0,1); }
|
||||||
|
mat3 gbuf_rot_y(float a) { float c=cos(a),s=sin(a); return mat3(c,0,s, 0,1,0, -s,0,c); }
|
||||||
|
|
||||||
|
mat3 gbuf_get_orientation_matrix(int ori) {
|
||||||
|
int face = ori / 4;
|
||||||
|
int twist = ori % 4;
|
||||||
|
float PI = 3.1415927;
|
||||||
|
mat3 base;
|
||||||
|
if (face == 0) base = mat3(1.0);
|
||||||
|
else if (face == 1) base = gbuf_rot_x(PI);
|
||||||
|
else if (face == 2) base = gbuf_rot_z(-PI*0.5);
|
||||||
|
else if (face == 3) base = gbuf_rot_z( PI*0.5);
|
||||||
|
else if (face == 4) base = gbuf_rot_x( PI*0.5);
|
||||||
|
else base = gbuf_rot_x(-PI*0.5);
|
||||||
|
return base * gbuf_rot_y(float(twist) * PI * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (isGround == 1) {
|
if (isGround == 1) {
|
||||||
vec4 world_pos = vec4(position.x * 100.0, planeHeight, position.z * 100.0, 1.0);
|
vec4 world_pos = vec4(position.x * 100.0, planeHeight, position.z * 100.0, 1.0);
|
||||||
@ -22,12 +40,15 @@ void main() {
|
|||||||
view_space_pos = view_pos_4.xyz;
|
view_space_pos = view_pos_4.xyz;
|
||||||
view_space_normal = mat3(view_matrix) * normal.xyz;
|
view_space_normal = mat3(view_matrix) * normal.xyz;
|
||||||
} else {
|
} else {
|
||||||
vec4 world_pos = vec4(position.xyz + instance.xyz, 1.0);
|
int ori = int(round(instance.w));
|
||||||
vec4 view_pos_4 = view_matrix * world_pos;
|
mat3 rot = gbuf_get_orientation_matrix(ori);
|
||||||
gl_Position = mvp * world_pos;
|
vec3 local = position.xyz - 0.5;
|
||||||
view_space_pos = view_pos_4.xyz;
|
vec3 rotated = rot * local + 0.5;
|
||||||
view_space_normal = mat3(view_matrix) * normal.xyz;
|
vec4 world_pos = vec4(rotated + instance.xyz, 1.0);
|
||||||
|
vec4 view_pos_4 = view_matrix * world_pos;
|
||||||
|
gl_Position = mvp * world_pos;
|
||||||
|
view_space_pos = view_pos_4.xyz;
|
||||||
|
view_space_normal = mat3(view_matrix) * (rot * normal.xyz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -16,18 +16,43 @@ out vec3 to_center;
|
|||||||
out vec3 vpos; // The actual position;
|
out vec3 vpos; // The actual position;
|
||||||
out vec3 ipos; // Trile space position;
|
out vec3 ipos; // Trile space position;
|
||||||
out vec4 fnormal;
|
out vec4 fnormal;
|
||||||
|
out vec3 orig_normal; // Unrotated object-space normal, used for trixel lookup
|
||||||
out vec3 trileCenter;
|
out vec3 trileCenter;
|
||||||
out vec3 cv;
|
out vec3 cv;
|
||||||
|
|
||||||
|
mat3 rot_x(float a) { float c=cos(a),s=sin(a); return mat3(1,0,0, 0,c,-s, 0,s,c); }
|
||||||
|
mat3 rot_z(float a) { float c=cos(a),s=sin(a); return mat3(c,-s,0, s,c,0, 0,0,1); }
|
||||||
|
mat3 rot_y(float a) { float c=cos(a),s=sin(a); return mat3(c,0,s, 0,1,0, -s,0,c); }
|
||||||
|
|
||||||
|
mat3 get_orientation_matrix(int ori) {
|
||||||
|
int face = ori / 4;
|
||||||
|
int twist = ori % 4;
|
||||||
|
float PI = 3.1415927;
|
||||||
|
mat3 base;
|
||||||
|
if (face == 0) base = mat3(1.0);
|
||||||
|
else if (face == 1) base = rot_x(PI);
|
||||||
|
else if (face == 2) base = rot_z(-PI*0.5);
|
||||||
|
else if (face == 3) base = rot_z( PI*0.5);
|
||||||
|
else if (face == 4) base = rot_x( PI*0.5);
|
||||||
|
else base = rot_x(-PI*0.5);
|
||||||
|
return base * rot_y(float(twist) * PI * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = mvp * vec4(position.xyz + instance.xyz, 1.0);
|
int ori = int(round(instance.w));
|
||||||
fnormal = normal;
|
mat3 rot = get_orientation_matrix(ori);
|
||||||
to_center = centre.xyz - position.xyz;
|
vec3 local = position.xyz - 0.5;
|
||||||
vpos = position.xyz + instance.xyz;
|
vec3 rotated = rot * local + 0.5;
|
||||||
ipos = position.xyz;
|
|
||||||
cam = camera;
|
gl_Position = mvp * vec4(rotated + instance.xyz, 1.0);
|
||||||
cv = normalize(camera - vpos);
|
fnormal = vec4(rot * normal.xyz, 0.0);
|
||||||
trileCenter = vpos - ipos + vec3(0.5);
|
orig_normal = normal.xyz; // unrotated, for trixel lookup
|
||||||
|
to_center = centre.xyz - position.xyz; // unrotated, for trixel lookup
|
||||||
|
vpos = rotated + instance.xyz;
|
||||||
|
ipos = position.xyz;
|
||||||
|
cam = camera;
|
||||||
|
cv = normalize(camera - vpos);
|
||||||
|
trileCenter = instance.xyz + vec3(0.5);
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -59,6 +84,7 @@ in vec3 to_center;
|
|||||||
in vec3 vpos;
|
in vec3 vpos;
|
||||||
in vec3 ipos;
|
in vec3 ipos;
|
||||||
in vec4 fnormal;
|
in vec4 fnormal;
|
||||||
|
in vec3 orig_normal;
|
||||||
in vec3 trileCenter;
|
in vec3 trileCenter;
|
||||||
in vec3 cv;
|
in vec3 cv;
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
@ -74,6 +100,7 @@ layout(binding=3) uniform trile_fs_params {
|
|||||||
float rdm_diff_scale;
|
float rdm_diff_scale;
|
||||||
float rdm_spec_scale;
|
float rdm_spec_scale;
|
||||||
vec3 ambient_color;
|
vec3 ambient_color;
|
||||||
|
int is_preview;
|
||||||
vec3 rdm_tint;
|
vec3 rdm_tint;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -447,7 +474,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trixel material sampling
|
// Trixel material sampling
|
||||||
vec3 pos_after_adjust = ipos - fnormal.xyz * 0.02;
|
vec3 pos_after_adjust = ipos - orig_normal * 0.02;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
vec4 trixel_material;
|
vec4 trixel_material;
|
||||||
while (count < 5) {
|
while (count < 5) {
|
||||||
@ -543,6 +570,9 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
frag_color = vec4(mix(deepColor, light + emissive, smoothstep(0.0, planeHeight, vpos.y)), 1.0);
|
frag_color = vec4(mix(deepColor, light + emissive, smoothstep(0.0, planeHeight, vpos.y)), 1.0);
|
||||||
|
if (is_preview == 1) {
|
||||||
|
frag_color.rgb = mix(frag_color.rgb, vec3(0.3, 0.7, 1.0), 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user