Adds missing data
This commit is contained in:
parent
e6391d9fdd
commit
53cdcc3433
620 changed files with 47293 additions and 151 deletions
86
addons/cyclops_level_builder/commands/cmd_add_block.gd
Normal file
86
addons/cyclops_level_builder/commands/cmd_add_block.gd
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# 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
|
||||
class_name CommandAddBlock
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public data to set before activating command
|
||||
var blocks_root_path:NodePath
|
||||
#var origin:Vector3
|
||||
var block_name:String
|
||||
var bounds:AABB
|
||||
var material_path:String
|
||||
var uv_transform:Transform2D = Transform2D.IDENTITY
|
||||
var collision_type:Collision.Type = Collision.Type.STATIC
|
||||
var collision_layers:int = 1
|
||||
var collision_mask:int = 1
|
||||
|
||||
#Private data
|
||||
var block_path:NodePath
|
||||
|
||||
func _init():
|
||||
command_name = "Add block"
|
||||
|
||||
func do_it():
|
||||
var block:CyclopsBlock = preload("res://addons/cyclops_level_builder/nodes/cyclops_block.gd").new()
|
||||
|
||||
#var blocks_root:Node = builder.get_block_add_parent()
|
||||
var block_parent:Node = builder.get_node(blocks_root_path)
|
||||
|
||||
block_parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = block_name
|
||||
block.collision_type = collision_type
|
||||
block.collision_layer = collision_layers
|
||||
block.collision_mask = collision_mask
|
||||
|
||||
var material_id:int = -1
|
||||
if ResourceLoader.exists(material_path):
|
||||
var mat = load(material_path)
|
||||
if mat is Material:
|
||||
material_id = 0
|
||||
block.materials.append(mat)
|
||||
|
||||
|
||||
#print("Block root %s" % block)
|
||||
#print("Create bounds %s" % bounds)
|
||||
#var parent_xform:Transform3D = node_global_transform(block_parent)
|
||||
#var vol_xform:Transform3D = Transform3D(Basis(), -bounds.position)
|
||||
|
||||
var mesh:ConvexVolume = ConvexVolume.new()
|
||||
mesh.init_block(bounds, uv_transform, material_id)
|
||||
mesh.translate(-bounds.position)
|
||||
|
||||
block.mesh_vector_data = mesh.to_mesh_vector_data()
|
||||
# block.block_data = mesh.to_convex_block_data()
|
||||
block_path = block.get_path()
|
||||
block.global_transform = Transform3D(Basis(), bounds.position)
|
||||
|
||||
# print("AddBlockCommand do_it() %s %s" % [block_inst_id, bounds])
|
||||
|
||||
func undo_it():
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.queue_free()
|
||||
|
||||
# print("AddBlockCommand undo_it()")
|
||||
115
addons/cyclops_level_builder/commands/cmd_add_cylinder.gd
Normal file
115
addons/cyclops_level_builder/commands/cmd_add_cylinder.gd
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# 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
|
||||
class_name CommandAddCylinder
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public data to set before activating command
|
||||
var blocks_root_path:NodePath
|
||||
#var block_name:String
|
||||
var block_name_prefix:String = "Block_"
|
||||
var origin:Vector3
|
||||
var axis_normal:Vector3
|
||||
var height:float
|
||||
var radius_inner:float
|
||||
var radius_outer:float
|
||||
var segments:int
|
||||
var tube:bool = false
|
||||
|
||||
var material_path:String
|
||||
var uv_transform:Transform2D = Transform2D.IDENTITY
|
||||
var collision_type:Collision.Type = Collision.Type.STATIC
|
||||
var collision_layers:int = 1
|
||||
var collision_mask:int = 1
|
||||
|
||||
#Private data
|
||||
var block_paths:Array[NodePath]
|
||||
|
||||
func _init():
|
||||
command_name = "Add cylinder"
|
||||
|
||||
func create_block(blocks_root:Node, set_pivot_xform:Transform3D, mat:Material)->CyclopsBlock:
|
||||
var block:CyclopsBlock = preload("res://addons/cyclops_level_builder/nodes/cyclops_block.gd").new()
|
||||
blocks_root.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = GeneralUtil.find_unique_name(blocks_root, block_name_prefix)
|
||||
block.global_transform = set_pivot_xform.affine_inverse()
|
||||
block.collision_type = collision_type
|
||||
block.collision_layer = collision_layers
|
||||
block.collision_mask = collision_mask
|
||||
|
||||
if mat:
|
||||
block.materials.append(mat)
|
||||
|
||||
return block
|
||||
|
||||
|
||||
func do_it():
|
||||
# var blocks_root:CyclopsBlocks = builder.get_node(blocks_root_path)
|
||||
var blocks_root:Node = builder.get_node(blocks_root_path)
|
||||
|
||||
var material:Material
|
||||
var material_id:int = -1
|
||||
if ResourceLoader.exists(material_path):
|
||||
var mat = load(material_path)
|
||||
if mat is Material:
|
||||
material_id = 0
|
||||
material = mat
|
||||
|
||||
var set_pivot_xform:Transform3D = Transform3D(Basis.IDENTITY, -origin)
|
||||
|
||||
if tube:
|
||||
var bounding_points_inner:PackedVector3Array = MathUtil.create_circle_points(origin, axis_normal, radius_inner, segments)
|
||||
var bounding_points_outer:PackedVector3Array = MathUtil.create_circle_points(origin, axis_normal, radius_outer, segments)
|
||||
|
||||
for p_idx0 in bounding_points_inner.size():
|
||||
var p_idx1:int = wrap(p_idx0 + 1, 0, bounding_points_inner.size())
|
||||
|
||||
var block:CyclopsBlock = create_block(blocks_root, set_pivot_xform, material)
|
||||
|
||||
var mesh:ConvexVolume = ConvexVolume.new()
|
||||
var base_points:PackedVector3Array = [bounding_points_inner[p_idx0], bounding_points_inner[p_idx1], bounding_points_outer[p_idx1], bounding_points_outer[p_idx0]]
|
||||
|
||||
mesh.init_prism(base_points, axis_normal * height, uv_transform, material_id)
|
||||
mesh.transform(set_pivot_xform)
|
||||
|
||||
# block.block_data = mesh.to_convex_block_data()
|
||||
block.mesh_vector_data = mesh.to_mesh_vector_data()
|
||||
block_paths.append(block.get_path())
|
||||
|
||||
else:
|
||||
var block:CyclopsBlock = create_block(blocks_root, set_pivot_xform, material)
|
||||
|
||||
var bounding_points:PackedVector3Array = MathUtil.create_circle_points(origin, axis_normal, radius_outer, segments)
|
||||
var mesh:ConvexVolume = ConvexVolume.new()
|
||||
mesh.init_prism(bounding_points, axis_normal * height, uv_transform, material_id)
|
||||
mesh.transform(set_pivot_xform)
|
||||
|
||||
block.mesh_vector_data = mesh.to_mesh_vector_data()
|
||||
block_paths.append(block.get_path())
|
||||
|
||||
func undo_it():
|
||||
for path in block_paths:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
block.queue_free()
|
||||
80
addons/cyclops_level_builder/commands/cmd_add_prism.gd
Normal file
80
addons/cyclops_level_builder/commands/cmd_add_prism.gd
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# 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
|
||||
class_name CommandAddPrism
|
||||
extends CyclopsCommand
|
||||
|
||||
@export var blocks_root_path:NodePath
|
||||
@export var block_name:String
|
||||
@export var base_polygon:PackedVector3Array
|
||||
@export var extrude:Vector3
|
||||
#var local_transform:Transform3D
|
||||
@export var uv_transform:Transform2D
|
||||
@export var material_path:String
|
||||
@export var collision_type:Collision.Type = Collision.Type.STATIC
|
||||
@export var collision_layers:int = 1
|
||||
@export var collision_mask:int = 1
|
||||
|
||||
#Private
|
||||
var block_path:NodePath
|
||||
|
||||
func _init():
|
||||
command_name = "Add prism"
|
||||
|
||||
func do_it():
|
||||
var block:CyclopsBlock = preload("res://addons/cyclops_level_builder/nodes/cyclops_block.gd").new()
|
||||
|
||||
var blocks_root:Node = builder.get_node(blocks_root_path)
|
||||
blocks_root.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = block_name
|
||||
#block.transform = local_transform
|
||||
block.collision_type = collision_type
|
||||
block.collision_layer = collision_layers
|
||||
block.collision_mask = collision_mask
|
||||
|
||||
var material_id:int = -1
|
||||
if ResourceLoader.exists(material_path):
|
||||
var mat = load(material_path)
|
||||
if mat is Material:
|
||||
material_id = 0
|
||||
block.materials.append(mat)
|
||||
|
||||
var set_pivot_xform:Transform3D = Transform3D(Basis.IDENTITY, -base_polygon[0])
|
||||
|
||||
var mesh:ConvexVolume = ConvexVolume.new()
|
||||
mesh.init_prism(base_polygon, extrude, uv_transform, material_id)
|
||||
mesh.transform(set_pivot_xform)
|
||||
|
||||
block.mesh_vector_data = mesh.to_mesh_vector_data()
|
||||
block_path = block.get_path()
|
||||
|
||||
block.global_transform = set_pivot_xform.affine_inverse()
|
||||
# print("AddBlockCommand do_it() %s %s" % [block_inst_id, bounds])
|
||||
|
||||
func undo_it():
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.queue_free()
|
||||
|
||||
# print("AddBlockCommand undo_it()")
|
||||
139
addons/cyclops_level_builder/commands/cmd_add_stairs.gd
Normal file
139
addons/cyclops_level_builder/commands/cmd_add_stairs.gd
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# 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
|
||||
class_name CommandAddStairs
|
||||
extends CyclopsCommand
|
||||
|
||||
#var blocks_root_inst_id:int
|
||||
var blocks_root_path:NodePath
|
||||
var block_name_prefix:String
|
||||
var floor_normal:Vector3
|
||||
var drag_origin:Vector3
|
||||
var base_drag_cur:Vector3
|
||||
var block_drag_cur:Vector3
|
||||
var step_height:float = .25
|
||||
var step_depth:float = .5
|
||||
var direction:int = 0
|
||||
|
||||
var uv_transform:Transform2D
|
||||
var material_path:String
|
||||
var collision_type:Collision.Type = Collision.Type.STATIC
|
||||
var collision_layers:int = 1
|
||||
var collision_mask:int = 1
|
||||
|
||||
#Private data
|
||||
var block_paths:Array[NodePath]
|
||||
|
||||
func _init():
|
||||
command_name = "Add stairs"
|
||||
|
||||
func create_block(blocks_root:Node, mat:Material)->CyclopsBlock:
|
||||
var block:CyclopsBlock = preload("res://addons/cyclops_level_builder/nodes/cyclops_block.gd").new()
|
||||
blocks_root.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = GeneralUtil.find_unique_name(blocks_root, block_name_prefix)
|
||||
block.collision_type = collision_type
|
||||
block.collision_layer = collision_layers
|
||||
block.collision_mask = collision_mask
|
||||
|
||||
if mat:
|
||||
block.materials.append(mat)
|
||||
|
||||
return block
|
||||
|
||||
|
||||
func do_it():
|
||||
var blocks_root:Node = builder.get_node(blocks_root_path)
|
||||
|
||||
var material:Material
|
||||
var material_id:int = -1
|
||||
if ResourceLoader.exists(material_path):
|
||||
var mat = load(material_path)
|
||||
if mat is Material:
|
||||
material_id = 0
|
||||
material = mat
|
||||
|
||||
var tan_bi:Array[Vector3] = MathUtil.get_axis_aligned_tangent_and_binormal(floor_normal)
|
||||
var u_normal:Vector3 = tan_bi[0]
|
||||
var v_normal:Vector3 = tan_bi[1]
|
||||
|
||||
#Rotate ccw by 90 degree increments
|
||||
match direction:
|
||||
1:
|
||||
var tmp:Vector3 = u_normal
|
||||
u_normal = -v_normal
|
||||
v_normal = tmp
|
||||
2:
|
||||
u_normal = -u_normal
|
||||
v_normal = -v_normal
|
||||
3:
|
||||
var tmp:Vector3 = -u_normal
|
||||
u_normal = v_normal
|
||||
v_normal = tmp
|
||||
|
||||
var u_span:Vector3 = (base_drag_cur - drag_origin).project(u_normal)
|
||||
var v_span:Vector3 = (base_drag_cur - drag_origin).project(v_normal)
|
||||
|
||||
var stairs_origin:Vector3 = drag_origin
|
||||
if u_span.dot(u_normal) < 0:
|
||||
stairs_origin += u_span
|
||||
u_span = -u_span
|
||||
if v_span.dot(v_normal) < 0:
|
||||
stairs_origin += v_span
|
||||
v_span = -v_span
|
||||
|
||||
#Stairs should ascend along v axis
|
||||
var height_offset = block_drag_cur - base_drag_cur
|
||||
if height_offset.dot(floor_normal) < 0:
|
||||
return
|
||||
var num_steps:int = min(v_span.length() / step_depth, height_offset.length() / step_height)
|
||||
|
||||
var max_height:float = floor(height_offset.length() / step_height) * step_height
|
||||
|
||||
var step_span:Vector3 = v_normal * step_depth
|
||||
for i in num_steps:
|
||||
var base_points:PackedVector3Array = [stairs_origin + step_span * i, \
|
||||
stairs_origin + u_span + step_span * i, \
|
||||
stairs_origin + u_span + step_span * (i + 1), \
|
||||
stairs_origin + step_span * (i + 1)]
|
||||
|
||||
var pivot_xform:Transform3D = Transform3D(Basis.IDENTITY, -base_points[0])
|
||||
|
||||
var mesh:ConvexVolume = ConvexVolume.new()
|
||||
mesh.init_prism(base_points, \
|
||||
floor_normal * (max_height - step_height * i), \
|
||||
uv_transform, material_id)
|
||||
mesh.transform(pivot_xform)
|
||||
|
||||
var block:CyclopsBlock = create_block(blocks_root, material)
|
||||
|
||||
block.mesh_vector_data = mesh.to_mesh_vector_data()
|
||||
block.global_transform = pivot_xform.affine_inverse()
|
||||
block_paths.append(block.get_path())
|
||||
|
||||
|
||||
func undo_it():
|
||||
for path in block_paths:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
block.queue_free()
|
||||
74
addons/cyclops_level_builder/commands/cmd_add_vertices.gd
Normal file
74
addons/cyclops_level_builder/commands/cmd_add_vertices.gd
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# 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
|
||||
class_name CommandAddVertices
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
#Public
|
||||
var points_to_add:PackedVector3Array
|
||||
var block_path:NodePath
|
||||
|
||||
#Private
|
||||
var tracked_block_data:MeshVectorData
|
||||
var selected_points:PackedVector3Array
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Add vertices"
|
||||
|
||||
func do_it():
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
if !tracked_block_data:
|
||||
var tracked_vol:ConvexVolume = block.control_mesh
|
||||
tracked_block_data = tracked_vol.to_mesh_vector_data()
|
||||
|
||||
for v in tracked_vol.vertices:
|
||||
if v.selected:
|
||||
selected_points.append(v.point)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(tracked_block_data)
|
||||
|
||||
var point_list:PackedVector3Array = vol.get_points()
|
||||
var local_points = block.global_transform.affine_inverse() * points_to_add
|
||||
point_list.append_array(local_points)
|
||||
|
||||
var new_vol:ConvexVolume = ConvexVolume.new()
|
||||
new_vol.init_from_points(point_list)
|
||||
new_vol.copy_face_attributes(vol)
|
||||
|
||||
|
||||
for v_idx in new_vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = new_vol.vertices[v_idx]
|
||||
if selected_points.has(v.point):
|
||||
v.selected = true
|
||||
|
||||
block.mesh_vector_data = new_vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
func undo_it():
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = tracked_block_data
|
||||
106
addons/cyclops_level_builder/commands/cmd_clip_block.gd
Normal file
106
addons/cyclops_level_builder/commands/cmd_clip_block.gd
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# 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
|
||||
class_name CommandClipBlock
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public data to set before activating command
|
||||
var blocks_root_path:NodePath
|
||||
var block_path:NodePath
|
||||
var cut_plane:Plane
|
||||
var uv_transform:Transform2D = Transform2D.IDENTITY
|
||||
var material_path:String = ""
|
||||
|
||||
#Private
|
||||
var block_sibling_name:String
|
||||
var old_block_data:MeshVectorData
|
||||
var old_mat_list:Array[Material]
|
||||
var block_sibling_path:NodePath
|
||||
|
||||
func _init():
|
||||
command_name = "Clip block"
|
||||
|
||||
func get_material_index(mat_list:Array[Material], path:String)->int:
|
||||
if path.is_empty():
|
||||
return -1
|
||||
for i in mat_list.size():
|
||||
var mat:Material = mat_list[i]
|
||||
if mat != null && mat.resource_path == path:
|
||||
return i
|
||||
return -1
|
||||
|
||||
func do_it():
|
||||
var blocks_root:Node = builder.get_node(blocks_root_path)
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
old_block_data = block.mesh_vector_data.duplicate()
|
||||
old_mat_list = block.materials.duplicate()
|
||||
|
||||
var new_mat_list0:Array[Material] = old_mat_list.duplicate()
|
||||
|
||||
var cut_mat_idx = get_material_index(old_mat_list, material_path)
|
||||
if cut_mat_idx == -1:
|
||||
var mat = load(material_path)
|
||||
if mat is Material:
|
||||
cut_mat_idx = new_mat_list0.size()
|
||||
new_mat_list0.append(mat)
|
||||
|
||||
|
||||
var new_mat_list1:Array[Material] = new_mat_list0.duplicate()
|
||||
|
||||
#var cut_plane_reverse:Plane = Plane(-cut_plane.normal, cut_plane.get_center())
|
||||
|
||||
var w2l:Transform3D = block.global_transform.affine_inverse()
|
||||
var cut_plane_local:Plane = w2l * cut_plane
|
||||
|
||||
var vol0:ConvexVolume = block.control_mesh.cut_with_plane(cut_plane_local, uv_transform, cut_mat_idx)
|
||||
var vol1:ConvexVolume = block.control_mesh.cut_with_plane(MathUtil.flip_plane(cut_plane_local), uv_transform, cut_mat_idx)
|
||||
|
||||
#Set data of existing block
|
||||
block.mesh_vector_data = vol0.to_mesh_vector_data()
|
||||
block.materials = new_mat_list0
|
||||
|
||||
#Create second block
|
||||
var block_sibling:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
|
||||
blocks_root.add_child(block_sibling)
|
||||
block_sibling.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block_sibling.name = block_sibling_name
|
||||
block_sibling.global_transform = block.global_transform
|
||||
#block_sibling.selected = block.selected
|
||||
block_sibling_path = block_sibling.get_path()
|
||||
|
||||
block_sibling.mesh_vector_data = vol1.to_mesh_vector_data()
|
||||
block_sibling.materials = new_mat_list1
|
||||
|
||||
|
||||
func undo_it():
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = old_block_data
|
||||
block.materials = old_mat_list.duplicate()
|
||||
|
||||
var block_sibling:CyclopsBlock = builder.get_node(block_sibling_path)
|
||||
block_sibling.queue_free()
|
||||
|
||||
|
||||
82
addons/cyclops_level_builder/commands/cmd_delete_blocks.gd
Normal file
82
addons/cyclops_level_builder/commands/cmd_delete_blocks.gd
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# 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
|
||||
class_name CommandDeleteBlocks
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public
|
||||
var block_paths:Array[NodePath]
|
||||
|
||||
#Private
|
||||
var tracked_blocks:Array[TrackedBlock]
|
||||
|
||||
func _init():
|
||||
command_name = "Delete blocks"
|
||||
|
||||
func will_change_anything():
|
||||
if !block_paths.is_empty():
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func do_it():
|
||||
#print("Delete do_it")
|
||||
|
||||
if tracked_blocks.is_empty():
|
||||
var points:PackedVector3Array
|
||||
|
||||
for path in block_paths:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
var tracker:TrackedBlock = TrackedBlock.new(block)
|
||||
tracked_blocks.append(tracker)
|
||||
|
||||
#Delete source blocks
|
||||
for block_path in block_paths:
|
||||
var del_block:CyclopsBlock = builder.get_node(block_path)
|
||||
del_block.get_parent().remove_child(del_block)
|
||||
del_block.queue_free()
|
||||
|
||||
|
||||
func undo_it():
|
||||
#print("Delete undo_it")
|
||||
for tracked in tracked_blocks:
|
||||
var parent = builder.get_node(tracked.path_parent)
|
||||
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
block.mesh_vector_data = tracked.data
|
||||
block.materials = tracked.materials
|
||||
block.name = tracked.name
|
||||
#block.selected = tracked.selected
|
||||
block.collision_type = tracked.collision_type
|
||||
block.collision_layer = tracked.collision_layers
|
||||
block.collision_mask = tracked.collision_mask
|
||||
|
||||
parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.global_transform = tracked.world_xform
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
# 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
|
||||
class_name CommandDuplicateBlocks
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public
|
||||
var blocks_root_path:NodePath
|
||||
var blocks_to_duplicate:Array[NodePath]
|
||||
var move_offset:Vector3
|
||||
var lock_uvs:bool
|
||||
|
||||
#Private
|
||||
class BlockInfo extends RefCounted:
|
||||
var new_block:CyclopsBlock
|
||||
var source_data:MeshVectorData
|
||||
var source_global_transform:Transform3D
|
||||
|
||||
func _init(new_block:CyclopsBlock, source_data:MeshVectorData, source_global_transform:Transform3D):
|
||||
self.new_block = new_block
|
||||
self.source_data = source_data
|
||||
self.source_global_transform = source_global_transform
|
||||
|
||||
var added_blocks:Array[BlockInfo]
|
||||
|
||||
func will_change_anything():
|
||||
return !added_blocks.is_empty()
|
||||
|
||||
func do_it():
|
||||
if added_blocks.is_empty():
|
||||
|
||||
#Create new blocks
|
||||
for block_path in blocks_to_duplicate:
|
||||
var new_block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
|
||||
var source_block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var blocks_root:Node = builder.get_node(blocks_root_path)
|
||||
new_block.name = GeneralUtil.find_unique_name(blocks_root, source_block.name)
|
||||
blocks_root.add_child(new_block)
|
||||
new_block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
new_block.global_transform = source_block.global_transform
|
||||
new_block.mesh_vector_data = source_block.mesh_vector_data.duplicate()
|
||||
|
||||
var info:BlockInfo = BlockInfo.new(new_block, source_block.mesh_vector_data, source_block.global_transform)
|
||||
new_block.materials = source_block.materials
|
||||
#new_block.selected = true
|
||||
|
||||
added_blocks.append(info)
|
||||
|
||||
for path in blocks_to_duplicate:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
#block.selected = false
|
||||
|
||||
for info in added_blocks:
|
||||
|
||||
var new_xform:Transform3D = info.source_global_transform.translated(move_offset)
|
||||
info.new_block.global_transform = new_xform
|
||||
|
||||
|
||||
func undo_it():
|
||||
for block in added_blocks:
|
||||
block.new_block.queue_free()
|
||||
added_blocks = []
|
||||
|
||||
for path in blocks_to_duplicate:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
#block.selected = true
|
||||
|
||||
152
addons/cyclops_level_builder/commands/cmd_intersect_block.gd
Normal file
152
addons/cyclops_level_builder/commands/cmd_intersect_block.gd
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# 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
|
||||
class_name CommandIntersectBlock
|
||||
extends CyclopsCommand
|
||||
|
||||
class NewBlockInfo extends RefCounted:
|
||||
var data:MeshVectorData
|
||||
var materials:Array[Material]
|
||||
var path:NodePath
|
||||
var xform:Transform3D
|
||||
#var centroid:Vector3
|
||||
|
||||
#Public
|
||||
var block_paths:Array[NodePath]
|
||||
var main_block_path:NodePath
|
||||
var block_name_prefix:String = "Block_"
|
||||
|
||||
#Private
|
||||
var start_blocks:Array[TrackedBlock]
|
||||
var main_block_cache:TrackedBlock
|
||||
#var added_blocks:Array[NewBlockInfo]
|
||||
var added_block:NewBlockInfo
|
||||
|
||||
func _init():
|
||||
command_name = "Intersect blocks"
|
||||
|
||||
func restore_tracked_block(tracked:TrackedBlock)->CyclopsBlock:
|
||||
var parent = builder.get_node(tracked.path_parent)
|
||||
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
block.mesh_vector_data = tracked.data
|
||||
block.materials = tracked.materials
|
||||
block.name = tracked.name
|
||||
#block.selected = tracked.selected
|
||||
block.global_transform = tracked.world_xform
|
||||
block.collision_type = tracked.collision_type
|
||||
block.collision_layer = tracked.collision_layers
|
||||
block.collision_mask = tracked.collision_mask
|
||||
|
||||
parent.add_child(block)
|
||||
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
|
||||
if tracked.selected:
|
||||
var selection:EditorSelection = builder.get_editor_interface().get_selection()
|
||||
selection.add_node(block)
|
||||
|
||||
return block
|
||||
|
||||
func will_change_anything()->bool:
|
||||
var main_block:CyclopsBlock = builder.get_node(main_block_path)
|
||||
var main_vol:ConvexVolume = main_block.control_mesh
|
||||
main_vol = main_vol.transformed(main_block.global_transform)
|
||||
|
||||
if block_paths.is_empty():
|
||||
return false
|
||||
|
||||
for minuend_path in block_paths:
|
||||
var minuend_block:CyclopsBlock = builder.get_node(minuend_path)
|
||||
var minuend_vol:ConvexVolume = minuend_block.control_mesh
|
||||
minuend_vol = minuend_vol.transformed(minuend_block.global_transform)
|
||||
|
||||
if minuend_vol.intersects_convex_volume(main_vol):
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func do_it():
|
||||
var main_block:CyclopsBlock = builder.get_node(main_block_path)
|
||||
var snap_to_grid_util:SnapToGridUtil = CyclopsAutoload.calc_snap_to_grid_util()
|
||||
|
||||
if start_blocks.is_empty():
|
||||
var main_vol:ConvexVolume = main_block.control_mesh
|
||||
main_block_cache = TrackedBlock.new(main_block)
|
||||
main_vol = main_vol.transformed(main_block.global_transform)
|
||||
|
||||
for path in block_paths:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
|
||||
var minuend_vol:ConvexVolume = block.control_mesh
|
||||
minuend_vol = minuend_vol.transformed(block.global_transform)
|
||||
if !minuend_vol.intersects_convex_volume(main_vol):
|
||||
continue
|
||||
|
||||
var tracker:TrackedBlock = TrackedBlock.new(block)
|
||||
start_blocks.append(tracker)
|
||||
|
||||
main_vol = minuend_vol.intersect(main_vol)
|
||||
|
||||
|
||||
var block_info:NewBlockInfo = NewBlockInfo.new()
|
||||
block_info.materials = main_block.materials
|
||||
var xform_inv:Transform3D = main_block.global_transform.affine_inverse()
|
||||
main_vol = main_vol.transformed(xform_inv)
|
||||
block_info.data = main_vol.to_mesh_vector_data()
|
||||
block_info.xform = main_block.global_transform
|
||||
added_block = block_info
|
||||
|
||||
#Delete source blocks
|
||||
for block_info in start_blocks:
|
||||
var del_block:CyclopsBlock = builder.get_node(block_info.path)
|
||||
del_block.queue_free()
|
||||
|
||||
main_block.queue_free()
|
||||
|
||||
#Create blocks
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
var parent:Node = builder.get_node(start_blocks[0].path_parent)
|
||||
parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = GeneralUtil.find_unique_name(parent, block_name_prefix)
|
||||
block.mesh_vector_data = added_block.data
|
||||
block.materials = added_block.materials
|
||||
block.global_transform = added_block.xform
|
||||
|
||||
added_block.path = block.get_path()
|
||||
|
||||
|
||||
|
||||
func undo_it():
|
||||
|
||||
#for info in added_blocks:
|
||||
var added_block_node:CyclopsBlock = builder.get_node(added_block.path)
|
||||
added_block_node.queue_free()
|
||||
|
||||
restore_tracked_block(main_block_cache)
|
||||
|
||||
for tracked in start_blocks:
|
||||
restore_tracked_block(tracked)
|
||||
|
||||
148
addons/cyclops_level_builder/commands/cmd_merge_blocks.gd
Normal file
148
addons/cyclops_level_builder/commands/cmd_merge_blocks.gd
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# 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
|
||||
class_name CommandMergeBlocks
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public
|
||||
var block_paths:Array[NodePath]
|
||||
var block_name_prefix:String = "Block_"
|
||||
|
||||
#Private
|
||||
var tracked_blocks:Array[TrackedBlock]
|
||||
var merged_block_data:MeshVectorData
|
||||
var merged_mat_list:Array[Material]
|
||||
var merged_block_path:NodePath
|
||||
var world_pivot:Vector3
|
||||
|
||||
func _init():
|
||||
command_name = "Merge blocks"
|
||||
|
||||
func get_best_face(centroid:Vector3, ref_list:Array[NodePath])->Array:
|
||||
var best_face:ConvexVolume.FaceInfo
|
||||
var best_dist:float = INF
|
||||
var best_block:CyclopsBlock
|
||||
|
||||
for block_path in ref_list:
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var vol:ConvexVolume = block.control_mesh
|
||||
for f in vol.faces:
|
||||
var face_center:Vector3 = f.get_centroid()
|
||||
var offset:float = centroid.distance_squared_to(face_center)
|
||||
if offset < best_dist:
|
||||
best_dist = offset
|
||||
best_face = f
|
||||
best_block = block
|
||||
|
||||
if best_face.material_id == -1:
|
||||
return [best_face, null]
|
||||
return [best_face, best_block.materials[best_face.material_id]]
|
||||
|
||||
func copy_face_attributes(target:ConvexVolume, ref_list:Array[NodePath])->Array[Material]:
|
||||
var mat_list:Array[Material]
|
||||
|
||||
for f in target.faces:
|
||||
var centroid:Vector3 = f.get_centroid()
|
||||
var res:Array = get_best_face(centroid, ref_list)
|
||||
var ref_face:ConvexVolume.FaceInfo = res[0]
|
||||
var material:Material = res[1]
|
||||
|
||||
var mat_idx:int = -1
|
||||
if material != null:
|
||||
mat_idx = mat_list.find(material)
|
||||
if mat_idx == -1:
|
||||
mat_idx = mat_list.size()
|
||||
mat_list.append(material)
|
||||
|
||||
f.material_id = mat_idx
|
||||
f.uv_transform = ref_face.uv_transform
|
||||
f.selected = ref_face.selected
|
||||
|
||||
return mat_list
|
||||
|
||||
func do_it():
|
||||
|
||||
if tracked_blocks.is_empty():
|
||||
var points:PackedVector3Array
|
||||
|
||||
var first_block:CyclopsBlock = builder.get_node(block_paths[0])
|
||||
world_pivot = first_block.global_transform.origin
|
||||
|
||||
for path in block_paths:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
var tracker:TrackedBlock = TrackedBlock.new(block)
|
||||
tracked_blocks.append(tracker)
|
||||
|
||||
var world_block:ConvexVolume = ConvexVolume.new()
|
||||
world_block.init_from_mesh_vector_data(block.control_mesh.to_mesh_vector_data())
|
||||
world_block.transform(block.global_transform)
|
||||
points.append_array(world_block.get_points())
|
||||
|
||||
var merged_vol:ConvexVolume = ConvexVolume.new()
|
||||
merged_vol.init_from_points(points)
|
||||
merged_mat_list = copy_face_attributes(merged_vol, block_paths)
|
||||
merged_vol.translate(-world_pivot)
|
||||
merged_block_data = merged_vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
|
||||
#Delete source blocks
|
||||
for block_path in block_paths:
|
||||
var del_block:CyclopsBlock = builder.get_node(block_path)
|
||||
del_block.queue_free()
|
||||
|
||||
#Create block
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
var parent:Node = builder.get_node(tracked_blocks[0].path_parent)
|
||||
parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = GeneralUtil.find_unique_name(parent, block_name_prefix)
|
||||
block.mesh_vector_data = merged_block_data
|
||||
block.materials = merged_mat_list
|
||||
block.global_transform = Transform3D.IDENTITY.translated(world_pivot)
|
||||
#block.materials
|
||||
|
||||
merged_block_path = block.get_path()
|
||||
|
||||
func undo_it():
|
||||
# var blocks_root:CyclopsBlocks = builder.get_node(blocks_root_path)
|
||||
var merged_block:CyclopsBlock = builder.get_node(merged_block_path)
|
||||
merged_block.queue_free()
|
||||
|
||||
# for i in blocks_to_merge.size():
|
||||
for tracked in tracked_blocks:
|
||||
var parent = builder.get_node(tracked.path_parent)
|
||||
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
block.mesh_vector_data = tracked.data
|
||||
block.materials = tracked.materials
|
||||
block.name = tracked.name
|
||||
#block.selected = tracked.selected
|
||||
block.global_transform = tracked.world_xform
|
||||
block.collision_type = tracked.collision_type
|
||||
block.collision_layer = tracked.collision_layers
|
||||
block.collision_mask = tracked.collision_mask
|
||||
|
||||
parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
142
addons/cyclops_level_builder/commands/cmd_merge_vertices.gd
Normal file
142
addons/cyclops_level_builder/commands/cmd_merge_vertices.gd
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# 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
|
||||
class_name CommandMergeVertices
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
class BlockVertexChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var vertex_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
#Public
|
||||
var merge_point:Vector3
|
||||
|
||||
enum MergeType { POINT, CENTER, FIRST, LAST }
|
||||
var merge_type:MergeType = MergeType.CENTER
|
||||
|
||||
func add_vertex(block_path:NodePath, index:int):
|
||||
add_vertices(block_path, [index])
|
||||
|
||||
func add_vertices(block_path:NodePath, indices:Array[int]):
|
||||
# print("adding vertex %s %s" % [block_path, indices])
|
||||
var changes:BlockVertexChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockVertexChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data.duplicate()
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.vertex_indices.has(index):
|
||||
changes.vertex_indices.append(index)
|
||||
|
||||
func _init():
|
||||
command_name = "Move vertices"
|
||||
|
||||
|
||||
func do_it():
|
||||
# print("move verts do_it")
|
||||
for block_path in block_map.keys():
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var w2l:Transform3D = block.global_transform.affine_inverse()
|
||||
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
var selected_points:PackedVector3Array
|
||||
var new_points:PackedVector3Array
|
||||
for v_idx in vol.vertices.size():
|
||||
if !rec.vertex_indices.has(v_idx):
|
||||
var p:Vector3 = vol.vertices[v_idx].point
|
||||
new_points.append(p)
|
||||
|
||||
var merge_point_local:Vector3
|
||||
match merge_type:
|
||||
MergeType.POINT:
|
||||
merge_point_local = w2l * merge_point
|
||||
pass
|
||||
MergeType.CENTER:
|
||||
var centroid:Vector3
|
||||
var count:int = 0
|
||||
for v_idx in vol.vertices.size():
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
var p:Vector3 = vol.vertices[v_idx].point
|
||||
centroid += p
|
||||
count += 1
|
||||
centroid /= count
|
||||
merge_point_local = centroid
|
||||
MergeType.FIRST:
|
||||
merge_point_local = vol.vertices[rec.vertex_indices[0]].point
|
||||
MergeType.LAST:
|
||||
merge_point_local = vol.vertices[rec.vertex_indices[-1]].point
|
||||
|
||||
|
||||
new_points.append(merge_point_local)
|
||||
selected_points.append(merge_point_local)
|
||||
|
||||
var new_vol:ConvexVolume = ConvexVolume.new()
|
||||
new_vol.init_from_points(new_points)
|
||||
|
||||
new_vol.copy_face_attributes(vol)
|
||||
|
||||
for v_idx in new_vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = new_vol.vertices[v_idx]
|
||||
# print ("vol point %s " % v.point)
|
||||
if selected_points.has(v.point):
|
||||
# print("set sel")
|
||||
v.selected = true
|
||||
|
||||
block.mesh_vector_data = new_vol.to_mesh_vector_data()
|
||||
|
||||
func undo_it():
|
||||
# print("move verts undo_it")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
func will_change_anything()->bool:
|
||||
for path in block_map:
|
||||
var rec:BlockVertexChanges = block_map[path]
|
||||
match merge_type:
|
||||
MergeType.POINT:
|
||||
if rec.vertex_indices.size() >= 1:
|
||||
return true
|
||||
_:
|
||||
if rec.vertex_indices.size() >= 2:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
150
addons/cyclops_level_builder/commands/cmd_move_edges.gd
Normal file
150
addons/cyclops_level_builder/commands/cmd_move_edges.gd
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# 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
|
||||
class_name CommandMoveEdges
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
class BlockEdgeChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var edge_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Public
|
||||
var move_offset:Vector3 = Vector3.ZERO
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
func add_edge(block_path:NodePath, index:int):
|
||||
add_edges(block_path, [index])
|
||||
|
||||
func add_edges(block_path:NodePath, indices:Array[int]):
|
||||
var changes:BlockEdgeChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockEdgeChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.edge_indices.has(index):
|
||||
changes.edge_indices.append(index)
|
||||
|
||||
func _init():
|
||||
command_name = "Move edges"
|
||||
|
||||
|
||||
func do_it():
|
||||
# print("cmd move edges- DO IT")
|
||||
|
||||
for block_path in block_map.keys():
|
||||
|
||||
# print("%s" % block_path)
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var rec:BlockEdgeChanges = block_map[block_path]
|
||||
|
||||
# print("rec %s" % rec)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
# print("init done")
|
||||
var w2l:Transform3D = block.global_transform.affine_inverse()
|
||||
var move_offset_local = w2l.basis * move_offset
|
||||
#print("move_offset ", move_offset)
|
||||
#print("move_offset_local ", move_offset_local)
|
||||
|
||||
var vert_indices:PackedInt32Array
|
||||
for edge_index in rec.edge_indices:
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[edge_index]
|
||||
if !vert_indices.has(e.start_index):
|
||||
vert_indices.append(e.start_index)
|
||||
if !vert_indices.has(e.end_index):
|
||||
vert_indices.append(e.end_index)
|
||||
|
||||
for v_idx in vert_indices:
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
v.point += move_offset_local
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
####
|
||||
#var moved_vert_indices:PackedInt32Array
|
||||
#var new_points:PackedVector3Array
|
||||
#var new_sel_centroids:PackedVector3Array
|
||||
#var moved_indices:Array[int] = []
|
||||
#for edge_index in rec.edge_indices:
|
||||
#var e:ConvexVolume.EdgeInfo = vol.edges[edge_index]
|
||||
#var v0:ConvexVolume.VertexInfo = vol.vertices[e.start_index]
|
||||
#var v1:ConvexVolume.VertexInfo = vol.vertices[e.end_index]
|
||||
#if e.selected:
|
||||
#new_sel_centroids.append((v0.point + v1.point) / 2 + move_offset_local)
|
||||
#
|
||||
#if !moved_indices.has(e.start_index):
|
||||
#new_points.append(v0.point + move_offset_local)
|
||||
#moved_indices.append(e.start_index)
|
||||
#if !moved_indices.has(e.end_index):
|
||||
#new_points.append(v1.point + move_offset_local)
|
||||
#moved_indices.append(e.end_index)
|
||||
#else:
|
||||
#if !moved_indices.has(e.start_index):
|
||||
#new_points.append(v0.point + move_offset_local)
|
||||
#moved_indices.append(e.start_index)
|
||||
#if !moved_indices.has(e.end_index):
|
||||
#new_points.append(v1.point + move_offset_local)
|
||||
#moved_indices.append(e.end_index)
|
||||
#
|
||||
#for v_idx in vol.vertices.size():
|
||||
#if !moved_indices.has(v_idx):
|
||||
#new_points.append(vol.vertices[v_idx].point)
|
||||
##print("new points_ %s" % new_points)
|
||||
#
|
||||
#var new_vol:ConvexVolume = ConvexVolume.new()
|
||||
#new_vol.init_from_points(new_points)
|
||||
#
|
||||
#new_vol.copy_face_attributes(vol)
|
||||
#
|
||||
##print("new init done")
|
||||
#
|
||||
##Copy selection data
|
||||
#for e_idx in new_vol.edges.size():
|
||||
#var e_new:ConvexVolume.EdgeInfo = new_vol.edges[e_idx]
|
||||
#var centroid:Vector3 = (new_vol.vertices[e_new.start_index].point + new_vol.vertices[e_new.end_index].point) / 2
|
||||
## print ("vol point %s " % v1.point)
|
||||
#if new_sel_centroids.has(centroid):
|
||||
## print("set sel")
|
||||
#e_new.selected = true
|
||||
#
|
||||
#block.mesh_vector_data = new_vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
func undo_it():
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockEdgeChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
102
addons/cyclops_level_builder/commands/cmd_move_face_planar.gd
Normal file
102
addons/cyclops_level_builder/commands/cmd_move_face_planar.gd
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# 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
|
||||
class_name CommandMoveFacePlanar
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public data to set before activating command
|
||||
var blocks_root_path:NodePath
|
||||
var block_path:NodePath
|
||||
var move_dir_normal:Vector3
|
||||
var move_amount:float
|
||||
var face_index:int
|
||||
var lock_uvs:bool = false
|
||||
|
||||
|
||||
#Private
|
||||
var block_name:String
|
||||
var block_selected:bool
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
var deleted:bool = false
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Move face planar"
|
||||
|
||||
func move_to(offset:Vector3, intermediate:bool):
|
||||
# print("move_to off %s faceindex %s amount %s movedir %s" % [offset, face_index, move_amount, move_dir_normal])
|
||||
if !tracked_block_data:
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
block_name = block.name
|
||||
block_selected = block.selected
|
||||
tracked_block_data = block.mesh_vector_data
|
||||
|
||||
var ctl_mesh:ConvexVolume = ConvexVolume.new()
|
||||
ctl_mesh.init_from_mesh_vector_data(tracked_block_data)
|
||||
var new_mesh:ConvexVolume = ctl_mesh.translate_face_plane(face_index, offset, lock_uvs)
|
||||
|
||||
#print("offset %s" % offset)
|
||||
#print("ctl_mesh %s" % ctl_mesh.get_points())
|
||||
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
if new_mesh == null || new_mesh.is_empty():
|
||||
#print("new_mesh EMPTY")
|
||||
block.block_data = null
|
||||
if !intermediate:
|
||||
block.queue_free()
|
||||
deleted = true
|
||||
return
|
||||
|
||||
#print("new_mesh %s" % new_mesh.get_points())
|
||||
|
||||
var result_data:MeshVectorData = new_mesh.to_mesh_vector_data()
|
||||
block.mesh_vector_data = result_data
|
||||
|
||||
|
||||
func do_it_intermediate():
|
||||
move_to(move_dir_normal * move_amount, true)
|
||||
|
||||
func do_it():
|
||||
move_to(move_dir_normal * move_amount, false)
|
||||
|
||||
func undo_it():
|
||||
if deleted:
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
|
||||
var blocks_root:Node = builder.get_node(blocks_root_path)
|
||||
blocks_root.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.mesh_vector_data = tracked_block_data
|
||||
block.name = block_name
|
||||
block.selected = block_selected
|
||||
|
||||
deleted = false
|
||||
return
|
||||
|
||||
move_to(Vector3.ZERO, false)
|
||||
|
||||
144
addons/cyclops_level_builder/commands/cmd_move_faces.gd
Normal file
144
addons/cyclops_level_builder/commands/cmd_move_faces.gd
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# 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
|
||||
class_name CommandMoveFaces
|
||||
extends CyclopsCommand
|
||||
|
||||
class BlockFaceChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Public
|
||||
var move_offset:Vector3 = Vector3.ZERO
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
|
||||
func add_face(block_path:NodePath, index:int):
|
||||
# print("Adding face %s %s" % [block_path, index])
|
||||
add_faces(block_path, [index])
|
||||
|
||||
func add_faces(block_path:NodePath, indices:Array[int]):
|
||||
var changes:BlockFaceChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockFaceChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.face_indices.has(index):
|
||||
changes.face_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Move faces"
|
||||
|
||||
func do_it():
|
||||
# print("cmd move edges- DO IT")
|
||||
|
||||
for block_path in block_map.keys():
|
||||
|
||||
# print("%s" % block_path)
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
|
||||
var w2l:Transform3D = block.global_transform.affine_inverse()
|
||||
var move_offset_local:Vector3 = w2l.basis * move_offset
|
||||
# print("rec %s" % rec)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
var vert_indices:PackedInt32Array
|
||||
for f_index in rec.face_indices:
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_index]
|
||||
for v_idx in f.vertex_indices:
|
||||
if !vert_indices.has(v_idx):
|
||||
vert_indices.append(v_idx)
|
||||
|
||||
for v_idx in vert_indices:
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
v.point += move_offset_local
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
|
||||
####
|
||||
# print("init done")
|
||||
|
||||
#var new_points:PackedVector3Array
|
||||
#var new_sel_centroids:PackedVector3Array
|
||||
#var moved_vert_indices:Array[int] = []
|
||||
#for face_index in rec.face_indices:
|
||||
#var f:ConvexVolume.FaceInfo = vol.faces[face_index]
|
||||
#var centroid:Vector3 = f.get_centroid()
|
||||
## var v0:ConvexVolume.VertexInfo = vol.vertices[e.start_index]
|
||||
## var v1:ConvexVolume.VertexInfo = vol.vertices[e.end_index]
|
||||
#if f.selected:
|
||||
#new_sel_centroids.append(centroid + move_offset_local)
|
||||
#
|
||||
#for v_idx in f.vertex_indices:
|
||||
#if !moved_vert_indices.has(v_idx):
|
||||
#new_points.append(vol.vertices[v_idx].point + move_offset_local)
|
||||
#moved_vert_indices.append(v_idx)
|
||||
#else:
|
||||
#for v_idx in f.vertex_indices:
|
||||
#if !moved_vert_indices.has(v_idx):
|
||||
#new_points.append(vol.vertices[v_idx].point + move_offset_local)
|
||||
#moved_vert_indices.append(v_idx)
|
||||
#
|
||||
#for v_idx in vol.vertices.size():
|
||||
#if !moved_vert_indices.has(v_idx):
|
||||
#new_points.append(vol.vertices[v_idx].point)
|
||||
##print("new points_ %s" % new_points)
|
||||
#
|
||||
#var new_vol:ConvexVolume = ConvexVolume.new()
|
||||
#new_vol.init_from_points(new_points)
|
||||
#
|
||||
#new_vol.copy_face_attributes(vol)
|
||||
##print("new init done")
|
||||
#
|
||||
##Copy selection data
|
||||
#for f_idx in new_vol.faces.size():
|
||||
#var f_new:ConvexVolume.FaceInfo = new_vol.faces[f_idx]
|
||||
#var centroid:Vector3 = f_new.get_centroid()
|
||||
## print ("vol point %s " % v1.point)
|
||||
#if new_sel_centroids.has(centroid):
|
||||
## print("set sel")
|
||||
#f_new.selected = true
|
||||
#
|
||||
#block.mesh_vector_data = new_vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
func undo_it():
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
117
addons/cyclops_level_builder/commands/cmd_move_vertices.gd
Normal file
117
addons/cyclops_level_builder/commands/cmd_move_vertices.gd
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# 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
|
||||
class_name CommandMoveVertices
|
||||
extends CyclopsCommand
|
||||
|
||||
class BlockVertexChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var vertex_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Public
|
||||
@export var move_offset:Vector3 = Vector3.ZERO
|
||||
@export var triplanar_lock_uvs:bool = false
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
|
||||
func add_vertex(block_path:NodePath, index:int):
|
||||
add_vertices(block_path, [index])
|
||||
|
||||
func add_vertices(block_path:NodePath, indices:Array[int]):
|
||||
# print("adding vertex %s %s" % [block_path, indices])
|
||||
var changes:BlockVertexChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockVertexChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data.duplicate()
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.vertex_indices.has(index):
|
||||
changes.vertex_indices.append(index)
|
||||
|
||||
func _init():
|
||||
command_name = "Move vertices"
|
||||
|
||||
func do_it():
|
||||
# print("move verts do_it")
|
||||
for block_path in block_map.keys():
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var w2l:Transform3D = block.global_transform
|
||||
w2l = w2l.affine_inverse()
|
||||
var move_offset_local:Vector3 = w2l.basis * move_offset
|
||||
|
||||
#print("move offset %s" % move_offset)
|
||||
#print("move offset local %s" % move_offset_local)
|
||||
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for v_idx in vol.vertices.size():
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
vol.vertices[v_idx].point += move_offset_local
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
#####
|
||||
#var selected_points:PackedVector3Array
|
||||
#var new_points:PackedVector3Array
|
||||
#for v_idx in vol.vertices.size():
|
||||
#if rec.vertex_indices.has(v_idx):
|
||||
#var p:Vector3 = vol.vertices[v_idx].point + move_offset_local
|
||||
#new_points.append(p)
|
||||
#selected_points.append(p)
|
||||
#else:
|
||||
#new_points.append(vol.vertices[v_idx].point)
|
||||
#
|
||||
#
|
||||
#var new_vol:ConvexVolume = ConvexVolume.new()
|
||||
#new_vol.init_from_points(new_points)
|
||||
#
|
||||
#new_vol.copy_face_attributes(vol)
|
||||
#
|
||||
#for v_idx in new_vol.vertices.size():
|
||||
#var v:ConvexVolume.VertexInfo = new_vol.vertices[v_idx]
|
||||
## print ("vol point %s " % v.point)
|
||||
#if selected_points.has(v.point):
|
||||
## print("set sel")
|
||||
#v.selected = true
|
||||
#
|
||||
#block.mesh_vector_data = new_vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
func undo_it():
|
||||
# print("move verts undo_it")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
239
addons/cyclops_level_builder/commands/cmd_select_blocks.gd
Normal file
239
addons/cyclops_level_builder/commands/cmd_select_blocks.gd
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
# 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
|
||||
class_name CommandSelectBlocks
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public
|
||||
var selection_type:Selection.Type = Selection.Type.REPLACE
|
||||
|
||||
var block_paths:Array[NodePath]
|
||||
|
||||
#Private
|
||||
#var tracked_selected_blocks:Array[NodePath]
|
||||
#var tracked_active_blocks:Array[NodePath]
|
||||
var cached_selection:Array[NodePath]
|
||||
var init:bool = false
|
||||
|
||||
func _init():
|
||||
command_name = "Select blocks"
|
||||
|
||||
#func will_change_anything()->bool:
|
||||
#
|
||||
# var active_path:NodePath
|
||||
# if !block_paths.is_empty():
|
||||
# active_path = block_paths[0]
|
||||
## print("will change active %s" % active_path)
|
||||
#
|
||||
# for child in builder.get_blocks():
|
||||
# if child is CyclopsBlock:
|
||||
# var block:CyclopsBlock = child
|
||||
# var path:NodePath = block.get_path()
|
||||
#
|
||||
# match selection_type:
|
||||
# Selection.Type.REPLACE:
|
||||
# if block.selected != block_paths.has(path):
|
||||
# return true
|
||||
#
|
||||
# if block.active != (path == active_path):
|
||||
# return true
|
||||
#
|
||||
# Selection.Type.ADD:
|
||||
# if block_paths.has(path):
|
||||
# if !block.selected:
|
||||
# return true
|
||||
# if block.active != (path == active_path):
|
||||
# return true
|
||||
#
|
||||
# Selection.Type.SUBTRACT:
|
||||
# if block_paths.has(path):
|
||||
# if block.selected:
|
||||
# return true
|
||||
#
|
||||
# Selection.Type.TOGGLE:
|
||||
# if !block_paths.is_empty():
|
||||
# return true
|
||||
#
|
||||
## print("will chage anything false")
|
||||
# return false
|
||||
|
||||
func will_change_anything()->bool:
|
||||
var selection:EditorSelection = builder.get_editor_interface().get_selection()
|
||||
|
||||
var cur_node_list:Array[Node] = selection.get_selected_nodes()
|
||||
if !init:
|
||||
for node in cur_node_list:
|
||||
cached_selection.append(node.get_path())
|
||||
init = true
|
||||
|
||||
var cur_paths:Array[NodePath]
|
||||
for node in selection.get_selected_nodes():
|
||||
cur_paths.append(node.get_path())
|
||||
|
||||
if selection_type == Selection.Type.REPLACE:
|
||||
if cur_paths.size() != block_paths.size():
|
||||
return true
|
||||
for i in cur_paths.size():
|
||||
if cur_paths[i] != block_paths[i]:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
elif selection_type == Selection.Type.ADD:
|
||||
for path in block_paths:
|
||||
if !cur_paths.has(path):
|
||||
return true
|
||||
return false
|
||||
|
||||
elif selection_type == Selection.Type.SUBTRACT:
|
||||
for path in block_paths:
|
||||
if cur_paths.has(path):
|
||||
return true
|
||||
return false
|
||||
|
||||
elif selection_type == Selection.Type.TOGGLE:
|
||||
if !block_paths.is_empty():
|
||||
return true
|
||||
return false
|
||||
|
||||
return false
|
||||
|
||||
func do_it():
|
||||
var selection:EditorSelection = builder.get_editor_interface().get_selection()
|
||||
|
||||
var cur_node_list:Array[Node] = selection.get_selected_nodes()
|
||||
if !init:
|
||||
cached_selection = cur_node_list.duplicate()
|
||||
init = true
|
||||
|
||||
var cur_paths:Array[NodePath]
|
||||
for node in selection.get_selected_nodes():
|
||||
cur_paths.append(node.get_path())
|
||||
|
||||
if selection_type == Selection.Type.REPLACE:
|
||||
selection.clear()
|
||||
for path in block_paths:
|
||||
var node:Node = builder.get_node(path)
|
||||
selection.add_node(node)
|
||||
|
||||
elif selection_type == Selection.Type.ADD:
|
||||
for path in block_paths:
|
||||
if !cur_paths.has(path):
|
||||
var node:Node = builder.get_node(path)
|
||||
selection.add_node(node)
|
||||
|
||||
elif selection_type == Selection.Type.SUBTRACT:
|
||||
for path in block_paths:
|
||||
if cur_paths.has(path):
|
||||
var node:Node = builder.get_node(path)
|
||||
selection.remove_node(node)
|
||||
|
||||
elif selection_type == Selection.Type.TOGGLE:
|
||||
for path in block_paths:
|
||||
var node:Node = builder.get_node(path)
|
||||
|
||||
if cur_paths.has(path):
|
||||
selection.remove_node(node)
|
||||
else:
|
||||
selection.add_node(node)
|
||||
|
||||
|
||||
#func do_it_old():
|
||||
## print("sel verts do_it")
|
||||
#
|
||||
# #Cache state
|
||||
# tracked_selected_blocks.clear()
|
||||
# tracked_active_blocks.clear()
|
||||
#
|
||||
#
|
||||
# var active_block:CyclopsBlock = builder.get_active_block()
|
||||
# tracked_active_blocks.append(active_block.get_path())
|
||||
#
|
||||
# for child in builder.get_selected_blocks():
|
||||
# var block:CyclopsBlock = child
|
||||
# tracked_selected_blocks.append(block.get_path())
|
||||
#
|
||||
# #Do selection
|
||||
# var active_path:NodePath
|
||||
# if !block_paths.is_empty():
|
||||
# active_path = block_paths[0]
|
||||
#
|
||||
# #print("do_it active %s" % active_path)
|
||||
## print("Setting active %s" % active_path)
|
||||
# for child in builder.get_blocks():
|
||||
# var block:CyclopsBlock = child
|
||||
# var path:NodePath = block.get_path()
|
||||
#
|
||||
# match selection_type:
|
||||
# Selection.Type.REPLACE:
|
||||
# block.selected = block_paths.has(path)
|
||||
# block.active = path == active_path
|
||||
# Selection.Type.ADD:
|
||||
# if block_paths.has(path):
|
||||
# block.selected = true
|
||||
# block.active = path == active_path
|
||||
# Selection.Type.SUBTRACT:
|
||||
# if block_paths.has(path):
|
||||
# block.selected = false
|
||||
# block.active = false
|
||||
# Selection.Type.TOGGLE:
|
||||
# #print("Check block %s" % path)
|
||||
# #print("act %s sel %s" % [block.active, block.selected])
|
||||
# if path == active_path:
|
||||
# #print("Match active")
|
||||
# if !block.active:
|
||||
# #print("Setting active %s" % block.name)
|
||||
# block.active = true
|
||||
# block.selected = true
|
||||
# else:
|
||||
# #print("Clearing active %s" % block.name)
|
||||
# block.active = false
|
||||
# block.selected = false
|
||||
# else:
|
||||
# if block_paths.has(path):
|
||||
# #print("Setting sel")
|
||||
# block.selected = !block.selected
|
||||
# block.active = false
|
||||
#
|
||||
# builder.selection_changed.emit()
|
||||
|
||||
func undo_it():
|
||||
var selection:EditorSelection = builder.get_editor_interface().get_selection()
|
||||
selection.clear()
|
||||
|
||||
for path in cached_selection:
|
||||
var node:Node = builder.get_node(path)
|
||||
selection.add_node(node)
|
||||
|
||||
#func undo_it():
|
||||
#
|
||||
# for child in builder.get_blocks():
|
||||
# if child is CyclopsBlock:
|
||||
# var block:CyclopsBlock = child
|
||||
# var path:NodePath = block.get_path()
|
||||
#
|
||||
# block.selected = tracked_selected_blocks.has(path)
|
||||
# block.active = tracked_active_blocks.has(path)
|
||||
#
|
||||
# builder.selection_changed.emit()
|
||||
176
addons/cyclops_level_builder/commands/cmd_select_edges.gd
Normal file
176
addons/cyclops_level_builder/commands/cmd_select_edges.gd
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# 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
|
||||
class_name CommandSelectEdges
|
||||
extends CyclopsCommand
|
||||
|
||||
class BlockEdgeChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var edge_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Public
|
||||
var selection_type:Selection.Type = Selection.Type.REPLACE
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
|
||||
func add_edge(block_path:NodePath, index:int):
|
||||
add_edges(block_path, [index])
|
||||
|
||||
func add_edges(block_path:NodePath, indices:Array[int]):
|
||||
var changes:BlockEdgeChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockEdgeChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.edge_indices.has(index):
|
||||
changes.edge_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Select edges"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
for block_path in block_map.keys():
|
||||
#print("path %s" % node_path)
|
||||
|
||||
var rec:BlockEdgeChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
if !rec.edge_indices.is_empty():
|
||||
if vol.active_edge != rec.edge_indices[0]:
|
||||
return true
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
for e_idx in vol.edges.size():
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
if e.selected != rec.edge_indices.has(e_idx):
|
||||
#print("will change SREP")
|
||||
return true
|
||||
Selection.Type.ADD:
|
||||
for e_idx in rec.edge_indices:
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
if rec.edge_indices.has(e_idx):
|
||||
if !e.selected:
|
||||
#print("will change ADD")
|
||||
return true
|
||||
Selection.Type.SUBTRACT:
|
||||
for e_idx in rec.edge_indices:
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
if rec.edge_indices.has(e_idx):
|
||||
if e.selected:
|
||||
#print("will change SUB")
|
||||
return true
|
||||
Selection.Type.TOGGLE:
|
||||
#print("will change TOG")
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func do_it():
|
||||
# print("sel edges do_it")
|
||||
|
||||
for block_path in block_map.keys():
|
||||
# print("path %s" % block_path)
|
||||
|
||||
var rec:BlockEdgeChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
if !rec.edge_indices.is_empty():
|
||||
var active_index:int = rec.edge_indices[0]
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
vol.active_edge = active_index
|
||||
Selection.Type.ADD:
|
||||
vol.active_edge = active_index
|
||||
Selection.Type.SUBTRACT:
|
||||
if rec.edge_indices.has(vol.active_edge):
|
||||
vol.active_edge = -1
|
||||
Selection.Type.TOGGLE:
|
||||
if rec.edge_indices.has(vol.active_edge):
|
||||
vol.active_edge = -1
|
||||
elif !vol.edges[active_index].selected:
|
||||
vol.active_edge = active_index
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
for e_idx in vol.edges.size():
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
e.selected = rec.edge_indices.has(e_idx)
|
||||
|
||||
Selection.Type.ADD:
|
||||
for e_idx in vol.edges.size():
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
if rec.edge_indices.has(e_idx):
|
||||
e.selected = true
|
||||
|
||||
Selection.Type.SUBTRACT:
|
||||
for e_idx in vol.edges.size():
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
if rec.edge_indices.has(e_idx):
|
||||
e.selected = false
|
||||
|
||||
Selection.Type.TOGGLE:
|
||||
for e_idx in vol.edges.size():
|
||||
var e:ConvexVolume.EdgeInfo = vol.edges[e_idx]
|
||||
if rec.edge_indices.has(e_idx):
|
||||
#print("flipping %s" % e.selected)
|
||||
e.selected = !e.selected
|
||||
|
||||
if vol.active_edge != -1:
|
||||
if vol.active_edge >= vol.edges.size() || !vol.edges[vol.active_edge].selected:
|
||||
vol.active_edge = -1
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
func undo_it():
|
||||
# print("sel verts undo_it")
|
||||
#print("sel vert undo_it()")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockEdgeChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
||||
|
||||
|
||||
168
addons/cyclops_level_builder/commands/cmd_select_faces.gd
Normal file
168
addons/cyclops_level_builder/commands/cmd_select_faces.gd
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# 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
|
||||
class_name CommandSelectFaces
|
||||
extends CyclopsCommand
|
||||
|
||||
class BlockFaceChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Public
|
||||
var selection_type:Selection.Type = Selection.Type.REPLACE
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
func add_face(block_path:NodePath, index:int):
|
||||
add_faces(block_path, [index])
|
||||
|
||||
func add_faces(block_path:NodePath, indices:Array[int]):
|
||||
var changes:BlockFaceChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockFaceChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.face_indices.has(index):
|
||||
changes.face_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Select faces"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
for block_path in block_map.keys():
|
||||
#print("path %s" % node_path)
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
# var active_idx:int = -1
|
||||
if !rec.face_indices.is_empty():
|
||||
if vol.active_face != rec.face_indices[0]:
|
||||
return true
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if f.selected != rec.face_indices.has(f_idx):
|
||||
return true
|
||||
Selection.Type.ADD:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if rec.face_indices.has(f_idx):
|
||||
if !f.selected:
|
||||
return true
|
||||
Selection.Type.SUBTRACT:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if rec.face_indices.has(f_idx):
|
||||
if f.selected:
|
||||
return true
|
||||
Selection.Type.TOGGLE:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func do_it():
|
||||
#print("sel verts do_it")
|
||||
#print("sel vert do_it()")
|
||||
for block_path in block_map.keys():
|
||||
# print("path %s" % block_path)
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
if !rec.face_indices.is_empty():
|
||||
var active_index:int = rec.face_indices[0]
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
vol.active_face = active_index
|
||||
Selection.Type.ADD:
|
||||
vol.active_face = active_index
|
||||
Selection.Type.SUBTRACT:
|
||||
if rec.face_indices.has(vol.active_face):
|
||||
vol.active_face = -1
|
||||
Selection.Type.TOGGLE:
|
||||
if rec.face_indices.has(vol.active_face):
|
||||
vol.active_face = -1
|
||||
elif !vol.faces[active_index].selected:
|
||||
vol.active_face = active_index
|
||||
|
||||
|
||||
# print("face active index %s" % active_idx)
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
f.selected = rec.face_indices.has(f_idx)
|
||||
|
||||
Selection.Type.ADD:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if rec.face_indices.has(f_idx):
|
||||
f.selected = true
|
||||
|
||||
Selection.Type.SUBTRACT:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if rec.face_indices.has(f_idx):
|
||||
f.selected = false
|
||||
|
||||
Selection.Type.TOGGLE:
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if rec.face_indices.has(f_idx):
|
||||
f.selected = !f.selected
|
||||
|
||||
if vol.active_face != -1:
|
||||
if vol.active_face >= vol.faces.size() || !vol.faces[vol.active_face].selected:
|
||||
vol.active_face = -1
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
builder.selection_changed.emit()
|
||||
|
||||
func undo_it():
|
||||
# print("undo_it() select faces")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
174
addons/cyclops_level_builder/commands/cmd_select_vertices.gd
Normal file
174
addons/cyclops_level_builder/commands/cmd_select_vertices.gd
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# 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
|
||||
class_name CommandSelectVertices
|
||||
extends CyclopsCommand
|
||||
|
||||
class BlockVertexChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var vertex_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
#Public
|
||||
var selection_type:Selection.Type = Selection.Type.REPLACE
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
|
||||
|
||||
|
||||
func add_vertex(block_path:NodePath, index:int):
|
||||
add_vertices(block_path, [index])
|
||||
|
||||
func add_vertices(block_path:NodePath, indices:Array[int]):
|
||||
var changes:BlockVertexChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockVertexChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.vertex_indices.has(index):
|
||||
changes.vertex_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Select vertices"
|
||||
|
||||
|
||||
func will_change_anything()->bool:
|
||||
for block_path in block_map.keys():
|
||||
#print("path %s" % node_path)
|
||||
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
if !rec.vertex_indices.is_empty():
|
||||
if vol.active_vertex != rec.vertex_indices[0]:
|
||||
return true
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
for v_idx in vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
if v.selected != rec.vertex_indices.has(v_idx):
|
||||
return true
|
||||
Selection.Type.ADD:
|
||||
for v_idx in rec.vertex_indices:
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
if !v.selected:
|
||||
return true
|
||||
Selection.Type.SUBTRACT:
|
||||
for v_idx in rec.vertex_indices:
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
if v.selected:
|
||||
return true
|
||||
Selection.Type.TOGGLE:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func do_it():
|
||||
# print("sel verts do_it")
|
||||
for block_path in block_map.keys():
|
||||
#print("path %s" % node_path)
|
||||
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
if !rec.vertex_indices.is_empty():
|
||||
var active_index:int = rec.vertex_indices[0]
|
||||
#print("active_index ", active_index)
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
vol.active_vertex = active_index
|
||||
Selection.Type.ADD:
|
||||
vol.active_vertex = active_index
|
||||
Selection.Type.SUBTRACT:
|
||||
if rec.vertex_indices.has(vol.active_vertex):
|
||||
vol.active_vertex = -1
|
||||
Selection.Type.TOGGLE:
|
||||
if rec.vertex_indices.has(vol.active_vertex):
|
||||
vol.active_vertex = -1
|
||||
elif !vol.vertices[active_index].selected:
|
||||
vol.active_vertex = active_index
|
||||
else:
|
||||
if selection_type == Selection.Type.REPLACE:
|
||||
vol.active_vertex = -1
|
||||
|
||||
match selection_type:
|
||||
Selection.Type.REPLACE:
|
||||
for v_idx in vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
v.selected = rec.vertex_indices.has(v_idx)
|
||||
|
||||
Selection.Type.ADD:
|
||||
for v_idx in vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
v.selected = true
|
||||
|
||||
Selection.Type.SUBTRACT:
|
||||
for v_idx in vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
v.selected = false
|
||||
|
||||
Selection.Type.TOGGLE:
|
||||
for v_idx in vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
if rec.vertex_indices.has(v_idx):
|
||||
v.selected = !v.selected
|
||||
|
||||
vol.update_edge_and_face_selection_from_vertices()
|
||||
#print("vol.active_vertex ", vol.active_vertex)
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
#print("block.mesh_vector_data.active_vertex ", block.mesh_vector_data.active_vertex)
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
func undo_it():
|
||||
# print("sel verts undo_it")
|
||||
#print("sel vert undo_it()")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
112
addons/cyclops_level_builder/commands/cmd_set_face_color.gd
Normal file
112
addons/cyclops_level_builder/commands/cmd_set_face_color.gd
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# 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
|
||||
class_name CommandSetFaceColor
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
class BlockFaceChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_indices:Array[int]
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
var color:Color = Color.WHITE
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
func add_face(block_path:NodePath, index:int):
|
||||
add_faces(block_path, [index])
|
||||
|
||||
func add_faces(block_path:NodePath, indices:Array[int]):
|
||||
# print("adding_face %s %s" % [block_path, indices])
|
||||
var changes:BlockFaceChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockFaceChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.face_indices.has(index):
|
||||
changes.face_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Set Face Color"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
# print("CommandSetUvTransform will_change_anything")
|
||||
for block_path in block_map.keys():
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
if rec.face_indices.has(f_idx):
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if f.color != color:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func do_it():
|
||||
#print("sel verts do_it")
|
||||
# print("sel uv_transform do_it()")
|
||||
for block_path in block_map.keys():
|
||||
# print("path %s" % block_path)
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
# print("block_path %s" % block_path)
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
if rec.face_indices.has(f_idx):
|
||||
# print("face_idx %s" % f_idx)
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
f.color = color
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
||||
func undo_it():
|
||||
# print("undo_it() select faces")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
# 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
|
||||
class_name CommandSetFaceUvTransform
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
class BlockFaceChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
var uv_transform:Transform2D = Transform2D.IDENTITY
|
||||
var visible:bool = true
|
||||
var color:Color = Color.WHITE
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
func add_face(block_path:NodePath, index:int):
|
||||
add_faces(block_path, [index])
|
||||
|
||||
func add_faces(block_path:NodePath, indices:Array[int]):
|
||||
# print("adding_face %s %s" % [block_path, indices])
|
||||
var changes:BlockFaceChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockFaceChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.face_indices.has(index):
|
||||
changes.face_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Set Face Uv Transform"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
# print("CommandSetUvTransform will_change_anything")
|
||||
for block_path in block_map.keys():
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
if rec.face_indices.has(f_idx):
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if f.uv_transform != uv_transform:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func do_it():
|
||||
#print("sel verts do_it")
|
||||
# print("sel uv_transform do_it()")
|
||||
for block_path in block_map.keys():
|
||||
# print("path %s" % block_path)
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
# print("block_path %s" % block_path)
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
if rec.face_indices.has(f_idx):
|
||||
# print("face_idx %s" % f_idx)
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
f.uv_transform = uv_transform
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
||||
func undo_it():
|
||||
# print("undo_it() select faces")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
# 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
|
||||
class_name CommandSetFaceVertexColor
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
class BlockFaceVertexChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_vert_indices:Array[int]
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
var color:Color = Color.WHITE
|
||||
var strength:float = 1
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
#class StrokePoint:
|
||||
#var position:Vector3
|
||||
#var pressure:float
|
||||
#
|
||||
#var stroke_points:Array[StrokePoint]
|
||||
|
||||
func add_face_vertex(block_path:NodePath, index:int):
|
||||
add_face_vertices(block_path, [index])
|
||||
|
||||
func add_face_vertices(block_path:NodePath, indices:Array[int]):
|
||||
# print("adding_face %s %s" % [block_path, indices])
|
||||
var changes:BlockFaceVertexChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockFaceVertexChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vertex_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.face_vert_indices.has(index):
|
||||
changes.face_vert_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Set Face Vertex Color"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
return block_map.size() > 0
|
||||
# print("CommandSetUvTransform will_change_anything")
|
||||
#for block_path in block_map.keys():
|
||||
#
|
||||
#var rec:BlockFaceVertexChanges = block_map[block_path]
|
||||
#var block:CyclopsBlock = builder.get_node(block_path)
|
||||
#
|
||||
#var vol:ConvexVolume = ConvexVolume.new()
|
||||
#vol.init_from_convex_block_data(rec.tracked_block_data)
|
||||
#
|
||||
#for f_idx in vol.faces.size():
|
||||
#if rec.face_indices.has(f_idx):
|
||||
#var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
#if f.color != color:
|
||||
#return true
|
||||
#
|
||||
#return false
|
||||
|
||||
|
||||
|
||||
func do_it():
|
||||
#print("sel verts do_it")
|
||||
#print("sel face vert color do_it()")
|
||||
for block_path in block_map.keys():
|
||||
# print("path %s" % block_path)
|
||||
|
||||
var rec:BlockFaceVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
#print("block_path %s" % block_path)
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for fv_idx in vol.face_vertices.size():
|
||||
if rec.face_vert_indices.has(fv_idx):
|
||||
#print("face_v_idx %s" % fv_idx)
|
||||
var fv:ConvexVolume.FaceVertexInfo = vol.face_vertices[fv_idx]
|
||||
fv.color = MathUtil.blend_colors_ignore_alpha(color, fv.color, strength)
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
||||
func undo_it():
|
||||
# print("undo_it() select faces")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockFaceVertexChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
112
addons/cyclops_level_builder/commands/cmd_set_face_visible.gd
Normal file
112
addons/cyclops_level_builder/commands/cmd_set_face_visible.gd
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# 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
|
||||
class_name CommandSetFaceVisible
|
||||
extends CyclopsCommand
|
||||
|
||||
|
||||
class BlockFaceChanges extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_indices:Array[int] = []
|
||||
var tracked_block_data:MeshVectorData
|
||||
|
||||
var visible:bool = true
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
|
||||
func add_face(block_path:NodePath, index:int):
|
||||
add_faces(block_path, [index])
|
||||
|
||||
func add_faces(block_path:NodePath, indices:Array[int]):
|
||||
# print("adding_face %s %s" % [block_path, indices])
|
||||
var changes:BlockFaceChanges
|
||||
if block_map.has(block_path):
|
||||
changes = block_map[block_path]
|
||||
else:
|
||||
changes = BlockFaceChanges.new()
|
||||
changes.block_path = block_path
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
changes.tracked_block_data = block.mesh_vector_data
|
||||
block_map[block_path] = changes
|
||||
|
||||
for index in indices:
|
||||
if !changes.face_indices.has(index):
|
||||
changes.face_indices.append(index)
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Set Face Properties"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
# print("CommandSetUvTransform will_change_anything")
|
||||
for block_path in block_map.keys():
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
if rec.face_indices.has(f_idx):
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if f.visible != visible:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func do_it():
|
||||
#print("sel verts do_it")
|
||||
# print("sel uv_transform do_it()")
|
||||
for block_path in block_map.keys():
|
||||
# print("path %s" % block_path)
|
||||
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
# print("block_path %s" % block_path)
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(rec.tracked_block_data)
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
if rec.face_indices.has(f_idx):
|
||||
# print("face_idx %s" % f_idx)
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
f.visible = visible
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
builder.selection_changed.emit()
|
||||
|
||||
|
||||
func undo_it():
|
||||
# print("undo_it() select faces")
|
||||
for block_path in block_map.keys():
|
||||
var rec:BlockFaceChanges = block_map[block_path]
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.mesh_vector_data = rec.tracked_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
158
addons/cyclops_level_builder/commands/cmd_set_material.gd
Normal file
158
addons/cyclops_level_builder/commands/cmd_set_material.gd
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# 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
|
||||
class_name CommandSetMaterial
|
||||
extends CyclopsCommand
|
||||
|
||||
class Target extends RefCounted:
|
||||
var block_path:NodePath
|
||||
var face_indices:PackedInt32Array
|
||||
|
||||
class BlockCache extends RefCounted:
|
||||
var path:NodePath
|
||||
var data:MeshVectorData
|
||||
var materials:Array[Material]
|
||||
|
||||
#Public
|
||||
var setting_material:bool = true
|
||||
var material_path:String
|
||||
|
||||
var setting_color:bool = false
|
||||
var color:Color = Color.WHITE
|
||||
|
||||
var setting_visibility:bool = false
|
||||
var visibility:bool = true
|
||||
|
||||
var painting_uv:bool = false
|
||||
var uv_matrix:Transform2D = Transform2D.IDENTITY
|
||||
|
||||
#Private
|
||||
var target_list:Array[Target] = []
|
||||
|
||||
var cache_list:Array[BlockCache] = []
|
||||
|
||||
func add_target(block_path:NodePath, face_indices:PackedInt32Array):
|
||||
# print("add target %s %s" % [block_path.get_name(block_path.get_name_count() - 1), face_indices])
|
||||
var target:Target = null
|
||||
for t in target_list:
|
||||
if t.block_path == block_path:
|
||||
target = t
|
||||
break
|
||||
|
||||
if !target:
|
||||
target = Target.new()
|
||||
target.block_path = block_path
|
||||
target_list.append(target)
|
||||
|
||||
for f_idx in face_indices:
|
||||
if !target.face_indices.has(f_idx):
|
||||
target.face_indices.append(f_idx)
|
||||
|
||||
|
||||
func make_cache():
|
||||
cache_list = []
|
||||
|
||||
for t in target_list:
|
||||
var cache:BlockCache = BlockCache.new()
|
||||
var block:CyclopsBlock = builder.get_node(t.block_path)
|
||||
|
||||
cache.path = block.get_path()
|
||||
cache.data = block.mesh_vector_data
|
||||
cache.materials = block.materials.duplicate()
|
||||
|
||||
cache_list.append(cache)
|
||||
|
||||
func will_change_anything()->bool:
|
||||
return !target_list.is_empty()
|
||||
|
||||
func _init():
|
||||
command_name = "Set material"
|
||||
|
||||
func do_it():
|
||||
make_cache()
|
||||
|
||||
for tgt in target_list:
|
||||
var block:CyclopsBlock = builder.get_node(tgt.block_path)
|
||||
|
||||
var data:MeshVectorData = block.mesh_vector_data
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(data)
|
||||
|
||||
if setting_material:
|
||||
|
||||
var target_material:Material = null
|
||||
if ResourceLoader.exists(material_path, "Material"):
|
||||
#print("loading material ", material_path)
|
||||
var mat = load(material_path)
|
||||
target_material = mat if mat is Material else null
|
||||
|
||||
var mat_reindex:Dictionary
|
||||
var mat_list_reduced:Array[Material]
|
||||
|
||||
for f_idx in vol.faces.size():
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
|
||||
var mat_to_apply:Material
|
||||
|
||||
if tgt.face_indices.has(f_idx):
|
||||
mat_to_apply = target_material
|
||||
else:
|
||||
mat_to_apply = null if f.material_id == -1 else block.materials[f.material_id]
|
||||
|
||||
if !mat_to_apply:
|
||||
f.material_id = -1
|
||||
elif !mat_reindex.has(mat_to_apply):
|
||||
var new_idx = mat_reindex.size()
|
||||
mat_reindex[mat_to_apply] = new_idx
|
||||
mat_list_reduced.append(mat_to_apply)
|
||||
f.material_id = new_idx
|
||||
else:
|
||||
f.material_id = mat_reindex[mat_to_apply]
|
||||
|
||||
block.materials = mat_list_reduced
|
||||
|
||||
#Set other properties
|
||||
for f_idx in vol.faces.size():
|
||||
if tgt.face_indices.has(f_idx):
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[f_idx]
|
||||
if setting_color:
|
||||
f.color = color
|
||||
for v_idx in f.vertex_indices:
|
||||
var fv:ConvexVolume.FaceVertexInfo = \
|
||||
vol.get_face_vertex(f_idx, v_idx)
|
||||
fv.color = color
|
||||
if setting_visibility:
|
||||
f.visible = visibility
|
||||
if painting_uv:
|
||||
f.uv_transform = uv_matrix
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
func undo_it():
|
||||
for cache in cache_list:
|
||||
var block:CyclopsBlock = builder.get_node(cache.path)
|
||||
block.materials = cache.materials.duplicate()
|
||||
block.mesh_vector_data = cache.data
|
||||
|
||||
84
addons/cyclops_level_builder/commands/cmd_snap_to_grid.gd
Normal file
84
addons/cyclops_level_builder/commands/cmd_snap_to_grid.gd
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# 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
|
||||
class_name CommandSnapToGrid
|
||||
extends CyclopsCommand
|
||||
|
||||
class TrackedInfo extends RefCounted:
|
||||
var data:MeshVectorData
|
||||
|
||||
|
||||
#Private
|
||||
var blocks_to_move:Array[NodePath]
|
||||
var tracked_block_data:Array[TrackedInfo]
|
||||
|
||||
|
||||
func _init():
|
||||
command_name = "Snap to grid"
|
||||
|
||||
|
||||
#Add blocks to be moved here
|
||||
func add_block(block_path:NodePath):
|
||||
blocks_to_move.append(block_path)
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
#tracked_blocks.append(block)
|
||||
var info:TrackedInfo = TrackedInfo.new()
|
||||
info.data = block.mesh_vector_data.duplicate()
|
||||
# info.materials = block.materials
|
||||
tracked_block_data.append(info)
|
||||
|
||||
|
||||
func do_it():
|
||||
|
||||
for i in blocks_to_move.size():
|
||||
var block:CyclopsBlock = builder.get_node(blocks_to_move[i])
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(tracked_block_data[i].data)
|
||||
|
||||
var points_new:PackedVector3Array
|
||||
for v_idx in vol.vertices.size():
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[v_idx]
|
||||
var p_snap:Vector3 = builder.get_snapping_manager().snap_point(
|
||||
block.global_transform * v.point, SnappingQuery.new(null, []))
|
||||
points_new.append(p_snap)
|
||||
|
||||
var new_vol:ConvexVolume = ConvexVolume.new()
|
||||
new_vol.init_from_points(points_new)
|
||||
new_vol.transform(block.global_transform.affine_inverse())
|
||||
|
||||
|
||||
new_vol.copy_face_attributes(vol)
|
||||
|
||||
block.mesh_vector_data = new_vol.to_mesh_vector_data()
|
||||
|
||||
func undo_it():
|
||||
for i in blocks_to_move.size():
|
||||
var block:CyclopsBlock = builder.get_node(blocks_to_move[i])
|
||||
|
||||
block.mesh_vector_data = tracked_block_data[i].data
|
||||
|
||||
|
||||
|
||||
158
addons/cyclops_level_builder/commands/cmd_subtract_block.gd
Normal file
158
addons/cyclops_level_builder/commands/cmd_subtract_block.gd
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# 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
|
||||
class_name CommandSubtractBlock
|
||||
extends CyclopsCommand
|
||||
|
||||
class NewBlockInfo extends RefCounted:
|
||||
var data:MeshVectorData
|
||||
var materials:Array[Material]
|
||||
var path:NodePath
|
||||
#var centroid:Vector3
|
||||
var xform:Transform3D
|
||||
|
||||
#Public
|
||||
var block_paths:Array[NodePath]
|
||||
var block_to_subtract_path:NodePath
|
||||
var block_name_prefix:String = "Block_"
|
||||
|
||||
#Private
|
||||
var start_blocks:Array[TrackedBlock]
|
||||
var subtracted_block_cache:TrackedBlock
|
||||
var added_blocks:Array[NewBlockInfo]
|
||||
|
||||
func _init():
|
||||
command_name = "Subtract blocks"
|
||||
|
||||
func restore_tracked_block(tracked:TrackedBlock)->CyclopsBlock:
|
||||
var parent = builder.get_node(tracked.path_parent)
|
||||
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
block.mesh_vector_data = tracked.data
|
||||
block.materials = tracked.materials
|
||||
block.name = tracked.name
|
||||
# block.selected = tracked.selected
|
||||
block.global_transform = tracked.world_xform
|
||||
block.collision_type = tracked.collision_type
|
||||
block.collision_layer = tracked.collision_layers
|
||||
block.collision_mask = tracked.collision_mask
|
||||
|
||||
parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
|
||||
if tracked.selected:
|
||||
var selection:EditorSelection = builder.get_editor_interface().get_selection()
|
||||
selection.add_node(block)
|
||||
|
||||
return block
|
||||
|
||||
func will_change_anything()->bool:
|
||||
var subtrahend_block:CyclopsBlock = builder.get_node(block_to_subtract_path)
|
||||
var subtrahend_vol:ConvexVolume = subtrahend_block.control_mesh
|
||||
subtrahend_vol = subtrahend_vol.transformed(subtrahend_block.global_transform)
|
||||
|
||||
if block_paths.is_empty():
|
||||
return false
|
||||
|
||||
for minuend_path in block_paths:
|
||||
var minuend_block:CyclopsBlock = builder.get_node(minuend_path)
|
||||
var minuend_vol:ConvexVolume = minuend_block.control_mesh
|
||||
minuend_vol = minuend_vol.transformed(minuend_block.global_transform)
|
||||
|
||||
if minuend_vol.intersects_convex_volume(subtrahend_vol):
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func do_it():
|
||||
var subtrahend_block:CyclopsBlock = builder.get_node(block_to_subtract_path)
|
||||
var snap_to_grid_util:SnapToGridUtil = CyclopsAutoload.calc_snap_to_grid_util()
|
||||
|
||||
if start_blocks.is_empty():
|
||||
var subtrahend_vol:ConvexVolume = subtrahend_block.control_mesh
|
||||
subtracted_block_cache = TrackedBlock.new(subtrahend_block)
|
||||
subtrahend_vol = subtrahend_vol.transformed(subtrahend_block.global_transform)
|
||||
var subtra_xform_inv:Transform3D = subtrahend_block.global_transform.affine_inverse()
|
||||
|
||||
for path in block_paths:
|
||||
var block:CyclopsBlock = builder.get_node(path)
|
||||
|
||||
var minuend_vol:ConvexVolume = block.control_mesh
|
||||
minuend_vol = minuend_vol.transformed(block.global_transform)
|
||||
if !minuend_vol.intersects_convex_volume(subtrahend_vol):
|
||||
continue
|
||||
|
||||
var tracker:TrackedBlock = TrackedBlock.new(block)
|
||||
start_blocks.append(tracker)
|
||||
|
||||
var fragments:Array[ConvexVolume] = minuend_vol.subtract(subtrahend_vol)
|
||||
|
||||
for f in fragments:
|
||||
f.copy_face_attributes(minuend_vol)
|
||||
#var centroid:Vector3 = f.get_centroid()
|
||||
#centroid = snap_to_grid_util.snap_point(centroid)
|
||||
#f.translate(-centroid)
|
||||
f = f.transformed(block.global_transform.affine_inverse())
|
||||
|
||||
var block_info:NewBlockInfo = NewBlockInfo.new()
|
||||
block_info.data = f.to_mesh_vector_data()
|
||||
block_info.materials = block.materials
|
||||
block_info.xform = block.global_transform
|
||||
#block_info.centroid = centroid
|
||||
added_blocks.append(block_info)
|
||||
|
||||
#Delete source blocks
|
||||
for block_info in start_blocks:
|
||||
var del_block:CyclopsBlock = builder.get_node(block_info.path)
|
||||
del_block.queue_free()
|
||||
|
||||
subtrahend_block.queue_free()
|
||||
|
||||
#Create blocks
|
||||
for info in added_blocks:
|
||||
var block:CyclopsBlock = preload("../nodes/cyclops_block.gd").new()
|
||||
var parent:Node = builder.get_node(start_blocks[0].path_parent)
|
||||
parent.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = GeneralUtil.find_unique_name(parent, block_name_prefix)
|
||||
block.mesh_vector_data = info.data
|
||||
block.materials = info.materials
|
||||
# block.global_transform = Transform3D.IDENTITY.translated(info.centroid)
|
||||
block.global_transform = info.xform
|
||||
|
||||
info.path = block.get_path()
|
||||
|
||||
|
||||
|
||||
func undo_it():
|
||||
|
||||
for info in added_blocks:
|
||||
var added_block:CyclopsBlock = builder.get_node(info.path)
|
||||
added_block.queue_free()
|
||||
|
||||
restore_tracked_block(subtracted_block_cache)
|
||||
|
||||
for tracked in start_blocks:
|
||||
restore_tracked_block(tracked)
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
# 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
|
||||
class_name CommandTransformBlocks
|
||||
extends CyclopsCommand
|
||||
|
||||
#Public data to set before activating command
|
||||
var transform:Transform3D
|
||||
var lock_uvs:bool = false
|
||||
|
||||
#Private
|
||||
var tracked_blocks:Array[TrackedBlock]
|
||||
|
||||
func _init():
|
||||
command_name = "Transform blocks"
|
||||
|
||||
#Add blocks to be moved here
|
||||
func add_block(block_path:NodePath):
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var tracked:TrackedBlock = TrackedBlock.new(block)
|
||||
tracked_blocks.append(tracked)
|
||||
|
||||
#Moves all blocks from the start position by this amount
|
||||
func move_to(offset:Vector3):
|
||||
for tracked in tracked_blocks:
|
||||
var block:CyclopsBlock = builder.get_node(tracked.path)
|
||||
var w_init_xform:Transform3D = tracked.world_xform
|
||||
|
||||
var new_w_xform:Transform3D = w_init_xform.translated(offset)
|
||||
block.global_transform = new_w_xform
|
||||
|
||||
|
||||
func do_it():
|
||||
for tracked in tracked_blocks:
|
||||
var block:CyclopsBlock = builder.get_node(tracked.path)
|
||||
var w_init_xform:Transform3D = tracked.world_xform
|
||||
|
||||
var new_w_xform:Transform3D = transform * w_init_xform
|
||||
block.global_transform = new_w_xform
|
||||
|
||||
if !lock_uvs:
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(tracked.data)
|
||||
|
||||
var uv_xform:Transform3D = transform.affine_inverse()
|
||||
vol.transform_uvs(uv_xform)
|
||||
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
|
||||
func undo_it():
|
||||
for tracked in tracked_blocks:
|
||||
var block:CyclopsBlock = builder.get_node(tracked.path)
|
||||
block.global_transform = tracked.world_xform
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
# 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.
|
||||
|
||||
#Applied trnasorm of points in local space
|
||||
|
||||
@tool
|
||||
class_name CommandTransformVertices
|
||||
extends CyclopsCommand
|
||||
|
||||
class TrackedInfo extends RefCounted:
|
||||
var data:MeshVectorData
|
||||
# var materials:Array[Material]
|
||||
|
||||
#Local space transform of points
|
||||
var transform:Transform3D
|
||||
var lock_uvs:bool = false
|
||||
|
||||
#Private
|
||||
var blocks_to_move:Array[NodePath]
|
||||
var tracked_block_data:Array[TrackedInfo]
|
||||
|
||||
func _init():
|
||||
command_name = "Transform vertices"
|
||||
|
||||
#Add blocks to be moved here
|
||||
func add_block(block_path:NodePath):
|
||||
blocks_to_move.append(block_path)
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
#tracked_blocks.append(block)
|
||||
var info:TrackedInfo = TrackedInfo.new()
|
||||
info.data = block.mesh_vector_data.duplicate()
|
||||
# info.materials = block.materials
|
||||
tracked_block_data.append(info)
|
||||
|
||||
#Moves all blocks from the start position by this amount
|
||||
func apply_transform(xform:Transform3D):
|
||||
for i in blocks_to_move.size():
|
||||
var block:CyclopsBlock = builder.get_node(blocks_to_move[i])
|
||||
|
||||
var ctl_mesh:ConvexVolume = ConvexVolume.new()
|
||||
ctl_mesh.init_from_mesh_vector_data(tracked_block_data[i].data)
|
||||
ctl_mesh.transform(xform, lock_uvs)
|
||||
var result_data:MeshVectorData = ctl_mesh.to_mesh_vector_data()
|
||||
block.mesh_vector_data = result_data
|
||||
|
||||
|
||||
func do_it():
|
||||
apply_transform(transform)
|
||||
|
||||
func undo_it():
|
||||
apply_transform(Transform3D.IDENTITY)
|
||||
|
||||
130
addons/cyclops_level_builder/commands/cmd_vertex_paint_stroke.gd
Normal file
130
addons/cyclops_level_builder/commands/cmd_vertex_paint_stroke.gd
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# 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
|
||||
class_name CommandVertexPaintStroke
|
||||
extends CyclopsCommand
|
||||
|
||||
@export var color:Color = Color.WHITE
|
||||
@export var strength:float = 1
|
||||
@export var radius:float = 1
|
||||
@export var falloff_curve:Curve
|
||||
|
||||
enum MaskType { NONE, VERTICES, FACES }
|
||||
@export var mask:MaskType = MaskType.NONE
|
||||
|
||||
#Private
|
||||
var block_map:Dictionary = {}
|
||||
#var block_tgt_map:Dictionary = {}
|
||||
|
||||
|
||||
var pen_stroke:PenStroke = PenStroke.new()
|
||||
|
||||
func append_block(block_path:NodePath):
|
||||
if block_map.has(block_path):
|
||||
return
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
#print("stroing block faces ", block.block_data.face_vertex_face_index)
|
||||
|
||||
block_map[block_path] = block.mesh_vector_data.duplicate(true)
|
||||
#print("stroing block faces ", block.block_data.face_vertex_face_index)
|
||||
# block_tgt_map[block_path] = block.block_data.duplicate(true)
|
||||
|
||||
func append_stroke_point(position:Vector3, pressure:float = 1):
|
||||
pen_stroke.append_stroke_point(position, pressure)
|
||||
#print("--pen_stroke ", pen_stroke.stroke_points)
|
||||
|
||||
func _init():
|
||||
command_name = "Paint Vertex Color Stroke"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
return !(block_map.is_empty() || pen_stroke.is_empty())
|
||||
|
||||
func do_it():
|
||||
#print("sel verts do_it")
|
||||
# print("sel uv_transform do_it()")
|
||||
|
||||
#print("stroke pts ", str(pen_stroke.stroke_points))
|
||||
var stroke_resamp:PenStroke = pen_stroke.resample_points(radius * .1)
|
||||
#print("stroke resamp pts ", str(stroke_resamp.stroke_points))
|
||||
|
||||
for block_path in block_map.keys():
|
||||
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
var w2l:Transform3D = block.global_transform.affine_inverse()
|
||||
#print("painting block ", block.name)
|
||||
|
||||
var block_data:MeshVectorData = block_map[block_path]
|
||||
#print("block_data raw faces ", block_data.face_vertex_face_index)
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_mesh_vector_data(block_data)
|
||||
|
||||
#Apply stroke
|
||||
for stroke_pt in stroke_resamp.stroke_points:
|
||||
var pos_local:Vector3 = w2l * stroke_pt.position
|
||||
for fv in vol.face_vertices:
|
||||
var v:ConvexVolume.VertexInfo = vol.vertices[fv.vertex_index]
|
||||
var f:ConvexVolume.FaceInfo = vol.faces[fv.face_index]
|
||||
|
||||
if mask == MaskType.FACES:
|
||||
if !f.selected:
|
||||
continue
|
||||
elif mask == MaskType.VERTICES:
|
||||
if !v.selected:
|
||||
continue
|
||||
|
||||
var dist:float = v.point.distance_to(pos_local)
|
||||
|
||||
if dist > radius:
|
||||
continue
|
||||
|
||||
var falloff_frac:float = 1 - (dist / radius)
|
||||
var falloff:float = falloff_curve.sample(falloff_frac) \
|
||||
if falloff_curve else 1
|
||||
|
||||
fv.color = MathUtil.blend_colors_ignore_alpha(\
|
||||
color, fv.color, strength * stroke_pt.pressure * falloff)
|
||||
|
||||
#print("fv_idx ", fv.index)
|
||||
#print("fv color ", fv.color)
|
||||
|
||||
var new_block_data:MeshVectorData = vol.to_mesh_vector_data()
|
||||
#print("new_block_data faces ", block.block_data.face_vertex_face_index)
|
||||
block.mesh_vector_data = new_block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
func undo_it():
|
||||
# print("undo_it() select faces")
|
||||
for block_path in block_map.keys():
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
|
||||
var block_data:MeshVectorData = block_map[block_path]
|
||||
|
||||
block.mesh_vector_data = block_data
|
||||
|
||||
builder.selection_changed.emit()
|
||||
|
||||
77
addons/cyclops_level_builder/commands/cyclops_command.gd
Normal file
77
addons/cyclops_level_builder/commands/cyclops_command.gd
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# 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
|
||||
class_name CyclopsCommand
|
||||
extends RefCounted
|
||||
|
||||
var command_name:String = ""
|
||||
var builder:CyclopsLevelBuilder
|
||||
|
||||
class TrackedBlock extends RefCounted:
|
||||
var path:NodePath
|
||||
var path_parent:NodePath
|
||||
var data:MeshVectorData
|
||||
var world_xform:Transform3D
|
||||
var materials:Array[Material]
|
||||
var selected:bool
|
||||
var name:String
|
||||
var collision_type:Collision.Type
|
||||
var collision_layers:int
|
||||
var collision_mask:int
|
||||
|
||||
func _init(block:CyclopsBlock):
|
||||
path = block.get_path()
|
||||
path_parent = block.get_parent().get_path()
|
||||
name = block.name
|
||||
data = block.mesh_vector_data.duplicate()
|
||||
world_xform = block.global_transform
|
||||
#selected = block.selected
|
||||
materials = block.materials
|
||||
collision_type = block.collision_type
|
||||
collision_layers = block.collision_layer
|
||||
collision_mask = block.collision_mask
|
||||
|
||||
func add_to_undo_manager(undo_manager:EditorUndoRedoManager):
|
||||
undo_manager.create_action(command_name, UndoRedo.MERGE_DISABLE)
|
||||
undo_manager.add_do_method(self, "do_it")
|
||||
undo_manager.add_undo_method(self, "undo_it")
|
||||
|
||||
undo_manager.commit_action()
|
||||
|
||||
func node_global_transform(node:Node)->Transform3D:
|
||||
var node_parent:Node3D
|
||||
while node:
|
||||
if node is Node3D:
|
||||
node_parent = node
|
||||
break
|
||||
node = node.get_parent()
|
||||
|
||||
return node_parent.global_transform if node_parent else Transform3D.IDENTITY
|
||||
|
||||
func do_it()->void:
|
||||
pass
|
||||
|
||||
func undo_it()->void:
|
||||
pass
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
# 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
|
||||
class_name CommandImportCyclopsFile
|
||||
extends CyclopsCommand
|
||||
|
||||
@export var file_path:String
|
||||
@export var target_parent:NodePath
|
||||
|
||||
var added_blocks:Array[NodePath]
|
||||
|
||||
func _init():
|
||||
command_name = "Import Cyclops File"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
return FileAccess.file_exists(file_path)
|
||||
|
||||
func do_it():
|
||||
if !FileAccess.file_exists(file_path):
|
||||
push_error("No such file: ", file_path)
|
||||
return
|
||||
|
||||
var source:String = FileAccess.get_file_as_string(file_path)
|
||||
var raw = JSON.parse_string(source)
|
||||
if !(raw is Dictionary):
|
||||
push_error("Invalid file format: ", file_path)
|
||||
return
|
||||
|
||||
load_file(raw)
|
||||
|
||||
pass
|
||||
|
||||
|
||||
func load_file(root:Dictionary):
|
||||
var loader:CyclopsFileLoader = CyclopsFileLoader.new()
|
||||
loader.load(root)
|
||||
|
||||
var editor_scene_root:Node = builder.get_editor_interface().get_edited_scene_root()
|
||||
|
||||
|
||||
for scene_id in loader.scene_map.keys():
|
||||
var root_node_id:int = loader.scene_map[scene_id]
|
||||
var loaded_scene:Node3D = loader.node_map[root_node_id]
|
||||
|
||||
editor_scene_root.add_child(loaded_scene)
|
||||
set_owner_recursive(loaded_scene, editor_scene_root)
|
||||
|
||||
added_blocks.append(loaded_scene.get_path())
|
||||
|
||||
|
||||
func undo_it():
|
||||
for block_path in added_blocks:
|
||||
var block:Node3D = builder.get_node(block_path)
|
||||
block.queue_free()
|
||||
|
||||
added_blocks.clear()
|
||||
|
||||
func set_owner_recursive(loaded_node:Node3D, owner_node:Node3D):
|
||||
loaded_node.owner = owner_node
|
||||
if loaded_node is CyclopsBlock:
|
||||
#Do not set owner of hidden children
|
||||
return
|
||||
|
||||
for child in loaded_node.get_children():
|
||||
set_owner_recursive(child, owner_node)
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
# 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
|
||||
class_name CommandImportGodotMeshes
|
||||
extends CyclopsCommand
|
||||
|
||||
@export var source_nodes:Array[NodePath]
|
||||
@export var target_parent:NodePath
|
||||
@export var collision_type:Collision.Type = Collision.Type.STATIC
|
||||
@export var collision_layers:int = 1
|
||||
@export var collision_mask:int = 1
|
||||
|
||||
var added_blocks:Array[NodePath]
|
||||
|
||||
func _init():
|
||||
command_name = "Import Godot Meshes"
|
||||
|
||||
func will_change_anything()->bool:
|
||||
return !target_parent.is_empty() && !source_nodes.is_empty()
|
||||
|
||||
func do_it():
|
||||
var tgt_parent_node:Node = builder.get_node(target_parent)
|
||||
if !tgt_parent_node || !(tgt_parent_node is Node3D):
|
||||
return
|
||||
|
||||
for src_path in source_nodes:
|
||||
var src_node:Node = builder.get_node(src_path)
|
||||
if !src_node is MeshInstance3D:
|
||||
continue
|
||||
|
||||
var src_mesh_inst:MeshInstance3D = src_node
|
||||
if !src_mesh_inst.mesh:
|
||||
continue
|
||||
|
||||
var block:CyclopsBlock = preload("res://addons/cyclops_level_builder/nodes/cyclops_block.gd").new()
|
||||
|
||||
var blocks_root:Node3D = tgt_parent_node
|
||||
blocks_root.add_child(block)
|
||||
block.owner = builder.get_editor_interface().get_edited_scene_root()
|
||||
block.name = src_node.name
|
||||
block.global_transform = src_node.global_transform
|
||||
block.collision_type = collision_type
|
||||
block.collision_layer = collision_layers
|
||||
block.collision_mask = collision_mask
|
||||
|
||||
added_blocks.append(block.get_path())
|
||||
|
||||
var best_mat:Material
|
||||
var points:PackedVector3Array
|
||||
for i in src_mesh_inst.mesh.get_surface_count():
|
||||
var mat:Material = src_mesh_inst.mesh.surface_get_material(i)
|
||||
if best_mat != null:
|
||||
best_mat = mat
|
||||
|
||||
var surface_arrs:Array = src_mesh_inst.mesh.surface_get_arrays(i)
|
||||
|
||||
if surface_arrs[Mesh.ARRAY_INDEX].is_empty():
|
||||
for pt in surface_arrs[Mesh.ARRAY_VERTEX]:
|
||||
points.append(pt)
|
||||
else:
|
||||
for idx in surface_arrs[Mesh.ARRAY_INDEX]:
|
||||
points.append(surface_arrs[Mesh.ARRAY_VERTEX][idx])
|
||||
|
||||
if best_mat:
|
||||
block.materials = [best_mat]
|
||||
|
||||
var vol:ConvexVolume = ConvexVolume.new()
|
||||
vol.init_from_points(points, Transform2D.IDENTITY, 0 if best_mat else -1)
|
||||
block.mesh_vector_data = vol.to_mesh_vector_data()
|
||||
|
||||
|
||||
func undo_it():
|
||||
for block_path in added_blocks:
|
||||
var block:CyclopsBlock = builder.get_node(block_path)
|
||||
block.queue_free()
|
||||
|
||||
added_blocks.clear()
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue