initial commit

This commit is contained in:
2023-05-24 00:27:34 +03:00
commit 11ee2c7949
174 changed files with 13452 additions and 0 deletions

View File

@ -0,0 +1,69 @@
# 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 CommandAddBlock2
extends CyclopsCommand
#Public data to set before activating command
var blocks_root_path:NodePath
var block_name:String
var bounds:AABB
var material_path:String
var uv_transform:Transform2D = Transform2D.IDENTITY
#Private data
var block_path:NodePath
func _init():
command_name = "Add block"
func do_it():
var block:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
var blocks_root:CyclopsBlocks = 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
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 mesh:ConvexVolume = ConvexVolume.new()
mesh.init_block(bounds, uv_transform, material_id)
block.block_data = mesh.to_convex_block_data()
block_path = block.get_path()
# print("AddBlockCommand do_it() %s %s" % [block_inst_id, bounds])
func undo_it():
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.queue_free()
# print("AddBlockCommand undo_it()")

View 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 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
#Private data
var block_paths:Array[NodePath]
func _init():
command_name = "Add cylinder"
func create_block(blocks_root:CyclopsBlocks, mat:Material)->CyclopsConvexBlock:
var block:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
blocks_root.add_child(block)
block.owner = builder.get_editor_interface().get_edited_scene_root()
block.name = GeneralUtil.find_unique_name(builder.active_node, block_name_prefix)
if mat:
block.materials.append(mat)
return block
func do_it():
var blocks_root:CyclopsBlocks = 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
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:CyclopsConvexBlock = create_block(blocks_root, 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)
block.block_data = mesh.to_convex_block_data()
block_paths.append(block.get_path())
else:
var block:CyclopsConvexBlock = create_block(blocks_root, 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)
block.block_data = mesh.to_convex_block_data()
block_paths.append(block.get_path())
func undo_it():
for path in block_paths:
var block:CyclopsConvexBlock = builder.get_node(path)
block.queue_free()

View File

@ -0,0 +1,69 @@
# 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
var blocks_root_path:NodePath
var block_name:String
var base_polygon:PackedVector3Array
var extrude:Vector3
var uv_transform:Transform2D
var material_path:String
#Private
var block_path:NodePath
func _init():
command_name = "Add prism"
func do_it():
var block:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
var blocks_root:CyclopsBlocks = builder.get_node(blocks_root_path)
blocks_root.add_child(block)
block.owner = builder.get_editor_interface().get_edited_scene_root()
# block.owner = block_owner
block.name = block_name
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 mesh:ConvexVolume = ConvexVolume.new()
mesh.init_prism(base_polygon, extrude, uv_transform, material_id)
block.block_data = mesh.to_convex_block_data()
block_path = block.get_path()
# print("AddBlockCommand do_it() %s %s" % [block_inst_id, bounds])
func undo_it():
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.queue_free()
# print("AddBlockCommand undo_it()")

View 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 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
#Private data
var block_paths:Array[NodePath]
func _init():
command_name = "Add stairs"
func create_block(blocks_root:CyclopsBlocks, mat:Material)->CyclopsConvexBlock:
var block:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
blocks_root.add_child(block)
block.owner = builder.get_editor_interface().get_edited_scene_root()
block.name = GeneralUtil.find_unique_name(builder.active_node, block_name_prefix)
if mat:
block.materials.append(mat)
return block
func do_it():
var blocks_root:CyclopsBlocks = 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 mesh:ConvexVolume = ConvexVolume.new()
mesh.init_prism(base_points, \
floor_normal * (max_height - step_height * i), \
uv_transform, material_id)
var block:CyclopsConvexBlock = create_block(blocks_root, material)
block.block_data = mesh.to_convex_block_data()
block_paths.append(block.get_path())
# global_scene.draw_prism(base_points, \
# floor_normal * (max_height - step_height * i), \
# global_scene.tool_material)
# 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:CyclopsConvexBlock = create_block(blocks_root, 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)
#
# block.block_data = mesh.to_convex_block_data()
# block_paths.append(block.get_path())
func undo_it():
for path in block_paths:
var block:CyclopsConvexBlock = builder.get_node(path)
block.queue_free()

