365 lines
13 KiB
GDScript
365 lines
13 KiB
GDScript
# 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
|