# MIT License # # Copyright (c) 2023 Mark McKay # https://github.com/blackears/cyclopsLevelBuilder # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. @tool extends Node3D class_name CyclopsGlobalScene @export var selection_color:Color = Color(1, .5, .5, 1) @export var default_material:Material = preload("res://addons/cyclops_level_builder/materials/grid.tres") @export var selection_rect_material:Material = preload("res://addons/cyclops_level_builder/materials/selection_rect_material.tres") @export var tool_edit_active_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_edit_active_material.tres") @export var tool_edit_active_fill_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_edit_active_fill_material.tres") @export var tool_edit_selected_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_edit_selected_material.tres") @export var tool_edit_selected_fill_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_edit_selected_fill_material.tres") @export var tool_edit_unselected_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_edit_unselected_material.tres") @export var tool_object_active_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_object_active_material.tres") @export var tool_object_selected_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_object_selected_material.tres") @export var vertex_unselected_material:Material = preload("res://addons/cyclops_level_builder/materials/vertex_unselected_material.tres") @export var vertex_selected_material:Material = preload("res://addons/cyclops_level_builder/materials/vertex_selected_material.tres") @export var vertex_active_material:Material = preload("res://addons/cyclops_level_builder/materials/vertex_active_material.tres") @export var vertex_tool_material:Material = preload("res://addons/cyclops_level_builder/materials/vertex_tool_material.tres") @export var vertex_radius:float = 8 @export var tool_material:Material = preload("res://addons/cyclops_level_builder/materials/tool_material.tres") @export var outline_material:Material = preload("res://addons/cyclops_level_builder/materials/outline_material.tres") var tool_mesh:ImmediateMesh @export var units_font:Font @export var units_font_size:int = 16 #@export var grid_size:int = 0 @export var drag_angle_limit:float = deg_to_rad(5) const SNAPPING_ENABLED:String = "snapping/enabled" const SNAPPING_GRID_UNIT_SIZE:String = "snapping/grid/unit_size" const SNAPPING_GRID_USE_SUBDIVISIONS:String = "snapping/grid/use_subdivisions" const SNAPPING_GRID_SUBDIVISIONS:String = "snapping/grid/subdivisions" const SNAPPING_GRID_POWER_OF_TWO_SCALE:String = "snapping/grid/power_of_two_scale" const SNAPPING_GRID_TRANSFORM:String = "snapping/grid/transform" const SNAPPING_GRID_ANGLE:String = "snapping/grid/angle" @export_file("*.config") var settings_file:String = "cyclops_settings.config" var settings:CyclopsSettings = CyclopsSettings.new() signal xray_mode_changed(value:bool) @export var xray_mode:bool = false: get: return xray_mode set(value): if xray_mode != value: xray_mode = value xray_mode_changed.emit(value) var unit_sphere:GeometryMesh var builder:CyclopsLevelBuilder # Called when the node enters the scene tree for the first time. func _ready(): init_settings() unit_sphere = MathGeometry.unit_sphere() tool_mesh = ImmediateMesh.new() $ToolInstance3D.mesh = tool_mesh if FileAccess.file_exists(settings_file): settings.load_from_file(settings_file) func init_settings(): settings.add_setting(SNAPPING_ENABLED, true, TYPE_BOOL) settings.add_setting(SNAPPING_GRID_UNIT_SIZE, 1, TYPE_FLOAT) settings.add_setting(SNAPPING_GRID_POWER_OF_TWO_SCALE, 0, TYPE_INT) settings.add_setting(SNAPPING_GRID_USE_SUBDIVISIONS, false, TYPE_BOOL) settings.add_setting(SNAPPING_GRID_SUBDIVISIONS, 10, TYPE_INT) settings.add_setting(SNAPPING_GRID_TRANSFORM, Transform3D.IDENTITY, TYPE_TRANSFORM3D) settings.add_setting(SNAPPING_GRID_ANGLE, 15, TYPE_FLOAT) func save_settings(): #print("saving ", settings_file) settings.save_to_file(settings_file) func calc_snap_to_grid_util(): var snap_to_grid_util:SnapToGridUtil = SnapToGridUtil.new() #print("calc_snap_to_grid_util") snap_to_grid_util.unit_size = settings.get_property(SNAPPING_GRID_UNIT_SIZE) #print("unit_size ", snap_to_grid_util.unit_size) snap_to_grid_util.power_of_two_scale = settings.get_property(SNAPPING_GRID_POWER_OF_TWO_SCALE) #print("power_of_two_scale ", snap_to_grid_util.power_of_two_scale) snap_to_grid_util.use_subdivisions = settings.get_property(SNAPPING_GRID_USE_SUBDIVISIONS) snap_to_grid_util.grid_subdivisions = settings.get_property(SNAPPING_GRID_SUBDIVISIONS) snap_to_grid_util.grid_transform = settings.get_property(SNAPPING_GRID_TRANSFORM) return snap_to_grid_util #Called by CyclopsLevelBuilder to draw 2D components func draw_over_viewport(overlay:Control): pass func draw_line(p0:Vector3, p1:Vector3, mat:Material): tool_mesh.surface_begin(Mesh.PRIMITIVE_LINES, mat) tool_mesh.surface_add_vertex(p0) tool_mesh.surface_add_vertex(p1) tool_mesh.surface_end() func draw_loop(points:PackedVector3Array, closed:bool = true, mat:Material = null): if points.is_empty(): return tool_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, mat) for p in points: tool_mesh.surface_add_vertex(p) if closed: tool_mesh.surface_add_vertex(points[0]) tool_mesh.surface_end() func draw_wireframe(points:PackedVector3Array, edges:PackedInt32Array, mat:Material = null, vertex_mat = null): for p in points: draw_vertex(p, vertex_mat) tool_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, mat) for e_idx in edges: tool_mesh.surface_add_vertex(points[e_idx]) tool_mesh.surface_end() func draw_prism(points:PackedVector3Array, extrude:Vector3, mat:Material = null, vertex_mat = null): for p in points: draw_vertex(p, vertex_mat) draw_vertex(p + extrude, vertex_mat) #Bottom loop tool_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, mat) for p in points: tool_mesh.surface_add_vertex(p) tool_mesh.surface_add_vertex(points[0]) tool_mesh.surface_end() #Top loop tool_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, mat) for p in points: tool_mesh.surface_add_vertex(p + extrude) tool_mesh.surface_add_vertex(points[0] + extrude) tool_mesh.surface_end() #Sides tool_mesh.surface_begin(Mesh.PRIMITIVE_LINES, mat) for p in points: tool_mesh.surface_add_vertex(p) tool_mesh.surface_add_vertex(p + extrude) tool_mesh.surface_end() func draw_triangles(tri_points:PackedVector3Array, mat:Material = null): tool_mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES, mat) for p in tri_points: tool_mesh.surface_add_vertex(p) tool_mesh.surface_end() func draw_rect(start:Vector3, end:Vector3, mat:Material = null, vertex_mat:Material = null): var p0:Vector3 = start var p2:Vector3 = end var p1:Vector3 = Vector3(p0.x, p0.y, p2.z) var p3:Vector3 = Vector3(p2.x, p0.y, p0.z) draw_vertex(p0, vertex_mat) draw_vertex(p1, vertex_mat) draw_vertex(p2, vertex_mat) draw_vertex(p3, vertex_mat) tool_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, mat) tool_mesh.surface_add_vertex(p0) tool_mesh.surface_add_vertex(p1) tool_mesh.surface_add_vertex(p2) tool_mesh.surface_add_vertex(p3) tool_mesh.surface_add_vertex(p0) tool_mesh.surface_end() func clear_tool_mesh(): #tool_mesh = ImmediateMesh.new() #$ToolInstance3D.mesh = tool_mesh tool_mesh.clear_surfaces() for child in %VertexGroup.get_children(): %VertexGroup.remove_child(child) child.queue_free() #print("clear") %cyclops_overlay.clear() func draw_text(text:String, pos:Vector2, font:Font, font_size:float): %cyclops_overlay.draw_text(text, pos, font, font_size) # Draws the bounding box for the points [p0, p1, p2] func draw_cube(p0:Vector3, p1:Vector3, p2:Vector3, mat:Material = null, vertex_mat:Material = null): # print ("draw_cube %s %s %s" % [p0, p1, p2]) var bounds:AABB = AABB(p0, Vector3.ZERO) bounds = bounds.expand(p1) bounds = bounds.expand(p2) var p000:Vector3 = bounds.position var p111:Vector3 = bounds.end var p001:Vector3 = Vector3(p000.x, p000.y, p111.z) var p010:Vector3 = Vector3(p000.x, p111.y, p000.z) var p011:Vector3 = Vector3(p000.x, p111.y, p111.z) var p100:Vector3 = Vector3(p111.x, p000.y, p000.z) var p101:Vector3 = Vector3(p111.x, p000.y, p111.z) var p110:Vector3 = Vector3(p111.x, p111.y, p000.z) draw_vertex(p000, vertex_mat) draw_vertex(p001, vertex_mat) draw_vertex(p010, vertex_mat) draw_vertex(p011, vertex_mat) draw_vertex(p100, vertex_mat) draw_vertex(p101, vertex_mat) draw_vertex(p110, vertex_mat) draw_vertex(p111, vertex_mat) tool_mesh.surface_begin(Mesh.PRIMITIVE_LINES, mat) tool_mesh.surface_add_vertex(p000) tool_mesh.surface_add_vertex(p001) tool_mesh.surface_add_vertex(p000) tool_mesh.surface_add_vertex(p100) tool_mesh.surface_add_vertex(p101) tool_mesh.surface_add_vertex(p001) tool_mesh.surface_add_vertex(p101) tool_mesh.surface_add_vertex(p100) tool_mesh.surface_add_vertex(p010) tool_mesh.surface_add_vertex(p011) tool_mesh.surface_add_vertex(p010) tool_mesh.surface_add_vertex(p110) tool_mesh.surface_add_vertex(p111) tool_mesh.surface_add_vertex(p011) tool_mesh.surface_add_vertex(p111) tool_mesh.surface_add_vertex(p110) tool_mesh.surface_add_vertex(p000) tool_mesh.surface_add_vertex(p010) tool_mesh.surface_add_vertex(p100) tool_mesh.surface_add_vertex(p110) tool_mesh.surface_add_vertex(p101) tool_mesh.surface_add_vertex(p111) tool_mesh.surface_add_vertex(p001) tool_mesh.surface_add_vertex(p011) tool_mesh.surface_end() #$ToolInstance3D.mesh = mesh func draw_points(points:PackedVector3Array, vertex_mat:Material = null): draw_vertices(points, vertex_mat) func draw_vertex(position:Vector3, mat:Material = null): draw_vertices([position], mat) func draw_vertices(vertices:PackedVector3Array, mat:Material = null): var arr_mesh = ArrayMesh.new() var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_POINTS, arrays) var mesh_inst = MeshInstance3D.new() mesh_inst.mesh = arr_mesh mesh_inst.material_override = mat %VertexGroup.add_child(mesh_inst) func draw_sphere(xform:Transform3D = Transform3D.IDENTITY, material:Material = null, segs_lat:int = 6, segs_long:int = 8): unit_sphere.append_to_immediate_mesh(tool_mesh, material, xform) func draw_selected_blocks(viewport_camera:Camera3D): var global_scene:CyclopsGlobalScene = builder.get_node("/root/CyclopsAutoload") var blocks:Array[CyclopsBlock] = builder.get_selected_blocks() var active_block:CyclopsBlock = builder.get_active_block() for block in blocks: var active:bool = block == active_block var mat:Material = global_scene.tool_object_active_material if active else global_scene.tool_object_selected_material #Selection highlight outline block.append_mesh_outline(tool_mesh, viewport_camera, block.global_transform, mat) #block.draw_unit_labels(viewport_camera, block.global_transform) func draw_screen_rect(viewport_camera:Camera3D, p00:Vector2, p11:Vector2, material:Material): var global_scene:CyclopsGlobalScene = builder.get_node("/root/CyclopsAutoload") var p01:Vector2 = Vector2(p00.x, p11.y) var p10:Vector2 = Vector2(p11.x, p00.y) var z_pos:float = (viewport_camera.near + viewport_camera.far) / 2 tool_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, material) for p in [p00, p01, p11, p10, p00]: var p_proj:Vector3 = viewport_camera.project_position(p, z_pos) # print("p_proj %s" % p_proj) tool_mesh.surface_add_vertex(p_proj) tool_mesh.surface_end() func set_custom_gizmo(gizmo:Node3D): for child in %GizmoControl.get_children(): %GizmoControl.remove_child(child) if gizmo: # print("Setting gizmo") %GizmoControl.add_child(gizmo) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): pass