View File

@ -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.
@tool
class_name CommandAddVertices
extends CyclopsCommand
#Public
var points_to_add:PackedVector3Array
var block_path:NodePath
#Private
var tracked_block_data:ConvexBlockData
var selected_points:PackedVector3Array
func _init():
command_name = "Add vertices"
func do_it():
var block:CyclopsConvexBlock = builder.get_node(block_path)
if !tracked_block_data:
var tracked_vol:ConvexVolume = block.control_mesh
tracked_block_data = tracked_vol.to_convex_block_data()
for v in tracked_vol.vertices:
if v.selected:
selected_points.append(v.point)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(tracked_block_data)
var point_list:PackedVector3Array = vol.get_points()
point_list.append_array(points_to_add)
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.block_data = new_vol.to_convex_block_data()
func undo_it():
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = tracked_block_data

View 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 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:ConvexBlockData
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:CyclopsBlocks = builder.get_node(blocks_root_path)
var block:CyclopsConvexBlock = builder.get_node(block_path)
old_block_data = block.block_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 vol0:ConvexVolume = block.control_mesh.cut_with_plane(cut_plane, uv_transform, cut_mat_idx)
var vol1:ConvexVolume = block.control_mesh.cut_with_plane(MathUtil.flip_plane(cut_plane), uv_transform, cut_mat_idx)
#Set data of existing block
block.block_data = vol0.to_convex_block_data()
block.materials = new_mat_list0
#Create second block
var block_sibling:CyclopsConvexBlock = preload("../nodes/cyclops_convex_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.selected = block.selected
block_sibling_path = block_sibling.get_path()
block_sibling.block_data = vol1.to_convex_block_data()
block_sibling.materials = new_mat_list1
func undo_it():
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = old_block_data
block.materials = old_mat_list.duplicate()
var block_sibling:CyclopsConvexBlock = builder.get_node(block_sibling_path)
block_sibling.queue_free()

View File

@ -0,0 +1,93 @@
# 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
class TrackedBlock extends RefCounted:
var path:NodePath
var path_parent:NodePath
var data:ConvexBlockData
var materials:Array[Material]
var selected:bool
var name:String
func _init(block:CyclopsConvexBlock):
path = block.get_path()
path_parent = block.get_parent().get_path()
name = block.name
data = block.block_data.duplicate()
selected = block.selected
materials = block.materials
#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:CyclopsConvexBlock = 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:CyclopsConvexBlock = builder.get_node(block_path)
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:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
block.block_data = tracked.data
block.materials = tracked.materials
block.name = tracked.name
block.selected = tracked.selected
parent.add_child(block)
block.owner = builder.get_editor_interface().get_edited_scene_root()

View File

@ -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 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:CyclopsConvexBlock
var source_data:ConvexBlockData
#var materials:Array[Material]
func _init(new_block:CyclopsConvexBlock, source_data:ConvexBlockData):
self.new_block = new_block
self.source_data = source_data
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:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
var source_block:CyclopsConvexBlock = builder.get_node(block_path)
var blocks_root:CyclopsBlocks = 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()
var info:BlockInfo = BlockInfo.new(new_block, source_block.block_data)
new_block.materials = source_block.materials
new_block.selected = true
added_blocks.append(info)
for path in blocks_to_duplicate:
var block:CyclopsConvexBlock = builder.get_node(path)
block.selected = false
for info in added_blocks:
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(info.source_data)
vol.translate(move_offset, lock_uvs)
info.new_block.block_data = vol.to_convex_block_data()
func undo_it():
for block in added_blocks:
block.new_block.queue_free()
added_blocks = []
for path in blocks_to_duplicate:
var block:CyclopsConvexBlock = builder.get_node(path)
block.selected = true

View File

@ -0,0 +1,149 @@
# 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
class TrackedBlock extends RefCounted:
var path:NodePath
var path_parent:NodePath
var data:ConvexBlockData
var materials:Array[Material]
var selected:bool
var name:String
func _init(block:CyclopsConvexBlock):
path = block.get_path()
path_parent = block.get_parent().get_path()
name = block.name
data = block.block_data.duplicate()
selected = block.selected
materials = block.materials
#Public
var block_paths:Array[NodePath]
var block_name_prefix:String = "Block_"
#Private
var tracked_blocks:Array[TrackedBlock]
var merged_block_data:ConvexBlockData
var merged_mat_list:Array[Material]
var merged_block_path:NodePath
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:CyclopsConvexBlock
for block_path in ref_list:
var block:CyclopsConvexBlock = 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
for path in block_paths:
var block:CyclopsConvexBlock = builder.get_node(path)
var tracker:TrackedBlock = TrackedBlock.new(block)
tracked_blocks.append(tracker)
points.append_array(block.control_mesh.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_block_data = merged_vol.to_convex_block_data()
#Delete source blocks
for block_path in block_paths:
var del_block:CyclopsConvexBlock = builder.get_node(block_path)
del_block.queue_free()
#Create block
var block:CyclopsConvexBlock = preload("../nodes/cyclops_convex_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.block_data = merged_block_data
block.materials = merged_mat_list
#block.materials
merged_block_path = block.get_path()
func undo_it():
# var blocks_root:CyclopsBlocks = builder.get_node(blocks_root_path)
var merged_block:CyclopsConvexBlock = 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:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
block.block_data = tracked.data
block.materials = tracked.materials
block.name = tracked.name
block.selected = tracked.selected
parent.add_child(block)
block.owner = builder.get_editor_interface().get_edited_scene_root()

View File

@ -0,0 +1,64 @@
# 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 CommandMoveBlocks
extends CyclopsCommand
#Public data to set before activating command
var move_offset:Vector3
var lock_uvs:bool = false
#Private
var blocks_to_move:Array[NodePath]
var tracked_block_data:Array[ConvexBlockData]
func _init():
command_name = "Move blocks"
#Add blocks to be moved here
func add_block(block_path:NodePath):
blocks_to_move.append(block_path)
var block:CyclopsConvexBlock = builder.get_node(block_path)
#tracked_blocks.append(block)
tracked_block_data.append(block.block_data.duplicate())
#Moves all blocks from the start position by this amount
func move_to(offset:Vector3):
for i in blocks_to_move.size():
var block:CyclopsConvexBlock = builder.get_node(blocks_to_move[i])
var ctl_mesh:ConvexVolume = ConvexVolume.new()
ctl_mesh.init_from_convex_block_data(tracked_block_data[i])
ctl_mesh.translate(offset, lock_uvs)
var result_data:ConvexBlockData = ctl_mesh.to_convex_block_data()
block.block_data = result_data
#tracked_blocks[block_idx].block_data = result_data
func do_it():
move_to(move_offset)
func undo_it():
move_to(Vector3.ZERO)

View File

@ -0,0 +1,132 @@
# 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:ConvexBlockData
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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:CyclopsConvexBlock = builder.get_node(block_path)
var rec:BlockEdgeChanges = block_map[block_path]
# print("rec %s" % rec)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(rec.tracked_block_data)
# print("init done")
#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)
if !moved_indices.has(e.start_index):
new_points.append(v0.point + move_offset)
moved_indices.append(e.start_index)
if !moved_indices.has(e.end_index):
new_points.append(v1.point + move_offset)
moved_indices.append(e.end_index)
else:
if !moved_indices.has(e.start_index):
new_points.append(v0.point + move_offset)
moved_indices.append(e.start_index)
if !moved_indices.has(e.end_index):
new_points.append(v1.point + move_offset)
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.block_data = new_vol.to_convex_block_data()
func undo_it():
for block_path in block_map.keys():
var rec:BlockEdgeChanges = block_map[block_path]
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data

View File

@ -0,0 +1,104 @@
# 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_id:int
var lock_uvs:bool = false
#Private
var block_name:String
var block_selected:bool
var tracked_block_data:ConvexBlockData
var deleted:bool = false
func _init():
command_name = "Move face planar"
func move_to(offset:Vector3, intermediate:bool):
# print("move_to off %s faceid %s amount %s movedir %s" % [offset, face_id, move_amount, move_dir_normal])
if !tracked_block_data:
var block:CyclopsConvexBlock = builder.get_node(block_path)
block_name = block.name
block_selected = block.selected
tracked_block_data = block.block_data
var ctl_mesh:ConvexVolume = ConvexVolume.new()
ctl_mesh.init_from_convex_block_data(tracked_block_data)
var new_mesh:ConvexVolume = ctl_mesh.translate_face_plane(face_id, offset, lock_uvs)
#print("offset %s" % offset)
#print("ctl_mesh %s" % ctl_mesh.get_points())
var block:CyclopsConvexBlock = 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
#ctl_mesh.remove_unused_planes()
#print("new_mesh %s" % new_mesh.get_points())
var result_data:ConvexBlockData = new_mesh.to_convex_block_data()
# var result_data:ConvexBlockData = ctl_mesh.to_convex_block_data()
block.block_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:CyclopsConvexBlock = preload("../nodes/cyclops_convex_block.gd").new()
var blocks_root:CyclopsBlocks = builder.get_node(blocks_root_path)
blocks_root.add_child(block)
block.owner = builder.get_editor_interface().get_edited_scene_root()
block.block_data = tracked_block_data
block.name = block_name
block.selected = block_selected
deleted = false
return
move_to(Vector3.ZERO, false)

View File

@ -0,0 +1,131 @@
# 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:ConvexBlockData
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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:CyclopsConvexBlock = builder.get_node(block_path)
var rec:BlockFaceChanges = block_map[block_path]
# print("rec %s" % rec)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(rec.tracked_block_data)
# print("init done")
#var moved_vert_indices:PackedInt32Array
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)
for v_idx in f.vertex_indices:
if !moved_vert_indices.has(v_idx):
new_points.append(vol.vertices[v_idx].point + move_offset)
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)
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.block_data = new_vol.to_convex_block_data()
func undo_it():
for block_path in block_map.keys():
var rec:BlockFaceChanges = block_map[block_path]
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data

View File

@ -0,0 +1,105 @@
# 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:ConvexBlockData
#Public
var move_offset:Vector3 = Vector3.ZERO
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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 = "Move vertices"
func do_it():
# print("move verts do_it")
for block_path in block_map.keys():
var block:CyclopsConvexBlock = builder.get_node(block_path)
var rec:BlockVertexChanges = block_map[block_path]
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(rec.tracked_block_data)
# print("rec.vertex_indices %s" % rec.vertex_indices)
# print("move_offset %s" % move_offset)
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
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.block_data = new_vol.to_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data

View File

@ -0,0 +1,135 @@
# 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]
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]
for child in builder.active_node.get_children():
if child is CyclopsConvexBlock:
var block:CyclopsConvexBlock = 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
return false
func do_it():
# print("sel verts do_it")
#Cache state
tracked_selected_blocks.clear()
tracked_active_blocks.clear()
for child in builder.active_node.get_children():
if child is CyclopsConvexBlock:
var block:CyclopsConvexBlock = child
if block.selected:
tracked_selected_blocks.append(block.get_path())
if block.active:
tracked_active_blocks.append(block.get_path())
#Do selection
var active_path:NodePath
if !block_paths.is_empty():
active_path = block_paths[0]
for child in builder.active_node.get_children():
if child is CyclopsConvexBlock:
var block:CyclopsConvexBlock = 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:
block.active = path == active_path
if block_paths.has(path):
block.selected = !block.selected
if !block.selected:
block.active = false
builder.selection_changed.emit()
func undo_it():
for child in builder.active_node.get_children():
if child is CyclopsConvexBlock:
var block:CyclopsConvexBlock = 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()

