#scope_file rotation : float = 0.0; tilt : float = 0.0; zoom : float = 3.0; brush_radius : int = 5; roughness : u8 = 0; metallic : u8 = 0; emittance : u8 = 0; hovered_trixel_x : int = -1; hovered_trixel_y : int = -1; hovered_trixel_z : int = -1; TRILE_ROTATION_SPEED :: 2.0; Trile_Editor_Tab :: enum { TOOLSET; METADATA; MATERIAL; }; Trile_Editor_Tool :: enum { PAINT; ADD; REMOVE; } Trile_Editor_Tool_Mode :: enum { POINT; BRUSH; AREA; } current_tab : Trile_Editor_Tab = .TOOLSET; current_tool : Trile_Editor_Tool = .PAINT; current_mode : Trile_Editor_Tool_Mode = .AREA; colorMuls : [16][16][16]Vector3; #scope_export ntrile :: (name: string) { set_trile_gfx(editor_current_trile.name, generate_trile_gfx_matias(editor_current_trile)); newt : Trile; newt.name = sprint("%", name); set_trile(newt.name, newt); editor_current_trile = get_trile(newt.name); } @Command cpytrile :: (trile: string, destination: string) { set_trile_gfx(editor_current_trile.name, generate_trile_gfx_matias(editor_current_trile)); newt : Trile; newt.name = sprint("%", destination); newt.trixels = get_trile(trile).trixels; set_trile(newt.name, newt); editor_current_trile = get_trile(newt.name); } @Command ltrile :: (name: string) { set_trile_gfx(editor_current_trile.name, generate_trile_gfx_matias(editor_current_trile)); nt := get_trile(name); if !nt { console_add_output_line("Failed to load a trile with that name..."); return; } editor_current_trile = nt; } @Command #scope_file apply_tool_to_trixel :: (x: s64, y: s64, z: s64) { if current_tool == .PAINT { editor_current_trile.trixels[x][y][z].material.color = current_color; editor_current_trile.trixels[x][y][z].material.metallic = metallic; editor_current_trile.trixels[x][y][z].material.roughness = roughness; editor_current_trile.trixels[x][y][z].material.emittance = emittance; } if current_tool == .ADD { editor_current_trile.trixels[x][y][z].empty = false; } if current_tool == .REMOVE { editor_current_trile.trixels[x][y][z].empty = true; } } area_start_x : int; area_start_y : int; area_start_z : int; area_active : bool; handle_tool_click :: () { if hovered_trixel_x < 0 && hovered_trixel_y < 0 && hovered_trixel_z < 0 then return; if current_mode == .POINT { apply_tool_to_trixel(hovered_trixel_x, hovered_trixel_y, hovered_trixel_z); } if current_mode == .BRUSH { is_in_radius :: (point : Vector3, radius: float) -> bool { center : Vector3 = .{xx hovered_trixel_x, xx hovered_trixel_y, xx hovered_trixel_z}; return length(point - center) <= radius; } for x: 0..15 { for y: 0..15 { for z: 0..15 { if is_in_radius(.{xx x, xx y, xx z}, xx brush_radius) { apply_tool_to_trixel(x,y,z); } } } } } if current_mode == .AREA { if area_active { // Apply tool to all trixels in the area. for x: min(area_start_x, hovered_trixel_x)..max(hovered_trixel_x, area_start_x) { for y: min(area_start_y, hovered_trixel_y)..max(hovered_trixel_y, area_start_y) { for z: min(area_start_z, hovered_trixel_z)..max(hovered_trixel_z, area_start_z) { apply_tool_to_trixel(x,y,z); } } } area_active = false; } else { area_active = true; area_start_x = hovered_trixel_x; area_start_y = hovered_trixel_y; area_start_z = hovered_trixel_z; } } } #scope_export current_color : Vector3 = .{1.0, 0.0, 0.0}; reset_trile :: () { newt : Trile; set_trile("test", newt); editor_current_trile = get_trile("test"); } @Command tick_trile_editor :: () { if console_open_ignore_input then return; if !editor_current_trile then editor_current_trile = get_trile("test"); if input_button_states[Key_Code.MOUSE_BUTTON_LEFT] & .START { handle_tool_click(); } mindist : float = 999999; hovered_trixel_x = -1; hovered_trixel_y = -1; hovered_trixel_z = -1; for x: 0..15 { for y: 0..15 { for z: 0..15 { t := editor_current_trile.trixels[x][y][z]; if t.empty then continue; cube : Collision_Cube; cube.position = Vector3.{cast(float) x, cast(float) y, cast(float) z} * TRIXEL_SIZE; cube.size = Vector3.{1,1,1} * TRIXEL_SIZE; ray := get_mouse_ray(*get_trile_editor_camera()); collision := does_ray_hit_cube(ray, cube); if collision.hit && collision.distance < mindist { mindist = collision.distance; hovered_trixel_x = x; hovered_trixel_y = y; hovered_trixel_z = z; } } } } for x: 0..15 { for y: 0..15 { for z: 0..15 { if x == hovered_trixel_x && y == hovered_trixel_y && z == hovered_trixel_z { colorMuls[x][y][z] = .{0.6, 0.0, 0.0}; } else { colorMuls[x][y][z] = .{1.0, 1.0, 1.0}; } } } } if !input_button_states[Key_Code.CTRL] & .DOWN { if input_button_states[#char "D"] & .DOWN { rotation += TRILE_ROTATION_SPEED * cast(float) delta_time; } if input_button_states[#char "A"] & .DOWN { rotation -= TRILE_ROTATION_SPEED * cast(float) delta_time; } if input_button_states[#char "W"] & .DOWN { tilt += TRILE_ROTATION_SPEED * cast(float) delta_time; } if input_button_states[#char "S"] & .DOWN { tilt -= TRILE_ROTATION_SPEED * cast(float) delta_time; } } trile_editor_shortcuts(); tilt = clamp(tilt, -(PI/2.0) + 0.01, PI/2.0 - 0.01); zoom = clamp(zoom + mouse_delta_z * -0.2, 1.0, 3.0); cam := get_trile_editor_camera(); ray := get_mouse_ray(*cam); } get_trile_editor_camera :: () -> Camera { camera: Camera; camera.near = 0.1; camera.far = 5000; cameraDir : Vector3 = .{1, 0, 0}; qrotation : Quaternion = .{cos(rotation/2.0),0,sin(rotation/2.0),0}; qtilt : Quaternion = .{cos(tilt/2.0),sin(tilt/2.0), 0, 0}; rotate(*cameraDir, qrotation * qtilt); camera.position = .{0.5, 0.5, 0.5}; camera.position += cameraDir * zoom; camera.target = .{0.5, 0.5, 0.5}; return camera; } global_palette_scroll : float = 0.0; trile_palette_scroll : float = 0.0; draw_tool_tab :: (theme: *GR.Overall_Theme, area: GR.Rect) { r := area; r.h = ui_h(4, 0); if GR.button(r, "Paint (P)", *t_button_selectable(theme, current_tool == .PAINT)) { current_tool = .PAINT; } r.y += r.h; if GR.button(r, "Add (+)", *t_button_selectable(theme, current_tool == .ADD)) { current_tool = .ADD; } r.y += r.h; if GR.button(r, "Remove (-)", *t_button_selectable(theme, current_tool == .REMOVE)) { current_tool = .REMOVE; } r.y += r.h * 3; if GR.button(r, "Point (c-P)", *t_button_selectable(theme, current_mode == .POINT)) { current_mode = .POINT; } r.y += r.h; if GR.button(r, "Area (c-A)", *t_button_selectable(theme, current_mode == .AREA)) { current_mode = .AREA; } r.y += r.h; if GR.button(r, "Brush (c-B)", *t_button_selectable(theme, current_mode == .BRUSH)) { current_mode = .BRUSH; } r.y += r.h; GR.slider(r, *brush_radius, 0, 12, 1, *theme.slider_theme); r.y += r.h * 2; if GR.button(r, "Save and gen", *theme.button_theme) { set_trile_gfx(editor_current_trile.name, generate_trile_gfx_matias(editor_current_trile)); }; } draw_material_tab :: (theme: *GR.Overall_Theme, area: GR.Rect) { r := area; r.h = ui_h(42, 0); GR.color_picker(r, *current_color, *theme.color_picker_theme); r.y += r.h; r.h = ui_h(100,0) - r.y; r.h -= ui_h(18,0); r.h /= 2; region, inside := GR.begin_scrollable_region(r, *theme.scrollable_region_theme); s := inside; GR.end_scrollable_region(region, s.x + s.w, s.y + s.h, *global_palette_scroll); r.y += r.h; region, inside = GR.begin_scrollable_region(r, *theme.scrollable_region_theme); s = inside; GR.end_scrollable_region(region, s.x + s.w, s.y + s.h, *trile_palette_scroll); r.y += r.h; r.h = ui_h(3,2); GR.label(r, "Roughness", *t_label_left(theme)); r.y += r.h; GR.slider(r, *roughness, 0, 7, 1, *theme.slider_theme); r.y += r.h; GR.label(r, "Metallic", *t_label_left(theme)); r.y += r.h; GR.slider(r, *metallic, 0, 3, 1, *theme.slider_theme); r.y += r.h; GR.label(r, "Emittance", *t_label_left(theme)); r.y += r.h; GR.slider(r, *emittance, 0, 2, 1, *theme.slider_theme); } draw_trile_editor :: () { create_set_cam_rendering_task(get_trile_editor_camera()); w := New(World,, temp); create_sky_rendering_task(*w.conf); create_trixel_rendering_task(editor_current_trile, *colorMuls); } trile_editor_shortcuts :: () { if console_open_ignore_input then return; if input_button_states[Key_Code.CTRL] & .DOWN { if input_button_states[#char "A"] & .START { current_mode = .AREA; } if input_button_states[#char "P"] & .START { current_mode = .POINT; } if input_button_states[#char "B"] & .START { current_mode = .BRUSH; } } else { if input_button_states[#char "T"] & .START { current_tab = .TOOLSET; } if input_button_states[#char "M"] & .START { current_tab = .MATERIAL; } if input_button_states[#char "I"] & .START { current_tab = .METADATA; } if input_button_states[#char "P"] & .START { current_tool = .PAINT; } // Hack: These will only work on nordic keyboards as expected... if input_button_states[#char "-"] & .START { current_tool = .ADD; } if input_button_states[#char "/"] & .START { current_tool = .REMOVE; } } } draw_trile_editor_ui :: (theme: *GR.Overall_Theme) { r := GR.get_rect(0, ui_h(5,0), ui_w(20, 20), ui_h(95, 0)); ui_add_mouse_occluder(r); draw_bg_rectangle(r, theme); tab_r := r; tab_r.h = ui_h(3,0); tab_r.w = ui_w(20, 20) / 3; if GR.button(tab_r, "Tool (T)", *t_button_tab(theme, current_tab == .TOOLSET)) { current_tab = .TOOLSET; } tab_r.x += tab_r.w; if GR.button(tab_r, "Material (M)", *t_button_tab(theme, current_tab == .MATERIAL)) { current_tab = .MATERIAL; } tab_r.x += tab_r.w; if GR.button(tab_r, "Meta (I)", *t_button_tab(theme, current_tab == .METADATA)) { current_tab = .METADATA; } r.y += tab_r.h; if current_tab == { case .MATERIAL; draw_material_tab(theme, r); case .TOOLSET; draw_tool_tab(theme, r); } draw_picker(theme); }