View File

@ -0,0 +1,189 @@
# 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:ConvexBlockData
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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:CyclopsConvexBlock = builder.get_node(block_path)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_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
#Synchronize vertex & face selection
#print("synchronizing verts")
# var selected_verts:Array[int] = []
# for e in vol.edges:
# if e.selected:
# for v_idx in [e.start_index, e.end_index]:
# if !selected_verts.has(v_idx):
# #print("selecting vert %s" % v_idx)
# selected_verts.append(v_idx)
# for v_idx in vol.vertices.size():
# vol.vertices[v_idx].selected = selected_verts.has(v_idx)
# vol.update_edge_and_face_selection_from_vertices()
block.block_data = vol.to_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data
builder.selection_changed.emit()

View File

@ -0,0 +1,180 @@
# 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:ConvexBlockData
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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:CyclopsConvexBlock = builder.get_node(block_path)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_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
#Synchronize edge & vertex selection
# var selected_verts:Array[int] = []
# for f in vol.faces:
# if f.selected:
# for v_idx in f.vertex_indices:
# if !selected_verts.has(v_idx):
# selected_verts.append(v_idx)
# for v_idx in vol.vertices.size():
# vol.vertices[v_idx].selected = selected_verts.has(v_idx)
# vol.update_edge_and_face_selection_from_vertices()
block.block_data = vol.to_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data
builder.selection_changed.emit()

View File

@ -0,0 +1,167 @@
# 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:ConvexBlockData
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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:CyclopsConvexBlock = builder.get_node(block_path)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(rec.tracked_block_data)
if !rec.vertex_indices.is_empty():
var active_index:int = rec.vertex_indices[0]
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
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()
block.block_data = vol.to_convex_block_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:BlockVertexChanges = block_map[block_path]
var block:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data
builder.selection_changed.emit()

View File

@ -0,0 +1,153 @@
# 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:ConvexBlockData
var materials:Array[Material]
#Public
var material_path:String
#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 = Target.new()
target.block_path = block_path
target.face_indices = face_indices
target_list.append(target)
func make_cache():
cache_list = []
for t in target_list:
var cache:BlockCache = BlockCache.new()
var block:CyclopsConvexBlock = builder.get_node(t.block_path)
cache.path = block.get_path()
cache.data = block.block_data
cache.materials = block.materials.duplicate()
cache_list.append(cache)
func will_change_anything()->bool:
for t in target_list:
if !t.face_indices.is_empty():
return true
return false
func _init():
command_name = "Set material"
func do_it():
make_cache()
# print("cmd set material %s" % material_path)
for t in target_list:
var block:CyclopsConvexBlock = builder.get_node(t.block_path)
var data:ConvexBlockData = block.block_data
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_data(data)
var mat_list:Array[Material] = block.materials.duplicate()
# print("start mat list")
# for m in mat_list:
# print("cur mat %s" % "?" if m == null else m.resource_path)
var target_material:Material
for m in mat_list:
if m.resource_path == material_path:
target_material = m
break
if !target_material:
target_material = load(material_path)
mat_list.append(target_material)
# print("target mat list")
# for m in mat_list:
# print("mat %s" % "?" if m == null else m.resource_path)
var remap_face_idx_to_mat:Array[Material] = []
var ctl_mesh:ConvexVolume = ConvexVolume.new()
ctl_mesh.init_from_convex_block_data(block.control_mesh.to_convex_block_data())
for f_idx in ctl_mesh.faces.size():
var f:ConvexVolume.FaceInfo = ctl_mesh.faces[f_idx]
if t.face_indices.has(f_idx):
remap_face_idx_to_mat.append(target_material)
elif f.material_id >= 0 && f.material_id < block.materials.size():
remap_face_idx_to_mat.append(block.materials[f.material_id])
else:
remap_face_idx_to_mat.append(null)
# print("remap faceidx to mat")
# for m in remap_face_idx_to_mat:
# print("mat %s" % "?" if m == null else m.resource_path)
#Reduce material list, discarding unused materials
var mat_list_reduced:Array[Material]
for m in remap_face_idx_to_mat:
if m != null && !mat_list_reduced.has(m):
mat_list_reduced.append(m)
# print("mat_list_reduced")
# for m in mat_list_reduced:
# print("mat %s" % "?" if m == null else m.resource_path)
#Set new face materials using new material ids
for f_idx in remap_face_idx_to_mat.size():
#print("face_idx %s" % f_idx)
var face:ConvexVolume.FaceInfo = ctl_mesh.faces[f_idx]
var mat = remap_face_idx_to_mat[f_idx]
#print("mat %s" % "?" if mat == null else mat.resource_path)
#print("has %s" % mat_list_reduced.has(mat))
#print("find %s" % mat_list_reduced.find(mat))
face.material_id = -1 if mat == null else mat_list_reduced.find(mat)
#print("face.material_id %s" % face.material_id)
block.materials = mat_list_reduced
block.block_data = ctl_mesh.to_convex_block_data()
func undo_it():
for cache in cache_list:
var block:CyclopsConvexBlock = builder.get_node(cache.path)
block.materials = cache.materials.duplicate()
block.block_data = cache.data

View File

@ -0,0 +1,110 @@
# 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 CommandSetUvTransform
extends CyclopsCommand
class BlockFaceChanges extends RefCounted:
var block_path:NodePath
var face_indices:Array[int] = []
var tracked_block_data:ConvexBlockData
var uv_transform:Transform2D = Transform2D.IDENTITY
#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:CyclopsConvexBlock = builder.get_node(block_path)
changes.tracked_block_data = block.block_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 Uv Transform"
func will_change_anything()->bool:
for block_path in block_map.keys():
var rec:BlockFaceChanges = block_map[block_path]
var block:CyclopsConvexBlock = builder.get_node(block_path)
# print("face active index %s" % active_idx)
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.uv_transform != uv_transform:
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:CyclopsConvexBlock = builder.get_node(block_path)
# print("face active index %s" % active_idx)
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]
f.uv_transform = uv_transform
block.block_data = vol.to_convex_block_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:CyclopsConvexBlock = builder.get_node(block_path)
block.block_data = rec.tracked_block_data
builder.selection_changed.emit()

View 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 CommandSnapToGrid
extends CyclopsCommand
class TrackedInfo extends RefCounted:
var data:ConvexBlockData
var grid_size:float
#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:CyclopsConvexBlock = builder.get_node(block_path)
#tracked_blocks.append(block)
var info:TrackedInfo = TrackedInfo.new()
info.data = block.block_data.duplicate()
# info.materials = block.materials
tracked_block_data.append(info)
func do_it():
for i in blocks_to_move.size():
var block:CyclopsConvexBlock = builder.get_node(blocks_to_move[i])
var vol:ConvexVolume = ConvexVolume.new()
vol.init_from_convex_block_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 = MathUtil.snap_to_grid(v.point, grid_size)
points_new.append(p_snap)
var new_vol:ConvexVolume = ConvexVolume.new()
new_vol.init_from_points(points_new)
new_vol.copy_face_attributes(vol)
block.block_data = new_vol.to_convex_block_data()
func undo_it():
for i in blocks_to_move.size():
var block:CyclopsConvexBlock = builder.get_node(blocks_to_move[i])
block.block_data = tracked_block_data[i].data

View File

@ -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
class TrackedInfo extends RefCounted:
var data:ConvexBlockData
# var materials:Array[Material]
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 blocks"
#Add blocks to be moved here
func add_block(block_path:NodePath):
blocks_to_move.append(block_path)
var block:CyclopsConvexBlock = builder.get_node(block_path)
#tracked_blocks.append(block)
var info:TrackedInfo = TrackedInfo.new()
info.data = block.block_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:CyclopsConvexBlock = builder.get_node(blocks_to_move[i])
var ctl_mesh:ConvexVolume = ConvexVolume.new()
ctl_mesh.init_from_convex_block_data(tracked_block_data[i].data)
ctl_mesh.transform(xform, lock_uvs)
var result_data:ConvexBlockData = ctl_mesh.to_convex_block_data()
block.block_data = result_data
# block.materials = tracked_block_data[i].materials
#tracked_blocks[block_idx].block_data = result_data
func do_it():
# if blocks_to_move.is_empty():
# var blocks:Array[CyclopsConvexBlock] = builder.get_selected_blocks()
# for block in blocks:
# add_block(block.get_path())
apply_transform(transform)
func undo_it():
apply_transform(Transform3D.IDENTITY)

View File

@ -0,0 +1,43 @@
# 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
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 do_it()->void:
pass
func undo_it()->void:
pass