Update everything
This commit is contained in:
7
Makefile
7
Makefile
@@ -1,4 +1,4 @@
|
|||||||
BLENDER = ../../blender-4.3.2-linux-x64/blender
|
BLENDER = ../../blender-3.6.20-linux-x64/blender
|
||||||
SERVER = src/godot/bin/godot_server.x11.opt.tools.64
|
SERVER = src/godot/bin/godot_server.x11.opt.tools.64
|
||||||
|
|
||||||
.PHONY: all godot-editor-main export export-models export-clothes \
|
.PHONY: all godot-editor-main export export-models export-clothes \
|
||||||
@@ -28,7 +28,10 @@ export-clean:
|
|||||||
rm -Rf godot/character-data/*
|
rm -Rf godot/character-data/*
|
||||||
rm -f assets/blender/scripts/tmp-*.blend
|
rm -f assets/blender/scripts/tmp-*.blend
|
||||||
|
|
||||||
import-vrm: export-clean
|
install-addons:
|
||||||
|
$(BLENDER) -b -Y -P assets/blender/scripts/install_addons.py
|
||||||
|
|
||||||
|
import-vrm: install-addons export-clean
|
||||||
mkdir -p assets/blender/scripts/shapes/male assets/blender/scripts/shapes/female
|
mkdir -p assets/blender/scripts/shapes/male assets/blender/scripts/shapes/female
|
||||||
$(BLENDER) -b -Y -P assets/blender/scripts/import_vrm.py
|
$(BLENDER) -b -Y -P assets/blender/scripts/import_vrm.py
|
||||||
|
|
||||||
|
|||||||
@@ -233,7 +233,10 @@ for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBab
|
|||||||
export_normals=True,
|
export_normals=True,
|
||||||
export_tangents=True,
|
export_tangents=True,
|
||||||
export_materials='EXPORT',
|
export_materials='EXPORT',
|
||||||
export_all_vertex_colors=True,
|
# export_all_vertex_colors=True,
|
||||||
|
# colors_type='SRGB',
|
||||||
|
# export_vertex_colors=True,
|
||||||
|
export_colors=True,
|
||||||
use_mesh_edges=False,
|
use_mesh_edges=False,
|
||||||
use_mesh_vertices=False,
|
use_mesh_vertices=False,
|
||||||
export_cameras=False,
|
export_cameras=False,
|
||||||
@@ -245,8 +248,11 @@ for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBab
|
|||||||
export_def_bones=False,
|
export_def_bones=False,
|
||||||
export_current_frame=False,
|
export_current_frame=False,
|
||||||
export_morph=True,
|
export_morph=True,
|
||||||
|
export_morph_animation=False,
|
||||||
export_morph_normal=True,
|
export_morph_normal=True,
|
||||||
export_lights=False)
|
export_morph_tangent=True,
|
||||||
|
export_lights=False,
|
||||||
|
export_skins=False)
|
||||||
shutil.move(mapping.gltf_path.replace(".npc", ".gltf"), mapping.gltf_path)
|
shutil.move(mapping.gltf_path.replace(".npc", ".gltf"), mapping.gltf_path)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,19 @@ import glob
|
|||||||
import shutil
|
import shutil
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from math import radians, pi
|
from math import radians, pi
|
||||||
|
if bpy.app.version[0] == 3:
|
||||||
|
sys.path.insert(0, os.getcwd() + "/assets/blender/scripts/mixamo/3.6")
|
||||||
|
if bpy.app.version[0] == 4:
|
||||||
|
sys.path.insert(0, os.getcwd() + "/assets/blender/scripts/mixamo/4.3")
|
||||||
sys.path.insert(0, os.getcwd() + "/assets/blender/scripts")
|
sys.path.insert(0, os.getcwd() + "/assets/blender/scripts")
|
||||||
from vrm import rename
|
from vrm import rename
|
||||||
from mixamo import mixamo_rig
|
if bpy.app.version[0] == 3:
|
||||||
|
from mixamo import mixamo_rig
|
||||||
from mixamo.lib.armature import *
|
from mixamo.lib.armature import *
|
||||||
#from mixamo.mixamoroot import import_armature
|
|
||||||
#from mixamo.import_mixamo_root_motion import import_mixamo_root_motion
|
|
||||||
from settings import VRMDataFemale, VRMDataMale, VRMDataMaleBabyShape, basepath
|
from settings import VRMDataFemale, VRMDataMale, VRMDataMaleBabyShape, basepath
|
||||||
|
|
||||||
|
|
||||||
imports = [VRMDataFemale(), VRMDataMale(), VRMDataMaleBabyShape()]
|
imports = [VRMDataFemale(), VRMDataMale(), VRMDataMaleBabyShape()]
|
||||||
|
|
||||||
|
|
||||||
class mkrig:
|
class mkrig:
|
||||||
ik_arms = True
|
ik_arms = True
|
||||||
ik_legs = True
|
ik_legs = True
|
||||||
@@ -27,7 +28,6 @@ class mkrig:
|
|||||||
mixamo_rig.remove_temp_objects()
|
mixamo_rig.remove_temp_objects()
|
||||||
mixamo_rig.clean_scene()
|
mixamo_rig.clean_scene()
|
||||||
def get_anim(filepath, root_bone_name="Root", hip_bone_name="mixamorig:Hips", remove_prefix=False, name_prefix="mixamorig:", insert_root=False, delete_armatures=False):
|
def get_anim(filepath, root_bone_name="Root", hip_bone_name="mixamorig:Hips", remove_prefix=False, name_prefix="mixamorig:", insert_root=False, delete_armatures=False):
|
||||||
# current_context = bpy.context.area.ui_type
|
|
||||||
old_objs = set(bpy.context.scene.objects)
|
old_objs = set(bpy.context.scene.objects)
|
||||||
try:
|
try:
|
||||||
import_armature(filepath, root_bone_name, hip_bone_name, remove_prefix, name_prefix, insert_root, delete_armatures)
|
import_armature(filepath, root_bone_name, hip_bone_name, remove_prefix, name_prefix, insert_root, delete_armatures)
|
||||||
@@ -36,7 +36,6 @@ def get_anim(filepath, root_bone_name="Root", hip_bone_name="mixamorig:Hips", re
|
|||||||
deleteArmature(imported_objects)
|
deleteArmature(imported_objects)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error("[Mixamo Root] ERROR get_all_anims raised %s when processing %s" % (str(e), filepath))
|
log.error("[Mixamo Root] ERROR get_all_anims raised %s when processing %s" % (str(e), filepath))
|
||||||
# bpy.context.area.ui_type = current_context
|
|
||||||
bpy.context.scene.frame_start = 0
|
bpy.context.scene.frame_start = 0
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
def create_root_bone(anim_obj):
|
def create_root_bone(anim_obj):
|
||||||
@@ -53,11 +52,6 @@ def hips_to_root(anim_obj):
|
|||||||
print(fc, fc.data_path, fc.array_index)
|
print(fc, fc.data_path, fc.array_index)
|
||||||
if fc.array_index in [0, 2]:
|
if fc.array_index in [0, 2]:
|
||||||
fc.data_path = fc.data_path.replace("mixamorig:Hips", "Root")
|
fc.data_path = fc.data_path.replace("mixamorig:Hips", "Root")
|
||||||
# if fc.array_index == 2:
|
|
||||||
# for kp in fc.keyframe_points:
|
|
||||||
# kp.co.z = min(0, abs(kp.co.z))
|
|
||||||
# hip_curves = [fc for fc in anim_obj.animation_data.action.fcurves if hip_bone_name in fc.data_path and fc.data_path.startswith('location')]
|
|
||||||
# print(hip_curves)
|
|
||||||
def hips_to_root(anim_obj):
|
def hips_to_root(anim_obj):
|
||||||
for fc in anim_obj.animation_data.action.fcurves:
|
for fc in anim_obj.animation_data.action.fcurves:
|
||||||
if "mixamorig:Hips" in fc.data_path:
|
if "mixamorig:Hips" in fc.data_path:
|
||||||
@@ -72,18 +66,12 @@ def hips_to_root2(anim_obj):
|
|||||||
print(fc, fc.data_path, fc.array_index)
|
print(fc, fc.data_path, fc.array_index)
|
||||||
if fc.array_index in [0, 2]:
|
if fc.array_index in [0, 2]:
|
||||||
data_path = fc.data_path[:]
|
data_path = fc.data_path[:]
|
||||||
# fc.data_path = data_path.replace("Ctrl_Hips", "Ctrl_Master")
|
|
||||||
fcr = anim_obj.animation_data.action.fcurves.new(data_path = data_path.replace("Ctrl_Hips", "Root"), index = fc.array_index)
|
fcr = anim_obj.animation_data.action.fcurves.new(data_path = data_path.replace("Ctrl_Hips", "Root"), index = fc.array_index)
|
||||||
keys = [0] * (2 * len(fc.keyframe_points))
|
keys = [0] * (2 * len(fc.keyframe_points))
|
||||||
fcr.keyframe_points.add(len(fc.keyframe_points))
|
fcr.keyframe_points.add(len(fc.keyframe_points))
|
||||||
fc.keyframe_points.foreach_get("co", keys)
|
fc.keyframe_points.foreach_get("co", keys)
|
||||||
fcr.keyframe_points.foreach_set("co", keys)
|
fcr.keyframe_points.foreach_set("co", keys)
|
||||||
print("ROOT")
|
print("ROOT")
|
||||||
# fc.data_path = data_path.replace("Ctrl_Hips", "Root")
|
|
||||||
# for fcr in anim_obj.animation_data.action.fcurves:
|
|
||||||
# if "Root" in fcr.data_path:
|
|
||||||
# fcr.array_index = fc.array_index
|
|
||||||
# print("ROOT")
|
|
||||||
|
|
||||||
for imp in imports:
|
for imp in imports:
|
||||||
bpy.ops.wm.read_homefile(use_empty=True)
|
bpy.ops.wm.read_homefile(use_empty=True)
|
||||||
@@ -126,8 +114,6 @@ for imp in imports:
|
|||||||
print("Load BVH..." + anim_path)
|
print("Load BVH..." + anim_path)
|
||||||
old_objs = set(bpy.context.scene.objects)
|
old_objs = set(bpy.context.scene.objects)
|
||||||
bpy.ops.import_scene.fbx(filepath=anim_path, global_scale=imp.fbx_scale)
|
bpy.ops.import_scene.fbx(filepath=anim_path, global_scale=imp.fbx_scale)
|
||||||
#import_mixamo_root_motion(bpy.context, anim_path, True, True, False, False, False, 'COPY_HIPS', True, True, True)
|
|
||||||
#get_anim(anim_path)
|
|
||||||
imported_objects = set(bpy.context.scene.objects) - old_objs
|
imported_objects = set(bpy.context.scene.objects) - old_objs
|
||||||
for anim_obj in imported_objects:
|
for anim_obj in imported_objects:
|
||||||
if anim_obj == main_armature:
|
if anim_obj == main_armature:
|
||||||
@@ -136,8 +122,6 @@ for imp in imports:
|
|||||||
continue
|
continue
|
||||||
if main_armature == anim_obj or anim_obj.type != "ARMATURE":
|
if main_armature == anim_obj or anim_obj.type != "ARMATURE":
|
||||||
continue
|
continue
|
||||||
# create_root_bone(anim_obj)
|
|
||||||
# hips_to_root(anim_obj)
|
|
||||||
if anim_obj.animation_data == None:
|
if anim_obj.animation_data == None:
|
||||||
print("Bad object: " + anim_obj.name + " " + anim_obj.type)
|
print("Bad object: " + anim_obj.name + " " + anim_obj.type)
|
||||||
bpy.data.objects.remove(anim_obj)
|
bpy.data.objects.remove(anim_obj)
|
||||||
@@ -163,23 +147,6 @@ for imp in imports:
|
|||||||
for anim_obj in imported_objects:
|
for anim_obj in imported_objects:
|
||||||
bpy.data.objects.remove(anim_obj)
|
bpy.data.objects.remove(anim_obj)
|
||||||
|
|
||||||
# bpy.ops.import_scene.fbx(filepath=anim_path,
|
|
||||||
# directory='', filter_glob='*.fbx',
|
|
||||||
# files=None, ui_tab='MAIN',
|
|
||||||
# use_manual_orientation=False,
|
|
||||||
# global_scale=1.0, bake_space_transform=False,
|
|
||||||
# use_custom_normals=True, colors_type='SRGB',
|
|
||||||
# use_image_search=True, use_alpha_decals=False,
|
|
||||||
# decal_offset=0.0, use_anim=True, anim_offset=1.0,
|
|
||||||
# use_subsurf=False, use_custom_props=True,
|
|
||||||
# use_custom_props_enum_as_string=True,
|
|
||||||
# ignore_leaf_bones=False, force_connect_children=False,
|
|
||||||
# automatic_bone_orientation=False, primary_bone_axis='Y',
|
|
||||||
# secondary_bone_axis='X', use_prepost_rot=True,
|
|
||||||
# axis_forward='-Z', axis_up='Y')
|
|
||||||
# bpy.context.object.name = anim
|
|
||||||
# bpy.context.object.animation_data.action.name = anim
|
|
||||||
# _zero_out(main_armature)
|
|
||||||
main_armature.animation_data.action = bpy.data.actions.new(name="default")
|
main_armature.animation_data.action = bpy.data.actions.new(name="default")
|
||||||
default_action = main_armature.animation_data.action
|
default_action = main_armature.animation_data.action
|
||||||
bpy.context.view_layer.objects.active = main_armature
|
bpy.context.view_layer.objects.active = main_armature
|
||||||
|
|||||||
14
assets/blender/scripts/install_addons.py
Normal file
14
assets/blender/scripts/install_addons.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import os
|
||||||
|
import bpy
|
||||||
|
path_to_script_dir = os.getcwd() + "/assets/blender/scripts/addons/" + str(bpy.app.version[0]) + "." + str(bpy.app.version[1])
|
||||||
|
file_list = sorted(os.listdir(path_to_script_dir))
|
||||||
|
script_list = [item for item in file_list if item.endswith('.zip')]
|
||||||
|
for file in file_list:
|
||||||
|
path_to_file = os.path.join(path_to_script_dir, file)
|
||||||
|
bpy.ops.preferences.addon_install(overwrite=True, target='DEFAULT', filepath=path_to_file, filter_folder=True, filter_python=False, filter_glob="*.py;*.zip")
|
||||||
|
enableTheseAddons = ["VRM_Addon_for_Blender-release"]
|
||||||
|
for string in enableTheseAddons:
|
||||||
|
name = enableTheseAddons
|
||||||
|
bpy.ops.preferences.addon_enable(module = string)
|
||||||
|
bpy.ops.wm.save_userpref()
|
||||||
|
|
||||||
62
assets/blender/scripts/mixamo/3.6/mixamo/__init__.py
Normal file
62
assets/blender/scripts/mixamo/3.6/mixamo/__init__.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENCE BLOCK *****
|
||||||
|
|
||||||
|
|
||||||
|
bl_info = {
|
||||||
|
"name": "Mixamo Rig",
|
||||||
|
"author": "Mixamo",
|
||||||
|
"version": (1, 11, 11),
|
||||||
|
"blender": (2, 80, 0),
|
||||||
|
"location": "3D View > Mixamo> Control Rig",
|
||||||
|
"description": "Generate a control rig from the selected Mixamo Fbx skeleton",
|
||||||
|
"category": "Animation"}
|
||||||
|
|
||||||
|
|
||||||
|
if "bpy" in locals():
|
||||||
|
import importlib
|
||||||
|
if "mixamo_rig_prefs" in locals():
|
||||||
|
importlib.reload(mixamo_rig_prefs)
|
||||||
|
if "mixamo_rig" in locals():
|
||||||
|
importlib.reload(mixamo_rig)
|
||||||
|
if "mixamo_rig_functions" in locals():
|
||||||
|
importlib.reload(mixamo_rig_functions)
|
||||||
|
if "utils" in locals():
|
||||||
|
importlib.reload(utils)
|
||||||
|
if "animation" in locals():
|
||||||
|
importlib.reload(animation)
|
||||||
|
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from . import mixamo_rig_prefs
|
||||||
|
from . import mixamo_rig
|
||||||
|
from . import mixamo_rig_functions
|
||||||
|
from . import utils
|
||||||
|
|
||||||
|
def register():
|
||||||
|
mixamo_rig_prefs.register()
|
||||||
|
mixamo_rig.register()
|
||||||
|
mixamo_rig_functions.register()
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
mixamo_rig_prefs.unregister()
|
||||||
|
mixamo_rig.unregister()
|
||||||
|
mixamo_rig_functions.unregister()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
register()
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# control rig
|
||||||
|
c_prefix = "Ctrl_"
|
||||||
|
master_rig_names = {"master":"Master"}
|
||||||
|
spine_rig_names = {"pelvis":"Hips", "spine1":"Spine", "spine2":"Spine1", "spine3":"Spine2", "hips_free":"Hips_Free", "hips_free_helper":"Hips_Free_Helper"}
|
||||||
|
head_rig_names = {"neck":"Neck", "head":"Head"}
|
||||||
|
leg_rig_names = {"thigh_ik":"UpLeg_IK", "thigh_fk":"UpLeg_FK", "calf_ik":"Leg_IK", "calf_fk":"Leg_FK", "foot_fk":"Foot_FK", "foot_ik":"Foot_IK", "foot_snap":"Foot_Snap", "foot_ik_target":"Foot_IK_target", "foot_01":"Foot_01", "foot_01_pole":"Foot_01_Pole", "heel_out":"FootHeelOut", "heel_in":"FootHeelIn", "heel_mid":"FootHeelMid", "toes_end":"ToeEnd", "toes_end_01":"ToeEnd_01", "toes_ik":"Toe_IK", "toes_track":"ToeTrack", "toes_01_ik":"Toe01_IK", "toes_02":"Toe02", "toes_fk":"Toe_FK", "foot_roll_cursor":"FootRoll_Cursor", "pole_ik":"LegPole_IK"}
|
||||||
|
arm_rig_names = {"shoulder":"Shoulder", "arm_ik":"Arm_IK", "arm_fk":"Arm_FK", "forearm_ik":"ForeArm_IK", "forearm_fk":"ForeArm_FK", "pole_ik":"ArmPole_IK", "hand_ik":"Hand_IK", "hand_fk":"Hand_FK"}
|
||||||
|
|
||||||
|
# mixamo bone names
|
||||||
|
spine_names = {"pelvis":"Hips", "spine1":"Spine", "spine2":"Spine1", "spine3":"Spine2"}
|
||||||
|
head_names = {"neck":"Neck", "head":"Head", "head_end":"HeadTop_End"}
|
||||||
|
leg_names = {"thigh":"UpLeg", "calf":"Leg", "foot":"Foot", "toes":"ToeBase", "toes_end":"Toe_End"}
|
||||||
|
arm_names = {"shoulder":"Shoulder", "arm":"Arm", "forearm":"ForeArm", "hand":"Hand"}
|
||||||
|
fingers_type = ["Thumb", "Index", "Middle", "Ring", "Pinky"]
|
||||||
15
assets/blender/scripts/mixamo/3.6/mixamo/lib/addon.py
Normal file
15
assets/blender/scripts/mixamo/3.6/mixamo/lib/addon.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import bpy, sys, linecache, ast
|
||||||
|
|
||||||
|
def get_error_message():
|
||||||
|
exc_type, exc_obj, tb = sys.exc_info()
|
||||||
|
f = tb.tb_frame
|
||||||
|
lineno = tb.tb_lineno
|
||||||
|
filename = f.f_code.co_filename
|
||||||
|
linecache.checkcache(filename)
|
||||||
|
line = linecache.getline(filename, lineno, f.f_globals)
|
||||||
|
error_message = 'Error in ({}\nLine {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)
|
||||||
|
return error_message
|
||||||
|
|
||||||
|
|
||||||
|
def get_addon_preferences():
|
||||||
|
return bpy.context.preferences.addons[__package__].preferences
|
||||||
203
assets/blender/scripts/mixamo/3.6/mixamo/lib/animation.py
Normal file
203
assets/blender/scripts/mixamo/3.6/mixamo/lib/animation.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import bpy
|
||||||
|
from .maths_geo import *
|
||||||
|
from .bones_pose import *
|
||||||
|
from .version import *
|
||||||
|
|
||||||
|
def bake_anim(frame_start=0, frame_end=10, only_selected=False, bake_bones=True, bake_object=False, ik_data=None):
|
||||||
|
scn = bpy.context.scene
|
||||||
|
obj_data = []
|
||||||
|
bones_data = []
|
||||||
|
armature = bpy.data.objects.get(bpy.context.active_object.name)
|
||||||
|
|
||||||
|
def get_bones_matrix():
|
||||||
|
matrix = {}
|
||||||
|
for pbone in armature.pose.bones:
|
||||||
|
if only_selected and not pbone.bone.select:
|
||||||
|
continue
|
||||||
|
|
||||||
|
bmat = pbone.matrix
|
||||||
|
|
||||||
|
# IK poles
|
||||||
|
if pbone.name.startswith("Ctrl_ArmPole") or pbone.name.startswith("Ctrl_LegPole"):
|
||||||
|
b1 = b2 = None
|
||||||
|
src_arm = ik_data["src_arm"]
|
||||||
|
type = ""
|
||||||
|
if "Leg" in pbone.name:
|
||||||
|
type = "Leg"
|
||||||
|
elif "Arm" in pbone.name:
|
||||||
|
type = "Arm"
|
||||||
|
|
||||||
|
name_split = pbone.name.split('_')
|
||||||
|
side = name_split[len(name_split)-1]
|
||||||
|
b1_name = ik_data[type+side][0]
|
||||||
|
b2_name = ik_data[type+side][1]
|
||||||
|
b1 = src_arm.pose.bones.get(b1_name)
|
||||||
|
b2 = src_arm.pose.bones.get(b2_name)
|
||||||
|
|
||||||
|
_axis = None
|
||||||
|
if type == "Leg":
|
||||||
|
_axis = (b1.z_axis*0.5) + (b2.z_axis*0.5)#b1.z_axis#
|
||||||
|
elif type == "Arm":
|
||||||
|
if side == "Left":
|
||||||
|
_axis = b2.x_axis
|
||||||
|
elif side == "Right":
|
||||||
|
_axis = -b2.x_axis
|
||||||
|
|
||||||
|
pole_pos = get_ik_pole_pos(b1, b2, method=2, axis=_axis)
|
||||||
|
#pole_pos = b2.head + (b2.z_axis.normalized() * (b2.tail-b2.head).magnitude)
|
||||||
|
bmat = Matrix.Translation(pole_pos)
|
||||||
|
|
||||||
|
# Child Of constraints are preserved after baking
|
||||||
|
# need to compensate the matrix with the Child Of transformation
|
||||||
|
child_of_cns = pbone.constraints.get("Child Of")
|
||||||
|
if child_of_cns:
|
||||||
|
if child_of_cns.influence == 1.0 and child_of_cns.mute == False:
|
||||||
|
bmat = get_pose_bone(child_of_cns.subtarget).matrix_channel.inverted() @ bmat
|
||||||
|
|
||||||
|
matrix[pbone.name] = armature.convert_space(pose_bone=pbone, matrix=bmat, from_space="POSE", to_space="LOCAL")
|
||||||
|
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
def get_obj_matrix():
|
||||||
|
parent = armature.parent
|
||||||
|
matrix = armature.matrix_world
|
||||||
|
if parent:
|
||||||
|
return parent.matrix_world.inverted_safe() @ matrix
|
||||||
|
else:
|
||||||
|
return matrix.copy()
|
||||||
|
|
||||||
|
# store matrices
|
||||||
|
current_frame = scn.frame_current
|
||||||
|
|
||||||
|
for f in range(int(frame_start), int(frame_end+1)):
|
||||||
|
scn.frame_set(f)
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
|
if bake_bones:
|
||||||
|
bones_data.append((f, get_bones_matrix()))
|
||||||
|
if bake_object:
|
||||||
|
obj_data.append((f, get_obj_matrix()))
|
||||||
|
|
||||||
|
# set new action
|
||||||
|
action = bpy.data.actions.new("Action")
|
||||||
|
anim_data = armature.animation_data_create()
|
||||||
|
anim_data.action = action
|
||||||
|
|
||||||
|
def store_keyframe(bn, prop_type, fc_array_index, fra, val):
|
||||||
|
fc_data_path = 'pose.bones["' + bn + '"].' + prop_type
|
||||||
|
fc_key = (fc_data_path, fc_array_index)
|
||||||
|
if not keyframes.get(fc_key):
|
||||||
|
keyframes[fc_key] = []
|
||||||
|
keyframes[fc_key].extend((fra, val))
|
||||||
|
|
||||||
|
|
||||||
|
# set transforms and store keyframes
|
||||||
|
if bake_bones:
|
||||||
|
for pb in armature.pose.bones:
|
||||||
|
if only_selected and not pb.bone.select:
|
||||||
|
continue
|
||||||
|
|
||||||
|
euler_prev = None
|
||||||
|
quat_prev = None
|
||||||
|
keyframes = {}
|
||||||
|
|
||||||
|
for (f, matrix) in bones_data:
|
||||||
|
pb.matrix_basis = matrix[pb.name].copy()
|
||||||
|
|
||||||
|
for arr_idx, value in enumerate(pb.location):
|
||||||
|
store_keyframe(pb.name, "location", arr_idx, f, value)
|
||||||
|
|
||||||
|
rotation_mode = pb.rotation_mode
|
||||||
|
|
||||||
|
if rotation_mode == 'QUATERNION':
|
||||||
|
if quat_prev is not None:
|
||||||
|
quat = pb.rotation_quaternion.copy()
|
||||||
|
quat.make_compatible(quat_prev)
|
||||||
|
pb.rotation_quaternion = quat
|
||||||
|
quat_prev = quat
|
||||||
|
del quat
|
||||||
|
else:
|
||||||
|
quat_prev = pb.rotation_quaternion.copy()
|
||||||
|
|
||||||
|
for arr_idx, value in enumerate(pb.rotation_quaternion):
|
||||||
|
store_keyframe(pb.name, "rotation_quaternion", arr_idx, f, value)
|
||||||
|
|
||||||
|
elif rotation_mode == 'AXIS_ANGLE':
|
||||||
|
for arr_idx, value in enumerate(pb.rotation_axis_angle):
|
||||||
|
store_keyframe(pb.name, "rotation_axis_angle", arr_idx, f, value)
|
||||||
|
|
||||||
|
else: # euler, XYZ, ZXY etc
|
||||||
|
if euler_prev is not None:
|
||||||
|
euler = pb.rotation_euler.copy()
|
||||||
|
euler.make_compatible(euler_prev)
|
||||||
|
pb.rotation_euler = euler
|
||||||
|
euler_prev = euler
|
||||||
|
del euler
|
||||||
|
else:
|
||||||
|
euler_prev = pb.rotation_euler.copy()
|
||||||
|
|
||||||
|
for arr_idx, value in enumerate(pb.rotation_euler):
|
||||||
|
store_keyframe(pb.name, "rotation_euler", arr_idx, f, value)
|
||||||
|
|
||||||
|
for arr_idx, value in enumerate(pb.scale):
|
||||||
|
store_keyframe(pb.name, "scale", arr_idx, f, value)
|
||||||
|
|
||||||
|
|
||||||
|
# Add keyframes
|
||||||
|
for fc_key, key_values in keyframes.items():
|
||||||
|
data_path, index = fc_key
|
||||||
|
fcurve = action.fcurves.find(data_path=data_path, index=index)
|
||||||
|
if fcurve == None:
|
||||||
|
fcurve = action.fcurves.new(data_path, index=index, action_group=pb.name)
|
||||||
|
|
||||||
|
num_keys = len(key_values) // 2
|
||||||
|
fcurve.keyframe_points.add(num_keys)
|
||||||
|
fcurve.keyframe_points.foreach_set('co', key_values)
|
||||||
|
|
||||||
|
if blender_version._float >= 290:# internal error when doing so with Blender 2.83, only for Blender 2.90 and higher
|
||||||
|
linear_enum_value = bpy.types.Keyframe.bl_rna.properties['interpolation'].enum_items['LINEAR'].value
|
||||||
|
fcurve.keyframe_points.foreach_set('interpolation', (linear_enum_value,) * num_keys)
|
||||||
|
else:
|
||||||
|
for kf in fcurve.keyframe_points:
|
||||||
|
kf.interpolation = 'LINEAR'
|
||||||
|
|
||||||
|
|
||||||
|
if bake_object:
|
||||||
|
euler_prev = None
|
||||||
|
quat_prev = None
|
||||||
|
|
||||||
|
for (f, matrix) in obj_data:
|
||||||
|
name = "Action Bake"
|
||||||
|
armature.matrix_basis = matrix
|
||||||
|
|
||||||
|
armature.keyframe_insert("location", index=-1, frame=f, group=name)
|
||||||
|
|
||||||
|
rotation_mode = armature.rotation_mode
|
||||||
|
if rotation_mode == 'QUATERNION':
|
||||||
|
if quat_prev is not None:
|
||||||
|
quat = armature.rotation_quaternion.copy()
|
||||||
|
quat.make_compatible(quat_prev)
|
||||||
|
armature.rotation_quaternion = quat
|
||||||
|
quat_prev = quat
|
||||||
|
del quat
|
||||||
|
else:
|
||||||
|
quat_prev = armature.rotation_quaternion.copy()
|
||||||
|
armature.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name)
|
||||||
|
elif rotation_mode == 'AXIS_ANGLE':
|
||||||
|
armature.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name)
|
||||||
|
else: # euler, XYZ, ZXY etc
|
||||||
|
if euler_prev is not None:
|
||||||
|
euler = armature.rotation_euler.copy()
|
||||||
|
euler.make_compatible(euler_prev)
|
||||||
|
armature.rotation_euler = euler
|
||||||
|
euler_prev = euler
|
||||||
|
del euler
|
||||||
|
else:
|
||||||
|
euler_prev = armature.rotation_euler.copy()
|
||||||
|
armature.keyframe_insert("rotation_euler", index=-1, frame=f, group=name)
|
||||||
|
|
||||||
|
armature.keyframe_insert("scale", index=-1, frame=f, group=name)
|
||||||
|
|
||||||
|
|
||||||
|
# restore current frame
|
||||||
|
scn.frame_set(current_frame)
|
||||||
19
assets/blender/scripts/mixamo/3.6/mixamo/lib/armature.py
Normal file
19
assets/blender/scripts/mixamo/3.6/mixamo/lib/armature.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def restore_armature_layers(layers_select):
|
||||||
|
# restore the armature layers visibility
|
||||||
|
for i in range(0, 32):
|
||||||
|
bpy.context.active_object.data.layers[i] = layers_select[i]
|
||||||
|
|
||||||
|
|
||||||
|
def enable_all_armature_layers():
|
||||||
|
# enable all layers
|
||||||
|
# and return the list of each layer visibility
|
||||||
|
_layers = bpy.context.active_object.data.layers
|
||||||
|
layers_select = []
|
||||||
|
for i in range(0, 32):
|
||||||
|
layers_select.append(_layers[i])
|
||||||
|
for i in range(0, 32):
|
||||||
|
bpy.context.active_object.data.layers[i] = True
|
||||||
|
|
||||||
|
return layers_select
|
||||||
17
assets/blender/scripts/mixamo/3.6/mixamo/lib/bones_data.py
Normal file
17
assets/blender/scripts/mixamo/3.6/mixamo/lib/bones_data.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def get_data_bone(name):
|
||||||
|
return bpy.context.active_object.data.bones.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def set_bone_layer(databone, layer_idx, multi=False):
|
||||||
|
if databone == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
databone.layers[layer_idx] = True
|
||||||
|
if multi:
|
||||||
|
return
|
||||||
|
|
||||||
|
for i, lay in enumerate(databone.layers):
|
||||||
|
if i != layer_idx:
|
||||||
|
databone.layers[i] = False
|
||||||
19
assets/blender/scripts/mixamo/3.6/mixamo/lib/bones_edit.py
Normal file
19
assets/blender/scripts/mixamo/3.6/mixamo/lib/bones_edit.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def get_edit_bone(name):
|
||||||
|
return bpy.context.object.data.edit_bones.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_bone_transforms(bone1, bone2):
|
||||||
|
# copy editbone bone1 transforms to bone 2
|
||||||
|
bone2.head = bone1.head.copy()
|
||||||
|
bone2.tail = bone1.tail.copy()
|
||||||
|
bone2.roll = bone1.roll
|
||||||
|
|
||||||
|
|
||||||
|
def create_edit_bone(bone_name, deform=False):
|
||||||
|
b = get_edit_bone(bone_name)
|
||||||
|
if b == None:
|
||||||
|
b = bpy.context.active_object.data.edit_bones.new(bone_name)
|
||||||
|
b.use_deform = deform
|
||||||
|
return b
|
||||||
104
assets/blender/scripts/mixamo/3.6/mixamo/lib/bones_pose.py
Normal file
104
assets/blender/scripts/mixamo/3.6/mixamo/lib/bones_pose.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import bpy
|
||||||
|
from .objects import *
|
||||||
|
from .version import *
|
||||||
|
|
||||||
|
def get_custom_shape_scale(pbone, uniform=True):
|
||||||
|
if blender_version._float >= 300:
|
||||||
|
if uniform:
|
||||||
|
# uniform scale
|
||||||
|
val = 0
|
||||||
|
for i in range(0,3):
|
||||||
|
val += pbone.custom_shape_scale_xyz[i]
|
||||||
|
return val/3
|
||||||
|
# array scale
|
||||||
|
else:
|
||||||
|
return pbone.custom_shape_scale_xyz
|
||||||
|
# pre-Blender 3.0
|
||||||
|
else:
|
||||||
|
return pbone.custom_shape_scale
|
||||||
|
|
||||||
|
|
||||||
|
def get_selected_pbone_name():
|
||||||
|
try:
|
||||||
|
return bpy.context.selected_pose_bones[0].name#.active_pose_bone.name
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def get_pose_bone(name):
|
||||||
|
return bpy.context.active_object.pose.bones.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def lock_pbone_transform(pbone, type, list):
|
||||||
|
for i in list:
|
||||||
|
if type == "location":
|
||||||
|
pbone.lock_location[i] = True
|
||||||
|
elif type == "rotation":
|
||||||
|
pbone.lock_rotation[i] = True
|
||||||
|
elif type == "scale":
|
||||||
|
pbone.lock_scale[i] = True
|
||||||
|
|
||||||
|
|
||||||
|
def set_bone_custom_shape(pbone, cs_name):
|
||||||
|
cs = get_object(cs_name)
|
||||||
|
if cs == None:
|
||||||
|
append_cs(cs_name)
|
||||||
|
cs = get_object(cs_name)
|
||||||
|
|
||||||
|
pbone.custom_shape = cs
|
||||||
|
|
||||||
|
|
||||||
|
def set_bone_color_group(obj, pb, grp_name):
|
||||||
|
# mixamo required color
|
||||||
|
orange = (0.969, 0.565, 0.208)
|
||||||
|
orange_light = (0.957, 0.659, 0.416)
|
||||||
|
blue_dark = (0.447, 0.682, 1.0)
|
||||||
|
blue_light = (0.365, 0.851, 1.0)
|
||||||
|
|
||||||
|
# base color
|
||||||
|
green = (0.0, 1.0, 0.0)
|
||||||
|
red = (1.0, 0.0, 0.0)
|
||||||
|
blue = (0.0, 0.9, 1.0)
|
||||||
|
|
||||||
|
grp_color_master = orange_light
|
||||||
|
grp_color_neck = orange_light
|
||||||
|
grp_color_root_master = orange
|
||||||
|
grp_color_head = orange
|
||||||
|
grp_color_body_mid = green
|
||||||
|
grp_color_body_left = blue_dark
|
||||||
|
grp_color_body_right = blue_light
|
||||||
|
|
||||||
|
grp = obj.pose.bone_groups.get(grp_name)
|
||||||
|
if grp == None:
|
||||||
|
grp = obj.pose.bone_groups.new(name=grp_name)
|
||||||
|
grp.color_set = 'CUSTOM'
|
||||||
|
|
||||||
|
grp_color = None
|
||||||
|
if grp_name == "body_mid":
|
||||||
|
grp_color = grp_color_body_mid
|
||||||
|
elif grp_name == "body_left":
|
||||||
|
grp_color = grp_color_body_left
|
||||||
|
elif grp_name == "body_right":
|
||||||
|
grp_color = grp_color_body_right
|
||||||
|
elif grp_name == "master":
|
||||||
|
grp_color = grp_color_master
|
||||||
|
elif grp_name == "neck":
|
||||||
|
grp_color = grp_color_head
|
||||||
|
elif grp_name == "head":
|
||||||
|
grp_color = grp_color_neck
|
||||||
|
elif grp_name == "root_master":
|
||||||
|
grp_color = grp_color_root_master
|
||||||
|
|
||||||
|
# set normal color
|
||||||
|
grp.colors.normal = grp_color
|
||||||
|
|
||||||
|
# set select color/active color
|
||||||
|
for col_idx in range(0,3):
|
||||||
|
grp.colors.select[col_idx] = grp_color[col_idx] + 0.2
|
||||||
|
grp.colors.active[col_idx] = grp_color[col_idx] + 0.4
|
||||||
|
|
||||||
|
pb.bone_group = grp
|
||||||
|
|
||||||
|
|
||||||
|
def update_transform():
|
||||||
|
bpy.ops.transform.rotate(value=0, orient_axis='Z', orient_type='VIEW', orient_matrix=((0.0, 0.0, 0), (0, 0.0, 0.0), (0.0, 0.0, 0.0)), orient_matrix_type='VIEW', mirror=False)
|
||||||
19
assets/blender/scripts/mixamo/3.6/mixamo/lib/constraints.py
Normal file
19
assets/blender/scripts/mixamo/3.6/mixamo/lib/constraints.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def add_copy_transf(p_bone, tgt, subtgt):
|
||||||
|
cns_transf = p_bone.constraints.get("Copy Transforms")
|
||||||
|
if cns_transf == None:
|
||||||
|
cns_transf = p_bone.constraints.new("COPY_TRANSFORMS")
|
||||||
|
cns_transf.name = "Copy Transforms"
|
||||||
|
cns_transf.target = tgt
|
||||||
|
cns_transf.subtarget = subtgt
|
||||||
|
|
||||||
|
|
||||||
|
def set_constraint_inverse_matrix(cns):
|
||||||
|
# set the inverse matrix of Child Of constraint
|
||||||
|
tar_obj = cns.target
|
||||||
|
subtarget_pbone = tar_obj.pose.bones.get(cns.subtarget)
|
||||||
|
if subtarget_pbone:
|
||||||
|
#cns.inverse_matrix = tar_obj.matrix_world.inverted() @ subtarget_pbone.matrix_basis.inverted()
|
||||||
|
print("reset child of cns", cns.name, cns.subtarget)
|
||||||
|
cns.inverse_matrix = subtarget_pbone.bone.matrix_local.to_4x4().inverted()
|
||||||
10
assets/blender/scripts/mixamo/3.6/mixamo/lib/context.py
Normal file
10
assets/blender/scripts/mixamo/3.6/mixamo/lib/context.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def get_current_mode():
|
||||||
|
return bpy.context.mode
|
||||||
|
|
||||||
|
|
||||||
|
def restore_current_mode(current_mode):
|
||||||
|
if current_mode == 'EDIT_ARMATURE':
|
||||||
|
current_mode = 'EDIT'
|
||||||
|
bpy.ops.object.mode_set(mode=current_mode)
|
||||||
60
assets/blender/scripts/mixamo/3.6/mixamo/lib/custom_props.py
Normal file
60
assets/blender/scripts/mixamo/3.6/mixamo/lib/custom_props.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import bpy
|
||||||
|
from .version import blender_version
|
||||||
|
|
||||||
|
|
||||||
|
def get_prop_setting(node, prop_name, setting):
|
||||||
|
if blender_version._float >= 300:
|
||||||
|
return node.id_properties_ui(prop_name).as_dict()[setting]
|
||||||
|
else:
|
||||||
|
return node['_RNA_UI'][prop_name][setting]
|
||||||
|
|
||||||
|
|
||||||
|
def set_prop_setting(node, prop_name, setting, value):
|
||||||
|
if blender_version._float >= 300:
|
||||||
|
ui_data = node.id_properties_ui(prop_name)
|
||||||
|
if setting == 'default':
|
||||||
|
ui_data.update(default=value)
|
||||||
|
elif setting == 'min':
|
||||||
|
ui_data.update(min=value)
|
||||||
|
elif setting == 'max':
|
||||||
|
ui_data.update(max=value)
|
||||||
|
elif setting == 'soft_min':
|
||||||
|
ui_data.update(soft_min=value)
|
||||||
|
elif setting == 'soft_max':
|
||||||
|
ui_data.update(soft_max=value)
|
||||||
|
elif setting == 'description':
|
||||||
|
ui_data.update(description=value)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if not "_RNA_UI" in node.keys():
|
||||||
|
node["_RNA_UI"] = {}
|
||||||
|
node['_RNA_UI'][prop_name][setting] = value
|
||||||
|
|
||||||
|
|
||||||
|
def create_custom_prop(node=None, prop_name="", prop_val=1.0, prop_min=0.0, prop_max=1.0, prop_description="", soft_min=None, soft_max=None, default=None):
|
||||||
|
if soft_min == None:
|
||||||
|
soft_min = prop_min
|
||||||
|
if soft_max == None:
|
||||||
|
soft_max = prop_max
|
||||||
|
|
||||||
|
if blender_version._float < 300:
|
||||||
|
if not "_RNA_UI" in node.keys():
|
||||||
|
node["_RNA_UI"] = {}
|
||||||
|
|
||||||
|
node[prop_name] = prop_val
|
||||||
|
|
||||||
|
if default == None:
|
||||||
|
default = prop_val
|
||||||
|
|
||||||
|
if blender_version._float < 300:
|
||||||
|
node["_RNA_UI"][prop_name] = {'use_soft_limits':True, 'min': prop_min, 'max': prop_max, 'description': prop_description, 'soft_min':soft_min, 'soft_max':soft_max, 'default':default}
|
||||||
|
else:
|
||||||
|
set_prop_setting(node, prop_name, 'min', prop_min)
|
||||||
|
set_prop_setting(node, prop_name, 'max', prop_max)
|
||||||
|
set_prop_setting(node, prop_name, 'description', prop_description)
|
||||||
|
set_prop_setting(node, prop_name, 'soft_min', soft_min)
|
||||||
|
set_prop_setting(node, prop_name, 'soft_max', soft_max)
|
||||||
|
set_prop_setting(node, prop_name, 'default', default)
|
||||||
|
|
||||||
|
# set as overridable
|
||||||
|
node.property_overridable_library_set('["'+prop_name+'"]', True)
|
||||||
23
assets/blender/scripts/mixamo/3.6/mixamo/lib/drivers.py
Normal file
23
assets/blender/scripts/mixamo/3.6/mixamo/lib/drivers.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def add_driver_to_prop(obj, dr_dp, tar_dp, array_idx=-1, exp="var"):
|
||||||
|
if obj.animation_data == None:
|
||||||
|
obj.animation_data_create()
|
||||||
|
|
||||||
|
drivers_list = obj.animation_data.drivers
|
||||||
|
dr = drivers_list.find(dr_dp, index=array_idx)
|
||||||
|
|
||||||
|
if dr == None:
|
||||||
|
dr = obj.driver_add(dr_dp, array_idx)
|
||||||
|
|
||||||
|
dr.driver.expression = exp
|
||||||
|
|
||||||
|
var = dr.driver.variables.get('var')
|
||||||
|
|
||||||
|
if var == None:
|
||||||
|
var = dr.driver.variables.new()
|
||||||
|
|
||||||
|
var.type = 'SINGLE_PROP'
|
||||||
|
var.name = 'var'
|
||||||
|
var.targets[0].id = obj
|
||||||
|
var.targets[0].data_path = tar_dp
|
||||||
151
assets/blender/scripts/mixamo/3.6/mixamo/lib/maths_geo.py
Normal file
151
assets/blender/scripts/mixamo/3.6/mixamo/lib/maths_geo.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
from math import *
|
||||||
|
from mathutils import *
|
||||||
|
|
||||||
|
|
||||||
|
def mat3_to_vec_roll(mat):
|
||||||
|
vec = mat.col[1]
|
||||||
|
vecmat = vec_roll_to_mat3(mat.col[1], 0)
|
||||||
|
vecmatinv = vecmat.inverted()
|
||||||
|
rollmat = vecmatinv @ mat
|
||||||
|
roll = atan2(rollmat[0][2], rollmat[2][2])
|
||||||
|
return roll
|
||||||
|
|
||||||
|
|
||||||
|
def vec_roll_to_mat3(vec, roll):
|
||||||
|
target = Vector((0, 0.1, 0))
|
||||||
|
nor = vec.normalized()
|
||||||
|
axis = target.cross(nor)
|
||||||
|
if axis.dot(axis) > 0.0000000001: # this seems to be the problem for some bones, no idea how to fix
|
||||||
|
axis.normalize()
|
||||||
|
theta = target.angle(nor)
|
||||||
|
bMatrix = Matrix.Rotation(theta, 3, axis)
|
||||||
|
else:
|
||||||
|
updown = 1 if target.dot(nor) > 0 else -1
|
||||||
|
bMatrix = Matrix.Scale(updown, 3)
|
||||||
|
bMatrix[2][2] = 1.0
|
||||||
|
|
||||||
|
rMatrix = Matrix.Rotation(roll, 3, nor)
|
||||||
|
mat = rMatrix @ bMatrix
|
||||||
|
return mat
|
||||||
|
|
||||||
|
|
||||||
|
def align_bone_x_axis(edit_bone, new_x_axis):
|
||||||
|
new_x_axis = new_x_axis.cross(edit_bone.y_axis)
|
||||||
|
new_x_axis.normalize()
|
||||||
|
dot = max(-1.0, min(1.0, edit_bone.z_axis.dot(new_x_axis)))
|
||||||
|
angle = acos(dot)
|
||||||
|
edit_bone.roll += angle
|
||||||
|
dot1 = edit_bone.z_axis.dot(new_x_axis)
|
||||||
|
edit_bone.roll -= angle * 2.0
|
||||||
|
dot2 = edit_bone.z_axis.dot(new_x_axis)
|
||||||
|
if dot1 > dot2:
|
||||||
|
edit_bone.roll += angle * 2.0
|
||||||
|
|
||||||
|
|
||||||
|
def align_bone_z_axis(edit_bone, new_z_axis):
|
||||||
|
new_z_axis = -(new_z_axis.cross(edit_bone.y_axis))
|
||||||
|
new_z_axis.normalize()
|
||||||
|
dot = max(-1.0, min(1.0, edit_bone.x_axis.dot(new_z_axis)))
|
||||||
|
angle = acos(dot)
|
||||||
|
edit_bone.roll += angle
|
||||||
|
dot1 = edit_bone.x_axis.dot(new_z_axis)
|
||||||
|
edit_bone.roll -= angle * 2.0
|
||||||
|
dot2 = edit_bone.x_axis.dot(new_z_axis)
|
||||||
|
if dot1 > dot2:
|
||||||
|
edit_bone.roll += angle * 2.0
|
||||||
|
|
||||||
|
|
||||||
|
def signed_angle(u, v, normal):
|
||||||
|
nor = normal.normalized()
|
||||||
|
a = u.angle(v)
|
||||||
|
|
||||||
|
c = u.cross(v)
|
||||||
|
|
||||||
|
if c.magnitude == 0.0:
|
||||||
|
c = u.normalized().cross(v)
|
||||||
|
if c.magnitude == 0.0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
if c.angle(nor) < 1:
|
||||||
|
a = -a
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
def project_point_onto_plane(q, p, n):
|
||||||
|
n = n.normalized()
|
||||||
|
return q - ((q - p).dot(n)) * n
|
||||||
|
|
||||||
|
|
||||||
|
def get_pole_angle(base_bone, ik_bone, pole_location):
|
||||||
|
pole_normal = (ik_bone.tail - base_bone.head).cross(pole_location - base_bone.head)
|
||||||
|
projected_pole_axis = pole_normal.cross(base_bone.tail - base_bone.head)
|
||||||
|
return signed_angle(base_bone.x_axis, projected_pole_axis, base_bone.tail - base_bone.head)
|
||||||
|
|
||||||
|
|
||||||
|
def get_pose_matrix_in_other_space(mat, pose_bone):
|
||||||
|
rest = pose_bone.bone.matrix_local.copy()
|
||||||
|
rest_inv = rest.inverted()
|
||||||
|
|
||||||
|
if pose_bone.parent and pose_bone.bone.use_inherit_rotation:
|
||||||
|
par_mat = pose_bone.parent.matrix.copy()
|
||||||
|
par_inv = par_mat.inverted()
|
||||||
|
par_rest = pose_bone.parent.bone.matrix_local.copy()
|
||||||
|
|
||||||
|
else:
|
||||||
|
par_mat = Matrix()
|
||||||
|
par_inv = Matrix()
|
||||||
|
par_rest = Matrix()
|
||||||
|
|
||||||
|
smat = rest_inv @ (par_rest @ (par_inv @ mat))
|
||||||
|
|
||||||
|
return smat
|
||||||
|
|
||||||
|
|
||||||
|
def get_ik_pole_pos(b1, b2, method=1, axis=None):
|
||||||
|
|
||||||
|
if method == 1:
|
||||||
|
# IK pole position based on real IK bones vector
|
||||||
|
plane_normal = (b1.head - b2.tail)
|
||||||
|
midpoint = (b1.head + b2.tail) * 0.5
|
||||||
|
prepole_dir = b2.head - midpoint#prepole_fk.tail - prepole_fk.head
|
||||||
|
pole_pos = b2.head + prepole_dir.normalized()# * 4
|
||||||
|
pole_pos = project_point_onto_plane(pole_pos, b2.head, plane_normal)
|
||||||
|
pole_pos = b2.head + ((pole_pos - b2.head).normalized() * (b2.head - b1.head).magnitude * 1.7)
|
||||||
|
|
||||||
|
elif method == 2:
|
||||||
|
# IK pole position based on bone2 Z axis vector
|
||||||
|
pole_pos = b2.head + (axis.normalized() * (b2.tail-b2.head).magnitude)
|
||||||
|
|
||||||
|
return pole_pos
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_point(point, angle, origin, axis):
|
||||||
|
rot_mat = Matrix.Rotation(angle, 4, axis.normalized())
|
||||||
|
# rotate in world origin space
|
||||||
|
offset_vec = -origin
|
||||||
|
offset_knee = point + offset_vec
|
||||||
|
# rotate
|
||||||
|
rotated_point = rot_mat @ offset_knee
|
||||||
|
# bring back to original space
|
||||||
|
rotated_point = rotated_point -offset_vec
|
||||||
|
return rotated_point
|
||||||
|
|
||||||
|
|
||||||
|
def dot_product(x, y):
|
||||||
|
return sum([x[i] * y[i] for i in range(len(x))])
|
||||||
|
|
||||||
|
|
||||||
|
def norm(x):
|
||||||
|
return sqrt(dot_product(x, x))
|
||||||
|
|
||||||
|
|
||||||
|
def normalize(x):
|
||||||
|
return [x[i] / norm(x) for i in range(len(x))]
|
||||||
|
|
||||||
|
|
||||||
|
def project_vector_onto_plane(x, n):
|
||||||
|
d = dot_product(x, n) / norm(n)
|
||||||
|
p = [d * normalize(n)[i] for i in range(len(n))]
|
||||||
|
vec_list = [x[i] - p[i] for i in range(len(x))]
|
||||||
|
return Vector((vec_list[0], vec_list[1], vec_list[2]))
|
||||||
|
|
||||||
39
assets/blender/scripts/mixamo/3.6/mixamo/lib/mixamo.py
Normal file
39
assets/blender/scripts/mixamo/3.6/mixamo/lib/mixamo.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import bpy
|
||||||
|
from .bones_pose import *
|
||||||
|
from .bones_data import *
|
||||||
|
from ..definitions import naming
|
||||||
|
|
||||||
|
def get_mixamo_prefix():
|
||||||
|
p = ""
|
||||||
|
rig = bpy.context.active_object
|
||||||
|
|
||||||
|
if 'mixamo_prefix' in rig.data.keys():
|
||||||
|
p = rig.data["mixamo_prefix"]
|
||||||
|
|
||||||
|
else:
|
||||||
|
for dbone in rig.data.bones:
|
||||||
|
if dbone.name.startswith("mixamorig") and ':' in dbone.name:
|
||||||
|
p = dbone.name.split(':')[0]+':'
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
rig.data["mixamo_prefix"] = p
|
||||||
|
except:# context error
|
||||||
|
pass
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
def get_mix_name(name, use_prefix):
|
||||||
|
if not use_prefix:
|
||||||
|
return name
|
||||||
|
else:
|
||||||
|
p = get_mixamo_prefix()
|
||||||
|
return p+name
|
||||||
|
|
||||||
|
|
||||||
|
def get_bone_side(bone_name):
|
||||||
|
if bone_name.endswith("_Left"):
|
||||||
|
return "Left"
|
||||||
|
elif bone_name.endswith("_Right"):
|
||||||
|
return "Right"
|
||||||
81
assets/blender/scripts/mixamo/3.6/mixamo/lib/objects.py
Normal file
81
assets/blender/scripts/mixamo/3.6/mixamo/lib/objects.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import bpy, os
|
||||||
|
|
||||||
|
def delete_object(obj):
|
||||||
|
bpy.data.objects.remove(obj, do_unlink=True)
|
||||||
|
|
||||||
|
|
||||||
|
def duplicate_object():
|
||||||
|
try:
|
||||||
|
bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
|
||||||
|
except:
|
||||||
|
bpy.ops.object.duplicate('TRANSLATION', False)
|
||||||
|
|
||||||
|
|
||||||
|
def get_object(name):
|
||||||
|
return bpy.data.objects.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def set_active_object(object_name):
|
||||||
|
bpy.context.view_layer.objects.active = bpy.data.objects[object_name]
|
||||||
|
bpy.data.objects[object_name].select_set(state=True)
|
||||||
|
|
||||||
|
|
||||||
|
def hide_object(obj_to_set):
|
||||||
|
obj_to_set.hide_set(True)
|
||||||
|
obj_to_set.hide_viewport = True
|
||||||
|
|
||||||
|
|
||||||
|
def is_object_hidden(obj_to_get):
|
||||||
|
if obj_to_get.hide_get() == False and obj_to_get.hide_viewport == False:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def append_cs(names=[]):
|
||||||
|
context = bpy.context
|
||||||
|
scene = context.scene
|
||||||
|
addon_directory = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
filepath = addon_directory + "\cs.blend"
|
||||||
|
|
||||||
|
# load the objects data in file
|
||||||
|
with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
|
||||||
|
data_to.objects = [name for name in data_from.objects if name in names]
|
||||||
|
|
||||||
|
# Add the objects in the scene
|
||||||
|
for obj in data_to.objects:
|
||||||
|
if obj:
|
||||||
|
# link in collec
|
||||||
|
scene.collection.objects.link(obj)
|
||||||
|
|
||||||
|
cs_grp = bpy.data.objects.get("cs_grp")
|
||||||
|
if cs_grp == None:
|
||||||
|
cs_grp = bpy.data.objects.new(name="cs_grp", object_data=None)
|
||||||
|
bpy.context.collection.objects.link(cs_grp)
|
||||||
|
cs_grp.location = [0,0,0]
|
||||||
|
cs_grp.rotation_euler = [0,0,0]
|
||||||
|
cs_grp.scale = [1,1,1]
|
||||||
|
|
||||||
|
# parent the custom shape
|
||||||
|
obj.parent = cs_grp
|
||||||
|
|
||||||
|
# assign to new collection
|
||||||
|
assigned_collections = []
|
||||||
|
for collec in cs_grp.users_collection:
|
||||||
|
try:
|
||||||
|
collec.objects.link(obj)
|
||||||
|
assigned_collections.append(collec)
|
||||||
|
except:# already in collection
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(assigned_collections):
|
||||||
|
# remove previous collections
|
||||||
|
for i in obj.users_collection:
|
||||||
|
if not i in assigned_collections:
|
||||||
|
i.objects.unlink(obj)
|
||||||
|
# and the scene collection
|
||||||
|
try:
|
||||||
|
scene.collection.objects.unlink(obj)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
35
assets/blender/scripts/mixamo/3.6/mixamo/lib/version.py
Normal file
35
assets/blender/scripts/mixamo/3.6/mixamo/lib/version.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
class ARP_blender_version:
|
||||||
|
_string = bpy.app.version_string
|
||||||
|
blender_v = bpy.app.version
|
||||||
|
_float = blender_v[0]*100+blender_v[1]+blender_v[2]*0.01
|
||||||
|
_char = bpy.app.version_char
|
||||||
|
|
||||||
|
blender_version = ARP_blender_version()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_drivers_cs_to_xyz(armature):
|
||||||
|
# Blender 3.0 requires Vector3 custom_shape_scale values
|
||||||
|
# convert single uniform driver to vector3 array drivers
|
||||||
|
drivers_armature = [i for i in armature.animation_data.drivers]
|
||||||
|
|
||||||
|
for dr in drivers_armature:
|
||||||
|
if 'custom_shape_scale' in dr.data_path:
|
||||||
|
if not 'custom_shape_scale_xyz' in dr.data_path:
|
||||||
|
for i in range(0, 3):
|
||||||
|
new_dr = armature.animation_data.drivers.from_existing(src_driver=dr)
|
||||||
|
new_dr.data_path = new_dr.data_path.replace('custom_shape_scale', 'custom_shape_scale_xyz')
|
||||||
|
new_dr.array_index = i
|
||||||
|
new_dr.driver.expression += ''# update hack
|
||||||
|
|
||||||
|
armature.driver_remove(dr.data_path, dr.array_index)
|
||||||
|
|
||||||
|
print("Converted custom shape scale drivers to xyz")
|
||||||
|
|
||||||
|
|
||||||
|
def get_custom_shape_scale_prop_name():
|
||||||
|
if blender_version._float >= 300:
|
||||||
|
return 'custom_shape_scale_xyz'
|
||||||
|
else:
|
||||||
|
return 'custom_shape_scale'
|
||||||
2764
assets/blender/scripts/mixamo/3.6/mixamo/mixamo_rig.py
Normal file
2764
assets/blender/scripts/mixamo/3.6/mixamo/mixamo_rig.py
Normal file
File diff suppressed because it is too large
Load Diff
1116
assets/blender/scripts/mixamo/3.6/mixamo/mixamo_rig_functions.py
Normal file
1116
assets/blender/scripts/mixamo/3.6/mixamo/mixamo_rig_functions.py
Normal file
File diff suppressed because it is too large
Load Diff
31
assets/blender/scripts/mixamo/3.6/mixamo/mixamo_rig_prefs.py
Normal file
31
assets/blender/scripts/mixamo/3.6/mixamo/mixamo_rig_prefs.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import bpy
|
||||||
|
|
||||||
|
def update_all_tab_names(self, context):
|
||||||
|
try:
|
||||||
|
from . import mixamo_rig
|
||||||
|
mixamo_rig.update_mixamo_tab()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MR_MT_addon_preferences(bpy.types.AddonPreferences):
|
||||||
|
bl_idname = __package__
|
||||||
|
mixamo_tab_name : bpy.props.StringProperty(name="Interface Tab", description="Name of the tab to display the interface in", default="Mixamo", update=update_all_tab_names)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
col = self.layout.column(align=True)
|
||||||
|
col.prop(self, "mixamo_tab_name", text="Interface Tab")
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
from bpy.utils import register_class
|
||||||
|
|
||||||
|
try:
|
||||||
|
register_class(MR_MT_addon_preferences)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
from bpy.utils import unregister_class
|
||||||
|
unregister_class(MR_MT_addon_preferences)
|
||||||
18
assets/blender/scripts/mixamo/3.6/mixamo/utils.py
Normal file
18
assets/blender/scripts/mixamo/3.6/mixamo/utils.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import bpy, os
|
||||||
|
from math import *
|
||||||
|
from mathutils import *
|
||||||
|
from bpy.types import Panel, UIList
|
||||||
|
from .lib.objects import *
|
||||||
|
from .lib.bones_data import *
|
||||||
|
from .lib.bones_edit import *
|
||||||
|
from .lib.bones_pose import *
|
||||||
|
from .lib.context import *
|
||||||
|
from .lib.addon import *
|
||||||
|
from .lib.mixamo import *
|
||||||
|
from .lib.armature import *
|
||||||
|
from .lib.constraints import *
|
||||||
|
from .lib.animation import *
|
||||||
|
from .lib.maths_geo import *
|
||||||
|
from .lib.drivers import *
|
||||||
|
from .lib.custom_props import *
|
||||||
|
from .lib.version import *
|
||||||
1
assets/blender/scripts/mixamo/4.3/mixamo/define.py
Normal file
1
assets/blender/scripts/mixamo/4.3/mixamo/define.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .definitions.naming import *
|
||||||
BIN
assets/blender/scripts/mixamo/4.3/mixamo/lib/cs.blend
Normal file
BIN
assets/blender/scripts/mixamo/4.3/mixamo/lib/cs.blend
Normal file
Binary file not shown.
@@ -1,13 +1,41 @@
|
|||||||
[brushes/0]
|
[brushes/0]
|
||||||
|
|
||||||
curve=[ Vector2( 0, 2 ), 0.0, 0.0, 0, 0, Vector2( 1, -0.0338984 ), 0.0, 0.0, 0, 0 ]
|
curve=[ Vector2( 0, 0.847458 ), 0.0, 0.0, 0, 0, Vector2( 0.989691, 0.0338984 ), -0.51918, 0.0, 0, 0 ]
|
||||||
radius=2.0
|
radius=20.0
|
||||||
strength=1.0
|
strength=0.05
|
||||||
flags=0
|
flags=49
|
||||||
|
|
||||||
[brushes/1]
|
[brushes/1]
|
||||||
|
|
||||||
curve=[ ]
|
curve=[ Vector2( 0, 2 ), 0.0, 0.0, 0, 0, Vector2( 0.262887, -0.169492 ), -11.5085, -11.5085, 0, 0, Vector2( 0.463917, -2 ), 0.0, 0.0, 0, 0, Vector2( 0.608247, -0.0677965 ), 15.2076, 15.2076, 0, 0, Vector2( 0.77835, 2 ), 0.0, 0.0, 0, 0, Vector2( 1, -0.0338984 ), 0.0, 0.0, 0, 0 ]
|
||||||
radius=1.0
|
radius=200.0
|
||||||
|
strength=0.2
|
||||||
|
flags=1
|
||||||
|
|
||||||
|
[brushes/2]
|
||||||
|
|
||||||
|
curve=[ Vector2( 0, -2 ), 0.0, 0.0, 0, 0, Vector2( 1, 0 ), 5.21566, 0.0, 0, 0 ]
|
||||||
|
radius=30.0
|
||||||
|
strength=1.0
|
||||||
|
flags=8
|
||||||
|
|
||||||
|
[brushes/3]
|
||||||
|
|
||||||
|
curve=[ Vector2( 0.0412371, -2 ), 0.0, 0.0, 0, 0, Vector2( 0.417526, -2 ), 0.0, 0.0, 0, 0, Vector2( 1, -0.101695 ), 5.54873, 0.0, 0, 0 ]
|
||||||
|
radius=300.0
|
||||||
|
strength=35.0
|
||||||
|
flags=0
|
||||||
|
|
||||||
|
[brushes/4]
|
||||||
|
|
||||||
|
curve=[ Vector2( 0, -0.372881 ), 0.0, 0.0, 0, 0, Vector2( 0.561856, -0.338983 ), 0.979444, 0.979444, 0, 0, Vector2( 1, 0.0338984 ), 3.91445, 0.0, 0, 0 ]
|
||||||
|
radius=60.0
|
||||||
strength=1.0
|
strength=1.0
|
||||||
flags=0
|
flags=0
|
||||||
|
|
||||||
|
[brushes/5]
|
||||||
|
|
||||||
|
curve=[ Vector2( 0, 2 ), 0.0, -2.09245, 0, 0, Vector2( 1, 0.542373 ), 0.0, 0.0, 0, 0 ]
|
||||||
|
radius=40.0
|
||||||
|
strength=0.5
|
||||||
|
flags=0
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -781,6 +781,8 @@
|
|||||||
"center2_road": {
|
"center2_road": {
|
||||||
"points": [
|
"points": [
|
||||||
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1110, 0.0210266, -245 )",
|
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1110, 0.0210266, -245 )",
|
||||||
|
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1118, 0.000228882, -138 )",
|
||||||
|
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1122, 0.000144958, -98 )",
|
||||||
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1125, -0.293396, -60 )",
|
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1125, -0.293396, -60 )",
|
||||||
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -835, 0.0421448, -60 )",
|
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -835, 0.0421448, -60 )",
|
||||||
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -330, 0.0576782, -60 )",
|
"Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -330, 0.0576782, -60 )",
|
||||||
@@ -993,6 +995,7 @@
|
|||||||
"lanes": -1,
|
"lanes": -1,
|
||||||
"pattern": 1,
|
"pattern": 1,
|
||||||
"buildings": [
|
"buildings": [
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"buildings9_buildings": {
|
"buildings9_buildings": {
|
||||||
@@ -1009,6 +1012,55 @@
|
|||||||
"lanes": -1,
|
"lanes": -1,
|
||||||
"pattern": 1,
|
"pattern": 1,
|
||||||
"buildings": [
|
"buildings": [
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"building_key": "",
|
"building_key": "",
|
||||||
"line_offset": 0,
|
"line_offset": 0,
|
||||||
@@ -1227,6 +1279,153 @@
|
|||||||
"y_rotation": 0,
|
"y_rotation": 0,
|
||||||
"y_offset": 0
|
"y_offset": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"building_key": "",
|
"building_key": "",
|
||||||
"line_offset": 0,
|
"line_offset": 0,
|
||||||
@@ -1653,6 +1852,398 @@
|
|||||||
"y_rotation": 0,
|
"y_rotation": 0,
|
||||||
"y_offset": 0
|
"y_offset": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"building_key": "",
|
||||||
|
"line_offset": 0,
|
||||||
|
"normal_offset": 0,
|
||||||
|
"y_rotation": 0,
|
||||||
|
"y_offset": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"building_key": "",
|
"building_key": "",
|
||||||
"line_offset": 0,
|
"line_offset": 0,
|
||||||
@@ -1677,4 +2268,4 @@
|
|||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
#undef NDEBUG
|
||||||
|
#include <cassert>
|
||||||
|
#include <core/io/resource_loader.h>
|
||||||
|
#include <core/os/file_access.h>
|
||||||
|
#include <core/io/compression.h>
|
||||||
#include "voxel_generator_imgmapper.h"
|
#include "voxel_generator_imgmapper.h"
|
||||||
#include <modules/voxel/util/fixed_array.h>
|
#include <modules/voxel/util/fixed_array.h>
|
||||||
#include "modules/voxel/util/span.h"
|
#include "modules/voxel/util/span.h"
|
||||||
@@ -45,6 +50,7 @@ namespace
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
#if 0
|
||||||
std::map<int, struct EditBrush *> EditBrushList::brushes;
|
std::map<int, struct EditBrush *> EditBrushList::brushes;
|
||||||
std::map<int, String> EditBrushList::brush_names;
|
std::map<int, String> EditBrushList::brush_names;
|
||||||
struct Brush0 : EditBrush
|
struct Brush0 : EditBrush
|
||||||
@@ -267,18 +273,21 @@ T *RegBrush(Args &&...args)
|
|||||||
EditBrushList::register_brush(&data);
|
EditBrushList::register_brush(&data);
|
||||||
return &data;
|
return &data;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
VoxelGeneratorImgMapper::VoxelGeneratorImgMapper()
|
VoxelGeneratorImgMapper::VoxelGeneratorImgMapper()
|
||||||
: VoxelGeneratorHeightmap(),
|
: VoxelGeneratorHeightmap(),
|
||||||
world_size(10240),
|
world_size(10240),
|
||||||
grid_size(0)
|
grid_size(0)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
RegBrush<Brush0>(_image_draw);
|
RegBrush<Brush0>(_image_draw);
|
||||||
RegBrush<Brush1>(_image_draw);
|
RegBrush<Brush1>(_image_draw);
|
||||||
RegBrush<Brush2>(_image_draw, curve1);
|
RegBrush<Brush2>(_image_draw, curve1);
|
||||||
RegBrush<Brush3>(_image_draw, curve1, this);
|
RegBrush<Brush3>(_image_draw, curve1, this);
|
||||||
RegBrush<Brush4>(_image_draw, curve2, this);
|
RegBrush<Brush4>(_image_draw, curve2, this);
|
||||||
RegBrush<Brush5>(_image_draw, this);
|
RegBrush<Brush5>(_image_draw, this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelGeneratorImgMapper::~VoxelGeneratorImgMapper()
|
VoxelGeneratorImgMapper::~VoxelGeneratorImgMapper()
|
||||||
@@ -384,7 +393,7 @@ VoxelGenerator::Result VoxelGeneratorImgMapper::generate_block(VoxelBlockRequest
|
|||||||
result = VoxelGeneratorHeightmap::generate(
|
result = VoxelGeneratorHeightmap::generate(
|
||||||
out_buffer,
|
out_buffer,
|
||||||
[this](int x, int z)
|
[this](int x, int z)
|
||||||
{ return get_height_linear(Vector3(x, 0, z)); },
|
{ return get_height_linear2(Vector3(x, 0, z)); },
|
||||||
input.origin_in_voxels, input.lod);
|
input.origin_in_voxels, input.lod);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,11 +421,12 @@ float VoxelGeneratorImgMapper::get_height(const Vector3 &v)
|
|||||||
else
|
else
|
||||||
return get_height_repeat(**_parameters.image, v.x, v.z);
|
return get_height_repeat(**_parameters.image, v.x, v.z);
|
||||||
#endif
|
#endif
|
||||||
return get_height_linear(v);
|
return get_height_linear2(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
float VoxelGeneratorImgMapper::get_height_linear(const Vector3 &v)
|
float VoxelGeneratorImgMapper::get_height_linear(const Vector3 &v)
|
||||||
{
|
{
|
||||||
|
update_heightmaps(v);
|
||||||
int px = (int)(v.x / grid_size);
|
int px = (int)(v.x / grid_size);
|
||||||
int pz = (int)(v.z / grid_size);
|
int pz = (int)(v.z / grid_size);
|
||||||
float mx = (float)px * grid_size;
|
float mx = (float)px * grid_size;
|
||||||
@@ -439,11 +449,37 @@ float VoxelGeneratorImgMapper::get_height_linear(const Vector3 &v)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float VoxelGeneratorImgMapper::get_height_linear2(const Vector3 &v)
|
||||||
|
{
|
||||||
|
update_heightmaps(v);
|
||||||
|
int px = (int)v.x + world_size / 2;
|
||||||
|
int pz = (int)v.z + world_size / 2;
|
||||||
|
float mx = (float)px;
|
||||||
|
float mz = (float)pz;
|
||||||
|
// float Mx = mx + (float)grid_size;
|
||||||
|
// float Mz = mz + (float)grid_size;
|
||||||
|
float x_weight = 0.0f;
|
||||||
|
float z_weight = 0.0f;
|
||||||
|
// float d0x = (v.x - mx) / (float)grid_size;
|
||||||
|
// float d0z = (v.z - mz) / (float)grid_size;
|
||||||
|
// float d1x = (mx + (float)grid_size - v.x) / (float)grid_size;
|
||||||
|
// float d1z = (mz + (float)grid_size - v.z) / (float)grid_size;
|
||||||
|
float p0 = get_world_pixel(px, pz);
|
||||||
|
float p1 = get_world_pixel(px + 1, pz);
|
||||||
|
float p2 = get_world_pixel(px, pz + 1);
|
||||||
|
float p3 = get_world_pixel(px + 1, pz + 1);
|
||||||
|
float a = (1.0f - x_weight);
|
||||||
|
float b = (1.0f - z_weight);
|
||||||
|
float result = p0 * a * b + p1 * x_weight * b + p2 * z_weight * a + p3 * x_weight * z_weight;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
float VoxelGeneratorImgMapper::get_height_full(const Vector3 &v)
|
float VoxelGeneratorImgMapper::get_height_full(const Vector3 &v)
|
||||||
{
|
{
|
||||||
return get_height(v) * 200.0f - 100.0f;
|
return get_height(v) * 200.0f - 100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, float r, float s, int id)
|
void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, float r, float s, int id)
|
||||||
{
|
{
|
||||||
print_line("draw_brush " + (v.operator String()) + " " +
|
print_line("draw_brush " + (v.operator String()) + " " +
|
||||||
@@ -492,191 +528,335 @@ void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, float r, float s, int
|
|||||||
float base_h = get_height_full(v);
|
float base_h = get_height_full(v);
|
||||||
float scale = s / 100.0f;
|
float scale = s / 100.0f;
|
||||||
EditBrushList::draw_brush(v, r, s, id);
|
EditBrushList::draw_brush(v, r, s, id);
|
||||||
#if 0
|
}
|
||||||
switch (id)
|
#endif
|
||||||
|
|
||||||
|
static inline Vector2 world2img(Ref<Image> img, const Vector3 &v)
|
||||||
|
{
|
||||||
|
|
||||||
|
Vector3 pos(v.x, v.y, v.z);
|
||||||
|
Vector2 pt = Vector2(pos.x * 0.1f + img->get_width() / 2,
|
||||||
|
pos.z * 0.1f + img->get_height() / 2);
|
||||||
|
pt.x = CLAMP(pt.x, 1, img->get_width() - 1);
|
||||||
|
pt.y = CLAMP(pt.y, 1, img->get_height() - 1);
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t VoxelGeneratorImgMapper::heightmap_index(const Vector3 &v)
|
||||||
|
{
|
||||||
|
int heightmap_size = 1024;
|
||||||
|
int world_offset = world_size / 2;
|
||||||
|
int wx = (int)v.x + world_offset;
|
||||||
|
int wz = (int)v.z + world_offset;
|
||||||
|
uint64_t heightmap_index = ((wz / heightmap_size) << 16) + wx / heightmap_size;
|
||||||
|
return heightmap_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<uint64_t> loaded_tiles;
|
||||||
|
static Set<uint64_t> dirty_tiles;
|
||||||
|
static HashMap<uint64_t, uint8_t *> tiles;
|
||||||
|
void VoxelGeneratorImgMapper::get_or_create_tile(uint64_t tile)
|
||||||
|
{
|
||||||
|
int heightmap_size = 1024;
|
||||||
|
Error err = OK;
|
||||||
|
String path = "res://terrain/" + String::hex_encode_buffer((uint8_t *)&tile, sizeof(tile)) + ".bin";
|
||||||
|
Vector<uint8_t> buffer;
|
||||||
|
if (loaded_tiles.has(tile))
|
||||||
|
return;
|
||||||
|
print_line("Loading: " + path + ": " + itos(loaded_tiles.size()));
|
||||||
|
buffer = FileAccess::get_file_as_array(path, &err);
|
||||||
|
if (err == OK)
|
||||||
{
|
{
|
||||||
case 0:
|
int i;
|
||||||
/* flat stuff */
|
uint8_t *buffer_dst = memnew_arr(uint8_t, heightmap_size * heightmap_size);
|
||||||
for (i = -xs; i < xs + 1; i++)
|
memset(buffer_dst, 127, heightmap_size * heightmap_size);
|
||||||
for (j = -xs; j < xs + 1; j++)
|
Compression::decompress(buffer_dst, heightmap_size * heightmap_size, buffer.ptr() + 8, buffer.size() - 8, Compression::MODE_FASTLZ);
|
||||||
{
|
tiles[tile] = buffer_dst;
|
||||||
float xr = Vector2(i, j).length();
|
loaded_tiles.insert(tile);
|
||||||
if (xr < r)
|
}
|
||||||
{
|
else
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
{
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
uint8_t *buffer_dst = memnew_arr(uint8_t, heightmap_size * heightmap_size);
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
memset(buffer_dst, 127, heightmap_size * heightmap_size);
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
tiles[tile] = buffer_dst;
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
loaded_tiles.insert(tile);
|
||||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
dirty_tiles.insert(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
/* erase stuff */
|
|
||||||
for (i = -xs; i < xs + 1; i++)
|
|
||||||
for (j = -xs; j < xs + 1; j++)
|
|
||||||
{
|
|
||||||
float xr = Vector2(i, j).length();
|
|
||||||
if (xr < r)
|
|
||||||
{
|
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
|
||||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
/* abs draw curve */
|
|
||||||
ERR_FAIL_COND(!curve1.is_valid());
|
|
||||||
for (i = -xs; i < xs + 1; i++)
|
|
||||||
for (j = -xs; j < xs + 1; j++)
|
|
||||||
{
|
|
||||||
float xr = Vector2(i, j).length();
|
|
||||||
if (xr < r)
|
|
||||||
{
|
|
||||||
float h = curve1->interpolate_baked(xr / r) * scale;
|
|
||||||
h = CLAMP(h, -100.0, 100.0f);
|
|
||||||
c = (h + 100.0f) / 200.0;
|
|
||||||
|
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
float VoxelGeneratorImgMapper::get_world_pixel(int wx, int wy)
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
{
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
int heightmap_size = 1024;
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
uint64_t tile_x = (wx / heightmap_size) & 0xFFFF;
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
uint64_t tile_z = (wy / heightmap_size) & 0xFFFF;
|
||||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
uint64_t tile = tile_x | (tile_z << 16);
|
||||||
}
|
assert(loaded_tiles.has(tile));
|
||||||
}
|
if (loaded_tiles.has(tile))
|
||||||
break;
|
{
|
||||||
case 3:
|
int px = (wx % heightmap_size);
|
||||||
/* rel draw curve1 */
|
int py = (wy % heightmap_size);
|
||||||
ERR_FAIL_COND(!curve1.is_valid());
|
assert(loaded_tiles.has(tile));
|
||||||
for (i = -xs; i < xs + 1; i++)
|
assert(tiles[tile]);
|
||||||
for (j = -xs; j < xs + 1; j++)
|
int raw_pixel = tiles[tile][px + py * heightmap_size];
|
||||||
{
|
float ret = (float)(raw_pixel) / 255.0f;
|
||||||
float xr = Vector2(i, j).length();
|
return ret;
|
||||||
if (xr < r)
|
}
|
||||||
{
|
return 0.0f;
|
||||||
float h = curve1->interpolate_baked(xr / r) * scale;
|
}
|
||||||
if (h < -2.0f || h > 2.0f)
|
|
||||||
{
|
|
||||||
h += get_height_full(v + Vector3(i, 0.0f, j));
|
|
||||||
h = CLAMP(h, -100.0, 100.0f);
|
|
||||||
c = (h + 100.0f) / 200.0;
|
|
||||||
|
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
void VoxelGeneratorImgMapper::set_world_pixel(int wx, int wy, float color)
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
{
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
int heightmap_size = 1024;
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
uint64_t tile_x = (wx / heightmap_size) & 0xFFFF;
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
uint64_t tile_z = (wy / heightmap_size) & 0xFFFF;
|
||||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
uint64_t tile = tile_x | (tile_z << 16);
|
||||||
}
|
// print_line("world pixel: " + itos(wx) + " " + itos(wy) + String::num(color));
|
||||||
}
|
assert(loaded_tiles.has(tile));
|
||||||
}
|
assert(tiles[tile]);
|
||||||
break;
|
if (loaded_tiles.has(tile))
|
||||||
case 4:
|
{
|
||||||
/* rel draw curve2 */
|
int px = (wx % heightmap_size);
|
||||||
ERR_FAIL_COND(!curve2.is_valid());
|
int py = (wy % heightmap_size);
|
||||||
for (i = -xs; i < xs + 1; i++)
|
int raw_pixels = (int)(color * 255.0f);
|
||||||
for (j = -xs; j < xs + 1; j++)
|
tiles[tile][px + py * heightmap_size] = raw_pixels;
|
||||||
{
|
dirty_tiles.insert(tile);
|
||||||
float xr = Vector2(i, j).length();
|
// print_line("dirty tile: " + String::num_uint64(tile, 16));
|
||||||
if (xr < r)
|
}
|
||||||
{
|
}
|
||||||
float h = curve2->interpolate_baked(xr / r) * scale;
|
|
||||||
if (h < -2.0f || h > 2.0f)
|
|
||||||
{
|
|
||||||
h += get_height_full(v + Vector3(i, 0.0f, j));
|
|
||||||
h = CLAMP(h, -100.0, 100.0f);
|
|
||||||
c = (h + 100.0f) / 200.0;
|
|
||||||
|
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
void VoxelGeneratorImgMapper::save_dirty_tiles()
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
{
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
Set<uint64_t>::Element *e = dirty_tiles.front();
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
int heightmap_size = 1024;
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
print_line("Save Dirty Tiles");
|
||||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
while (e)
|
||||||
}
|
{
|
||||||
}
|
uint64_t tile = e->get();
|
||||||
}
|
Vector<uint8_t> buffer;
|
||||||
break;
|
buffer.resize(heightmap_size * heightmap_size + 8);
|
||||||
#if 0
|
buffer.write[0] = (uint8_t)(heightmap_size % 256);
|
||||||
|
buffer.write[1] = (uint8_t)(heightmap_size >> 8);
|
||||||
|
buffer.write[2] = (uint8_t)(heightmap_size % 256);
|
||||||
|
buffer.write[3] = (uint8_t)(heightmap_size >> 8);
|
||||||
|
buffer.write[4] = 0;
|
||||||
|
buffer.write[5] = 0;
|
||||||
|
buffer.write[6] = 0;
|
||||||
|
buffer.write[7] = 0;
|
||||||
|
assert(loaded_tiles.has(tile));
|
||||||
|
assert(tiles[tile]);
|
||||||
|
int size = Compression::compress(buffer.ptrw() + 8, tiles[tile], heightmap_size * heightmap_size, Compression::MODE_FASTLZ);
|
||||||
|
Error err = OK;
|
||||||
|
String path = "res://terrain/" + String::hex_encode_buffer((uint8_t *)&tile, sizeof(tile)) + ".bin";
|
||||||
|
print_line("Saving: " + path + ": " + itos(loaded_tiles.size()));
|
||||||
|
FileAccess *pfd = FileAccess::open(path, FileAccess::WRITE, &err);
|
||||||
|
if (err == OK && pfd)
|
||||||
{
|
{
|
||||||
Ref<Curve> curve;
|
pfd->store_buffer(buffer.ptr(), size + 8);
|
||||||
if (id == 3)
|
pfd->close();
|
||||||
curve = curve1;
|
}
|
||||||
else if (id == 4)
|
e = e->next();
|
||||||
curve = curve2;
|
}
|
||||||
ERR_FAIL_COND(!curve.is_valid());
|
dirty_tiles.clear();
|
||||||
Ref<Image> img;
|
}
|
||||||
img.instance();
|
|
||||||
img->create(xs * 2, xs * 2, false, Image::FORMAT_RGBA8);
|
|
||||||
img->fill(Color(0, 0, 0, 0));
|
|
||||||
for (i = -xs ; i < xs + 1; i++)
|
|
||||||
for (j = -xs ; j < xs + 1; j++) {
|
|
||||||
float xr = Vector2(i, j).length();
|
|
||||||
if (xr < r) {
|
|
||||||
float h = curve->interpolate_baked(xr / r);
|
|
||||||
if (h < -2.0f || h > 2.0f) {
|
|
||||||
h += get_height_full(v + Vector3(i, 0.0f, j));
|
|
||||||
h = CLAMP(h, -100.0, 100.0f);
|
|
||||||
c = (h + 100.0f) / 200.0;
|
|
||||||
|
|
||||||
img->fill_rect(Rect2(Vector2(i + xs, j + xs), Vector2(1, 1)), Color(c, 0, 0, 1));
|
void VoxelGeneratorImgMapper::draw_brush(const Vector3 &v, Ref<Curve> curve, float radius, float strength, int flags)
|
||||||
}
|
{
|
||||||
}
|
float min_x = v.x - radius;
|
||||||
}
|
float min_z = v.z - radius;
|
||||||
Vector3 pos(v.x, v.y, v.z);
|
float max_x = v.x + radius;
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
float max_z = v.z + radius;
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
float step = grid_size;
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
Vector3 min_pos(min_x, v.y, min_z), max_pos(max_x, v.y, max_z);
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
int x, z;
|
||||||
_image_draw->blend_rect(img,
|
update_heightmaps(v);
|
||||||
Rect2(Vector2(), Vector2(img->get_width(), img->get_height())),
|
if (radius < 1.0f || strength <= 0.0f)
|
||||||
Vector2(pt.x - xs, pt.y - xs));
|
return;
|
||||||
|
if (!_image_draw.is_valid())
|
||||||
} break;
|
return;
|
||||||
#endif
|
if (!brush_canvas.is_valid())
|
||||||
case 5:
|
brush_canvas = _image_draw->duplicate();
|
||||||
|
brush_canvas->blit_rect(_image_draw, Rect2(0, 0, _image_draw->get_width(), _image_draw->get_height()), Vector2());
|
||||||
|
int xpos_min = min_pos.x / grid_size + _image_draw->get_width() / 2;
|
||||||
|
int xpos_max = max_pos.x / grid_size + _image_draw->get_width() / 2;
|
||||||
|
int zpos_min = min_pos.z / grid_size + _image_draw->get_height() / 2;
|
||||||
|
int zpos_max = max_pos.z / grid_size + _image_draw->get_height() / 2;
|
||||||
|
int radius_int = Math::ceil(radius / grid_size);
|
||||||
|
int center_x = v.x / grid_size + _image_draw->get_width() / 2;
|
||||||
|
int center_z = v.z / grid_size + _image_draw->get_height() / 2;
|
||||||
|
int wx_min = world_size / 2 + (int)min_pos.x;
|
||||||
|
int wx_max = world_size / 2 + (int)max_pos.x;
|
||||||
|
int wz_min = world_size / 2 + (int)min_pos.z;
|
||||||
|
int wz_max = world_size / 2 + (int)max_pos.z;
|
||||||
|
int wx_center = world_size / 2 + (int)v.x;
|
||||||
|
int wz_center = world_size / 2 + (int)v.z;
|
||||||
|
gen.set_seed(wx_center + world_size * wz_center);
|
||||||
|
// abs + offt (1 << 0)
|
||||||
|
// abs (1 << 1)
|
||||||
|
// rnd (1 << 2)
|
||||||
|
// flatten (1 << 3)
|
||||||
|
// smooth (1 << 4)
|
||||||
|
// no increments (1 << 5)
|
||||||
|
float avg = 0.0f;
|
||||||
|
float minv = Math_INF;
|
||||||
|
float maxv = -Math_INF;
|
||||||
|
if (flags & 16)
|
||||||
{
|
{
|
||||||
float h = get_height_full(v) + 2.0f;
|
int count = 0;
|
||||||
h = CLAMP(h, -100.0, 100.0f);
|
for (z = wz_min; z <= wz_max; z++)
|
||||||
for (i = -8; i < 8 + 1; i++)
|
{
|
||||||
for (j = -8; j < 8 + 1; j++)
|
for (x = wx_min; x <= wx_max; x++)
|
||||||
{
|
{
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
float r = Vector2((x - wx_center), (z - wz_center)).length();
|
||||||
h = MAX(h, get_height_full(pos) + 2.0f);
|
if (r >= radius)
|
||||||
|
continue;
|
||||||
|
float h = get_world_pixel(x, z);
|
||||||
|
if (minv > h)
|
||||||
|
minv = h;
|
||||||
|
if (maxv < h)
|
||||||
|
maxv = h;
|
||||||
|
avg += h;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
c = (h + 100.0f) / 200.0;
|
}
|
||||||
for (i = -xs; i < xs + 1; i++)
|
avg /= (float)count;
|
||||||
for (j = -xs; j < xs + 1; j++)
|
}
|
||||||
|
print_line("AVG: " + String::num(avg));
|
||||||
|
for (z = wz_min; z <= wz_max; z++)
|
||||||
|
{
|
||||||
|
for (x = wx_min; x <= wx_max; x++)
|
||||||
|
{
|
||||||
|
float r = Vector2((x - wx_center), (z - wz_center)).length();
|
||||||
|
if (r >= radius)
|
||||||
|
continue;
|
||||||
|
float offset = r / radius;
|
||||||
|
float value = curve->interpolate_baked(offset) * strength;
|
||||||
|
float nvalue = value * 0.5f; // -1:1 range
|
||||||
|
float mvalue = nvalue * 0.5f + 0.5f; // 0:1 range
|
||||||
|
float nh = CLAMP((v.y + 100.0f) / 200.0f, 0.0f, 1.0f);
|
||||||
|
float h = get_world_pixel(x, z);
|
||||||
|
float new_h = h + nvalue;
|
||||||
|
float c;
|
||||||
|
if (flags & 1) // absolute with offset
|
||||||
|
new_h = nh + nvalue;
|
||||||
|
else if (flags & 2) // absolute
|
||||||
|
new_h = nvalue;
|
||||||
|
if (flags & 8)
|
||||||
|
new_h = nh;
|
||||||
|
else if (flags & 16)
|
||||||
{
|
{
|
||||||
float xr = Vector2(i, j).length();
|
int ox, oz;
|
||||||
if (xr < r)
|
float hu = maxv - avg;
|
||||||
|
float hb = avg - minv;
|
||||||
|
new_h = avg + (h - avg) * 0.9f;
|
||||||
|
if (z > 0 && z < world_size - 1 && x > 0 && x < world_size - 1)
|
||||||
{
|
{
|
||||||
Vector3 pos(v.x + i, v.y, v.z + j);
|
float smooth_h = 0.0f;
|
||||||
Vector2 pt = Vector2(pos.x * 0.1f + _image_draw->get_width() / 2,
|
int smooth_count = 0;
|
||||||
pos.z * 0.1f + _image_draw->get_height() / 2);
|
for (oz = 0; oz < 5; oz++)
|
||||||
pt.x = CLAMP(pt.x, 1, _image_draw->get_width() - 1);
|
for (ox = 0; ox < 5; ox++)
|
||||||
pt.y = CLAMP(pt.y, 1, _image_draw->get_height() - 1);
|
{
|
||||||
_image_draw->fill_rect(Rect2(pt - Vector2(1, 1), Vector2(2, 2)), Color(c, 0, 0, 1));
|
if (ox == 0 && oz == 0)
|
||||||
|
continue;
|
||||||
|
smooth_h += get_world_pixel(x + ox - 2, z + oz - 2);
|
||||||
|
smooth_count++;
|
||||||
|
}
|
||||||
|
new_h = new_h * 0.5f + smooth_h / (float)smooth_count * 0.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (flags & 4)
|
||||||
|
new_h = 0.95f * new_h + 0.05f * (gen.randf() - 0.5f);
|
||||||
|
// relative
|
||||||
|
if (flags & 32)
|
||||||
|
c = CLAMP(new_h, 0.0f, 1.0f);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (offset > 0.9f)
|
||||||
|
c = CLAMP(h * 0.95f + new_h * 0.05f, 0.0f, 1.0f);
|
||||||
|
else
|
||||||
|
c = CLAMP(h * 0.8f + new_h * 0.2f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
set_world_pixel(x, z, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
#if 0
|
||||||
default:
|
int wz = world_size / 2 + (int)v.z;
|
||||||
break;
|
brush_canvas->lock();
|
||||||
|
for (z = zpos_min; z <= zpos_max; z++)
|
||||||
|
{
|
||||||
|
for (x = xpos_min; x <= xpos_max; x++)
|
||||||
|
{
|
||||||
|
float r = Vector2((x - center_x) * grid_size, (z - center_z) * grid_size).length();
|
||||||
|
if (r >= radius)
|
||||||
|
continue;
|
||||||
|
float offset = r / radius;
|
||||||
|
float value = curve->interpolate_baked(offset) * strength;
|
||||||
|
float nvalue = value * 0.5f; // -1:1 range
|
||||||
|
float nh = CLAMP((v.y + 100.0f) / 200.0f, 0.0f, 1.0f);
|
||||||
|
int xx = CLAMP(x, 0, _image_draw->get_width() - 1);
|
||||||
|
int zz = CLAMP(z, 0, _image_draw->get_height() - 1);
|
||||||
|
// height in 0-1 range where 0.5 is zero
|
||||||
|
float h = brush_canvas->get_pixel(xx, zz).r;
|
||||||
|
// print_line("h: " + String::num(h));
|
||||||
|
float new_h;
|
||||||
|
float c;
|
||||||
|
new_h = h + nvalue;
|
||||||
|
if (flags & 1) // absolute
|
||||||
|
new_h = nh + nvalue;
|
||||||
|
// relative
|
||||||
|
if (offset > 0.9f)
|
||||||
|
c = CLAMP(h * 0.95f + new_h * 0.05f, 0.0f, 1.0f);
|
||||||
|
else
|
||||||
|
c = CLAMP(h * 0.8f + new_h * 0.2f, 0.0f, 1.0f);
|
||||||
|
// print_line("c: " + String::num(c));
|
||||||
|
brush_canvas->set_pixel(xx, zz, Color(c, 0, 0, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
brush_canvas->unlock();
|
||||||
|
_image_draw->blit_rect(brush_canvas, Rect2(0, 0, brush_canvas->get_width(), brush_canvas->get_height()), Vector2());
|
||||||
#endif
|
#endif
|
||||||
|
save_dirty_tiles();
|
||||||
|
}
|
||||||
|
static Mutex update_heightmaps_lock;
|
||||||
|
void VoxelGeneratorImgMapper::update_heightmaps(const Vector3 &v)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int heightmap_size = 1024;
|
||||||
|
uint64_t pos_x = (int)v.x + (world_size / 2);
|
||||||
|
uint64_t pos_z = (int)v.z + (world_size / 2);
|
||||||
|
uint64_t tile_x = (pos_x / heightmap_size) & 0xFFFF;
|
||||||
|
uint64_t tile_z = (pos_z / heightmap_size) & 0xFFFF;
|
||||||
|
Vector<uint64_t> tiles;
|
||||||
|
tiles.resize(9);
|
||||||
|
for (i = 0; i < tiles.size(); i++)
|
||||||
|
{
|
||||||
|
int m_x = (i % 3) - 1;
|
||||||
|
int m_z = (i / 3) - 1;
|
||||||
|
tiles.write[i] = (tile_z << 16) | tile_x;
|
||||||
|
if (tile_x == 0 && m_x < 0)
|
||||||
|
continue;
|
||||||
|
if (tile_z == 0 && m_z < 0)
|
||||||
|
continue;
|
||||||
|
tiles.write[i] = ((tile_z + m_x) << 16) | (tile_x + m_z);
|
||||||
|
}
|
||||||
|
Vector3 pos = v;
|
||||||
|
pos.y = 0;
|
||||||
|
update_heightmaps_lock.lock();
|
||||||
|
if (current_position.is_equal_approx(pos))
|
||||||
|
goto out_unlock;
|
||||||
|
for (i = 0; i < tiles.size(); i++)
|
||||||
|
{
|
||||||
|
if (!loaded_tiles.has(tiles[i]))
|
||||||
|
get_or_create_tile(tiles[i]);
|
||||||
|
}
|
||||||
|
current_position = pos;
|
||||||
|
out_unlock:
|
||||||
|
update_heightmaps_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelGeneratorImgMapper::compose()
|
void VoxelGeneratorImgMapper::compose()
|
||||||
{
|
{
|
||||||
Ref<Image> copy;
|
Ref<Image> copy;
|
||||||
print_line("compose");
|
// print_line("compose");
|
||||||
ERR_FAIL_COND(!_image_bg.is_valid());
|
ERR_FAIL_COND(!_image_bg.is_valid());
|
||||||
ERR_FAIL_COND(!_image_overlay.is_valid());
|
ERR_FAIL_COND(!_image_overlay.is_valid());
|
||||||
ERR_FAIL_COND(!_image_draw.is_valid());
|
ERR_FAIL_COND(!_image_draw.is_valid());
|
||||||
@@ -723,6 +903,7 @@ void VoxelGeneratorImgMapper::save_png()
|
|||||||
_image_overlay->save_png("res://terrain/terrain_edit.png");
|
_image_overlay->save_png("res://terrain/terrain_edit.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
void VoxelGeneratorImgMapper::set_curve1(const Ref<Curve> &curve)
|
void VoxelGeneratorImgMapper::set_curve1(const Ref<Curve> &curve)
|
||||||
{
|
{
|
||||||
ERR_FAIL_COND(!curve.is_valid());
|
ERR_FAIL_COND(!curve.is_valid());
|
||||||
@@ -770,6 +951,7 @@ Ref<Curve> VoxelGeneratorImgMapper::get_curve4() const
|
|||||||
{
|
{
|
||||||
return curve4;
|
return curve4;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void VoxelGeneratorImgMapper::set_grid_size(int value)
|
void VoxelGeneratorImgMapper::set_grid_size(int value)
|
||||||
{
|
{
|
||||||
@@ -791,10 +973,12 @@ int VoxelGeneratorImgMapper::get_world_size() const
|
|||||||
return world_size;
|
return world_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
std::map<int, String> VoxelGeneratorImgMapper::get_brush_names() const
|
std::map<int, String> VoxelGeneratorImgMapper::get_brush_names() const
|
||||||
{
|
{
|
||||||
return EditBrushList::get_brush_names();
|
return EditBrushList::get_brush_names();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void VoxelGeneratorImgMapper::_bind_methods()
|
void VoxelGeneratorImgMapper::_bind_methods()
|
||||||
{
|
{
|
||||||
@@ -807,6 +991,7 @@ void VoxelGeneratorImgMapper::_bind_methods()
|
|||||||
ClassDB::bind_method(D_METHOD("set_image_draw", "image"), &VoxelGeneratorImgMapper::set_image_draw);
|
ClassDB::bind_method(D_METHOD("set_image_draw", "image"), &VoxelGeneratorImgMapper::set_image_draw);
|
||||||
ClassDB::bind_method(D_METHOD("get_image_draw"), &VoxelGeneratorImgMapper::get_image_draw);
|
ClassDB::bind_method(D_METHOD("get_image_draw"), &VoxelGeneratorImgMapper::get_image_draw);
|
||||||
|
|
||||||
|
#if 0
|
||||||
ClassDB::bind_method(D_METHOD("set_curve1", "curve"), &VoxelGeneratorImgMapper::set_curve1);
|
ClassDB::bind_method(D_METHOD("set_curve1", "curve"), &VoxelGeneratorImgMapper::set_curve1);
|
||||||
ClassDB::bind_method(D_METHOD("get_curve1"), &VoxelGeneratorImgMapper::get_curve1);
|
ClassDB::bind_method(D_METHOD("get_curve1"), &VoxelGeneratorImgMapper::get_curve1);
|
||||||
ClassDB::bind_method(D_METHOD("set_curve2", "curve"), &VoxelGeneratorImgMapper::set_curve2);
|
ClassDB::bind_method(D_METHOD("set_curve2", "curve"), &VoxelGeneratorImgMapper::set_curve2);
|
||||||
@@ -815,9 +1000,9 @@ void VoxelGeneratorImgMapper::_bind_methods()
|
|||||||
ClassDB::bind_method(D_METHOD("get_curve3"), &VoxelGeneratorImgMapper::get_curve3);
|
ClassDB::bind_method(D_METHOD("get_curve3"), &VoxelGeneratorImgMapper::get_curve3);
|
||||||
ClassDB::bind_method(D_METHOD("set_curve4", "curve"), &VoxelGeneratorImgMapper::set_curve4);
|
ClassDB::bind_method(D_METHOD("set_curve4", "curve"), &VoxelGeneratorImgMapper::set_curve4);
|
||||||
ClassDB::bind_method(D_METHOD("get_curve4"), &VoxelGeneratorImgMapper::get_curve4);
|
ClassDB::bind_method(D_METHOD("get_curve4"), &VoxelGeneratorImgMapper::get_curve4);
|
||||||
|
#endif
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_height", "v", "height"), &VoxelGeneratorImgMapper::set_height);
|
ClassDB::bind_method(D_METHOD("set_height", "v", "height"), &VoxelGeneratorImgMapper::set_height);
|
||||||
ClassDB::bind_method(D_METHOD("draw_brush", "v", "r", "s", "id"), &VoxelGeneratorImgMapper::draw_brush);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_height", "v"), &VoxelGeneratorImgMapper::get_height);
|
ClassDB::bind_method(D_METHOD("get_height", "v"), &VoxelGeneratorImgMapper::get_height);
|
||||||
ClassDB::bind_method(D_METHOD("get_height_full", "v"), &VoxelGeneratorImgMapper::get_height_full);
|
ClassDB::bind_method(D_METHOD("get_height_full", "v"), &VoxelGeneratorImgMapper::get_height_full);
|
||||||
ClassDB::bind_method(D_METHOD("compose"), &VoxelGeneratorImgMapper::compose);
|
ClassDB::bind_method(D_METHOD("compose"), &VoxelGeneratorImgMapper::compose);
|
||||||
@@ -832,9 +1017,11 @@ void VoxelGeneratorImgMapper::_bind_methods()
|
|||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_bg", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_bg", "get_image_bg");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_bg", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_bg", "get_image_bg");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_overlay", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_overlay", "get_image_overlay");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_overlay", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_overlay", "get_image_overlay");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_draw", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_draw", "get_image_draw");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "image_draw", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "set_image_draw", "get_image_draw");
|
||||||
|
#if 0
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve1", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve1", "get_curve1");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve1", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve1", "get_curve1");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve2", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve2", "get_curve2");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve2", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve2", "get_curve2");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve3", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve3", "get_curve3");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve3", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve3", "get_curve3");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve4", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve4", "get_curve4");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve4", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve4", "get_curve4");
|
||||||
|
#endif
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blur_enabled"), "set_blur_enabled", "is_blur_enabled");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blur_enabled"), "set_blur_enabled", "is_blur_enabled");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <core/math/random_number_generator.h>
|
||||||
#include <modules/voxel/generators/simple/voxel_generator_heightmap.h>
|
#include <modules/voxel/generators/simple/voxel_generator_heightmap.h>
|
||||||
#include <core/image.h>
|
#include <core/image.h>
|
||||||
#include <scene/resources/curve.h>
|
#include <scene/resources/curve.h>
|
||||||
@@ -21,6 +22,7 @@ struct EditBrush
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
struct EditBrushList
|
struct EditBrushList
|
||||||
{
|
{
|
||||||
static std::map<int, struct EditBrush *> brushes;
|
static std::map<int, struct EditBrush *> brushes;
|
||||||
@@ -46,6 +48,7 @@ public:
|
|||||||
return brush_names;
|
return brush_names;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// Provides infinite tiling heightmap based on an image
|
// Provides infinite tiling heightmap based on an image
|
||||||
class VoxelGeneratorImgMapper : public VoxelGeneratorHeightmap
|
class VoxelGeneratorImgMapper : public VoxelGeneratorHeightmap
|
||||||
@@ -74,14 +77,25 @@ public:
|
|||||||
Result generate_block(VoxelBlockRequest &input) override;
|
Result generate_block(VoxelBlockRequest &input) override;
|
||||||
|
|
||||||
void set_height(const Vector3 &v, float height);
|
void set_height(const Vector3 &v, float height);
|
||||||
|
#if 0
|
||||||
void draw_brush(const Vector3 &v, float r, float s, int id);
|
void draw_brush(const Vector3 &v, float r, float s, int id);
|
||||||
|
#endif
|
||||||
|
void draw_brush(const Vector3 &v, Ref<Curve> curve, float radius, float strength, int flags);
|
||||||
|
void update_heightmaps(const Vector3 &v);
|
||||||
|
uint64_t heightmap_index(const Vector3 &v);
|
||||||
|
void get_or_create_tile(uint64_t tile);
|
||||||
|
float get_world_pixel(int wx, int wy);
|
||||||
|
void set_world_pixel(int wx, int wy, float color);
|
||||||
|
void save_dirty_tiles();
|
||||||
float get_height(const Vector3 &v);
|
float get_height(const Vector3 &v);
|
||||||
float get_height_linear(const Vector3 &v);
|
float get_height_linear(const Vector3 &v);
|
||||||
|
float get_height_linear2(const Vector3 &v);
|
||||||
float get_height_full(const Vector3 &v);
|
float get_height_full(const Vector3 &v);
|
||||||
float get_height_full_linear(const Vector3 &v);
|
float get_height_full_linear(const Vector3 &v);
|
||||||
void compose();
|
void compose();
|
||||||
void save_png();
|
void save_png();
|
||||||
|
|
||||||
|
#if 0
|
||||||
void set_curve1(const Ref<Curve> &curve);
|
void set_curve1(const Ref<Curve> &curve);
|
||||||
Ref<Curve> get_curve1() const;
|
Ref<Curve> get_curve1() const;
|
||||||
|
|
||||||
@@ -93,10 +107,13 @@ public:
|
|||||||
|
|
||||||
void set_curve4(const Ref<Curve> &curve);
|
void set_curve4(const Ref<Curve> &curve);
|
||||||
Ref<Curve> get_curve4() const;
|
Ref<Curve> get_curve4() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
void set_world_size(int value);
|
void set_world_size(int value);
|
||||||
int get_world_size() const;
|
int get_world_size() const;
|
||||||
|
#if 0
|
||||||
std::map<int, String> get_brush_names() const;
|
std::map<int, String> get_brush_names() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
@@ -107,6 +124,9 @@ private:
|
|||||||
Ref<Image> _image_bg;
|
Ref<Image> _image_bg;
|
||||||
Ref<Image> _image_overlay, _image_buildings;
|
Ref<Image> _image_overlay, _image_buildings;
|
||||||
Ref<Image> _image_draw;
|
Ref<Image> _image_draw;
|
||||||
|
Ref<Image> brush_canvas;
|
||||||
|
Vector3 current_position;
|
||||||
|
RandomNumberGenerator gen;
|
||||||
|
|
||||||
Ref<Curve> curve1, curve2, curve3, curve4;
|
Ref<Curve> curve1, curve2, curve3, curve4;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ module_obj = []
|
|||||||
SConscript("buildings/SCsub")
|
SConscript("buildings/SCsub")
|
||||||
SConscript("rtree/SCsub")
|
SConscript("rtree/SCsub")
|
||||||
SConscript("ui/SCsub")
|
SConscript("ui/SCsub")
|
||||||
|
SConscript("npc/SCsub")
|
||||||
|
|
||||||
env_stream = env_modules.Clone()
|
env_stream = env_modules.Clone()
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ void BuildingsData::build_building_aabbs()
|
|||||||
building_aabbs[e->get()] = aabb;
|
building_aabbs[e->get()] = aabb;
|
||||||
scene->queue_delete();
|
scene->queue_delete();
|
||||||
ps.unref();
|
ps.unref();
|
||||||
}
|
} else
|
||||||
|
print_error("Could not load: " + path);
|
||||||
e = e->next();
|
e = e->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -604,6 +605,12 @@ Node *BuildingsData::get_scene_item_node(const String &key,
|
|||||||
return bi->node;
|
return bi->node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildingsData::save_buildings()
|
||||||
|
{
|
||||||
|
String buildings_path = config.get_value("buildings", "buildings_path");
|
||||||
|
save_buildings_json(buildings_path);
|
||||||
|
}
|
||||||
|
|
||||||
Node *BuildingsData::item_nodes_get_node(const String &key) const
|
Node *BuildingsData::item_nodes_get_node(const String &key) const
|
||||||
{
|
{
|
||||||
flecs::query_builder<const CBuildingInstance> qb =
|
flecs::query_builder<const CBuildingInstance> qb =
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
Node *node);
|
Node *node);
|
||||||
bool has_scene_item(const String &key, const String &bkey) const;
|
bool has_scene_item(const String &key, const String &bkey) const;
|
||||||
Node *get_scene_item_node(const String &key, const String &bkey) const;
|
Node *get_scene_item_node(const String &key, const String &bkey) const;
|
||||||
|
void save_buildings();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Node *item_nodes_get_node(const String &key) const;
|
Node *item_nodes_get_node(const String &key) const;
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ void NavPanel::_notification(int which)
|
|||||||
EditorEvent::get_singleton()->event.emit(
|
EditorEvent::get_singleton()->event.emit(
|
||||||
"editor_camera_moved", varray(camera_xform));
|
"editor_camera_moved", varray(camera_xform));
|
||||||
transform_changhed = false;
|
transform_changhed = false;
|
||||||
print_line("moved: " +
|
print_verbose("moved: " +
|
||||||
(camera_xform.origin.operator String()));
|
(camera_xform.origin.operator String()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <editor/editor_node.h>
|
||||||
#include "register_types.h"
|
#include "register_types.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "road_debug.h"
|
#include "road_debug.h"
|
||||||
@@ -6,8 +7,18 @@
|
|||||||
#include "line_metadata_editor.h"
|
#include "line_metadata_editor.h"
|
||||||
#include "buildings/building_layout_editor.h"
|
#include "buildings/building_layout_editor.h"
|
||||||
#include "ui/main_tabs.h"
|
#include "ui/main_tabs.h"
|
||||||
|
#include "npc/importer.h"
|
||||||
#include "base_data.h"
|
#include "base_data.h"
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
static void _editor_init()
|
||||||
|
{
|
||||||
|
Ref<EditorImportNPC> import_npc;
|
||||||
|
import_npc.instance();
|
||||||
|
ResourceImporterScene::get_singleton()->add_importer(import_npc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void register_stream_types()
|
void register_stream_types()
|
||||||
{
|
{
|
||||||
ClassDB::register_class<StreamWorld>();
|
ClassDB::register_class<StreamWorld>();
|
||||||
@@ -17,6 +28,13 @@ void register_stream_types()
|
|||||||
ClassDB::register_class<LineMetadataEditor>();
|
ClassDB::register_class<LineMetadataEditor>();
|
||||||
ClassDB::register_class<BuildingLayoutEditor>();
|
ClassDB::register_class<BuildingLayoutEditor>();
|
||||||
ClassDB::register_class<MainTabs>();
|
ClassDB::register_class<MainTabs>();
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||||
|
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||||
|
ClassDB::register_class<EditorImportNPC>();
|
||||||
|
ClassDB::set_current_api(prev_api);
|
||||||
|
EditorNode::add_init_callback(_editor_init);
|
||||||
|
#endif
|
||||||
BaseData::get_singleton()->setup();
|
BaseData::get_singleton()->setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -216,21 +216,58 @@ struct RoadLinesProcessing {
|
|||||||
int onext = (j + 1) % edges[i].neighbors.size();
|
int onext = (j + 1) % edges[i].neighbors.size();
|
||||||
Vector3 n1 = normal(node - neighbors[j]);
|
Vector3 n1 = normal(node - neighbors[j]);
|
||||||
Vector3 n2 = normal(neighbors[onext] - node);
|
Vector3 n2 = normal(neighbors[onext] - node);
|
||||||
|
float angle = n1.signed_angle_to(
|
||||||
|
n2, Vector3(0, 1, 0));
|
||||||
Vector3 a0 = (neighbors[j] - node) * 0.5 +
|
Vector3 a0 = (neighbors[j] - node) * 0.5 +
|
||||||
node + n1 * 3.0f;
|
node + n1 * 3.0f;
|
||||||
Vector3 a1 = node + n1 * road_side_width;
|
Vector3 a1 = node + n1 * road_side_width;
|
||||||
Vector3 b0 = node + n2 * road_side_width;
|
Vector3 b0 = node + n2 * road_side_width;
|
||||||
Vector3 b1 = (neighbors[onext] - node) * 0.5 +
|
Vector3 b1 = (neighbors[onext] - node) * 0.5 +
|
||||||
node + n2 * 3.0f;
|
node + n2 * 3.0f;
|
||||||
Vector3 q, r;
|
Vector3 q, r, pr;
|
||||||
Geometry::get_closest_points_between_segments(
|
if (angle < 0 || angle > Math_PI) {
|
||||||
a0, a1, b0, b1, q, r);
|
Vector3 da = (a1 - a0).normalized() *
|
||||||
Vector3 pr;
|
road_side_width * 2.0f;
|
||||||
if (Vector2(q.x, q.z).distance_squared_to(
|
Vector3 db = (b1 - b0).normalized() *
|
||||||
Vector2(r.x, r.z)) < 0.001f)
|
road_side_width * 2.0f;
|
||||||
pr = q.linear_interpolate(r, 0.5f);
|
Geometry::get_closest_points_between_segments(
|
||||||
else
|
a0 - da, a1 + da, b0 - db,
|
||||||
pr = node + n1 * road_side_width;
|
b1 + db, q, r);
|
||||||
|
if (Vector2(q.x, q.z)
|
||||||
|
.distance_squared_to(
|
||||||
|
Vector2(r.x, r.z)) <
|
||||||
|
0.005f)
|
||||||
|
pr = q.linear_interpolate(r,
|
||||||
|
0.5f);
|
||||||
|
else {
|
||||||
|
print_line(
|
||||||
|
"bad luck: " +
|
||||||
|
(q.operator String()) +
|
||||||
|
" -> " +
|
||||||
|
(r.operator String()));
|
||||||
|
float e =
|
||||||
|
Vector2(q.x, q.z).distance_squared_to(
|
||||||
|
Vector2(r.x,
|
||||||
|
r.z));
|
||||||
|
print_line("dst " +
|
||||||
|
String::num(e));
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
/* pr = node +
|
||||||
|
n1 * road_side_width; */
|
||||||
|
} else {
|
||||||
|
Geometry::get_closest_points_between_segments(
|
||||||
|
a0, a1, b0, b1, q, r);
|
||||||
|
if (Vector2(q.x, q.z)
|
||||||
|
.distance_squared_to(
|
||||||
|
Vector2(r.x, r.z)) <
|
||||||
|
0.001f)
|
||||||
|
pr = q.linear_interpolate(r,
|
||||||
|
0.5f);
|
||||||
|
else
|
||||||
|
pr = node +
|
||||||
|
n1 * road_side_width;
|
||||||
|
}
|
||||||
Vector3 o1 = (neighbors[j] - node) * 0.5 + node;
|
Vector3 o1 = (neighbors[j] - node) * 0.5 + node;
|
||||||
Vector3 o2 = node,
|
Vector3 o2 = node,
|
||||||
o3 = (neighbors[onext] - node) * 0.5 +
|
o3 = (neighbors[onext] - node) * 0.5 +
|
||||||
@@ -542,6 +579,11 @@ public:
|
|||||||
this->center = center;
|
this->center = center;
|
||||||
this->mid = mid;
|
this->mid = mid;
|
||||||
this->edge = edge;
|
this->edge = edge;
|
||||||
|
if (!(l2 >= l1 - 0.0001f && l2 >= l3 - 0.0001f))
|
||||||
|
print_line("bad parameters: l1 = " +
|
||||||
|
String::num(l1) +
|
||||||
|
" l2 = " + String::num(l2) +
|
||||||
|
" l3 = " + String::num(l3));
|
||||||
assert(l2 >= l1 - 0.0001f && l2 >= l3 - 0.0001f);
|
assert(l2 >= l1 - 0.0001f && l2 >= l3 - 0.0001f);
|
||||||
assert(l1 - 3.0f < 0.001f);
|
assert(l1 - 3.0f < 0.001f);
|
||||||
assert(l3 - 3.0f < 0.001f);
|
assert(l3 - 3.0f < 0.001f);
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
#ifndef SIGNAL_HANDLER_H_
|
#ifndef SIGNAL_HANDLER_H_
|
||||||
#define SIGNAL_HANDLER_H_
|
#define SIGNAL_HANDLER_H_
|
||||||
#include <core/object.h>
|
#include <core/object.h>
|
||||||
|
#include <scene/gui/option_button.h>
|
||||||
|
#include <scene/gui/button.h>
|
||||||
|
#include <scene/gui/line_edit.h>
|
||||||
|
#include <scene/gui/check_box.h>
|
||||||
#include "editor_event.h"
|
#include "editor_event.h"
|
||||||
|
|
||||||
#define _GODOT_HANDLER_METHOD(class_name, obj_name, sig_name, event_name, \
|
#define _GODOT_HANDLER_METHOD(class_name, obj_name, sig_name, event_name, \
|
||||||
@@ -86,8 +90,6 @@
|
|||||||
obj_name, sig_name, hdecl, hargs, hbind) \
|
obj_name, sig_name, hdecl, hargs, hbind) \
|
||||||
typedef _GODOT_HANDLER_CONCAT2(class_name, __LINE__) class_name;
|
typedef _GODOT_HANDLER_CONCAT2(class_name, __LINE__) class_name;
|
||||||
|
|
||||||
//GODOT_HANDLER_METHOD(BrushSelectHandler, OptionButton, item_selected,
|
|
||||||
// brush_select, (int id), (id), D_METHOD("handler", "id"))
|
|
||||||
GODOT_HANDLER_EVENT_METHOD(OptionButtonHandler, OptionButton, item_selected,
|
GODOT_HANDLER_EVENT_METHOD(OptionButtonHandler, OptionButton, item_selected,
|
||||||
(int id), (id), D_METHOD("handler", "id"))
|
(int id), (id), D_METHOD("handler", "id"))
|
||||||
GODOT_HANDLER_EVENT_METHOD(ButtonPressHandler, Button, pressed, (), (),
|
GODOT_HANDLER_EVENT_METHOD(ButtonPressHandler, Button, pressed, (), (),
|
||||||
@@ -95,5 +97,9 @@ GODOT_HANDLER_EVENT_METHOD(ButtonPressHandler, Button, pressed, (), (),
|
|||||||
GODOT_HANDLER_EVENT_METHOD(LineEditString, LineEdit, text_changed,
|
GODOT_HANDLER_EVENT_METHOD(LineEditString, LineEdit, text_changed,
|
||||||
(const String &text), (text),
|
(const String &text), (text),
|
||||||
D_METHOD("handler", "text"))
|
D_METHOD("handler", "text"))
|
||||||
|
GODOT_HANDLER_EVENT_METHOD(CheckBoxPressHandler, CheckBox, pressed, (), (),
|
||||||
|
D_METHOD("handler"))
|
||||||
|
GODOT_HANDLER_EVENT_METHOD(PopupMenuSelectHandler, PopupMenu, id_pressed,
|
||||||
|
(int id), (id), D_METHOD("handler", "id"))
|
||||||
|
|
||||||
#endif // SIGNAL_HANDLER_H_
|
#endif // SIGNAL_HANDLER_H_
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "editor_event.h"
|
#include "editor_event.h"
|
||||||
#include "world_editor.h"
|
#include "world_editor.h"
|
||||||
|
#include "buildings_data.h"
|
||||||
#include "signal_handler.h"
|
#include "signal_handler.h"
|
||||||
#include "terrain_editor.h"
|
#include "terrain_editor.h"
|
||||||
|
|
||||||
@@ -73,21 +74,15 @@ TerrainEditor::~TerrainEditor()
|
|||||||
|
|
||||||
void TerrainEditor::activate()
|
void TerrainEditor::activate()
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
EditorEvent::get_singleton()->event.add_listener(
|
EditorEvent::get_singleton()->event.add_listener(
|
||||||
this, &TerrainEditor::event_handler);
|
this, &TerrainEditor::event_handler);
|
||||||
|
|
||||||
assert(editor->is_inside_tree());
|
assert(editor->is_inside_tree());
|
||||||
imgmapper = editor->get_heightmap();
|
imgmapper = editor->get_heightmap();
|
||||||
assert(imgmapper.is_valid());
|
|
||||||
const std::map<int, String> &brush_names = imgmapper->get_brush_names();
|
|
||||||
assert(brush_names.size() > 0);
|
|
||||||
Dictionary brushes;
|
Dictionary brushes;
|
||||||
std::map<int, String>::const_iterator ib = brush_names.begin();
|
for (i = 0; i < 32; i++)
|
||||||
while (ib != brush_names.end()) {
|
brushes[i] = "Brush" + itos(i);
|
||||||
std::pair<int, String> ibp = *ib;
|
|
||||||
brushes[ibp.first] = ibp.second;
|
|
||||||
ib++;
|
|
||||||
}
|
|
||||||
assert(brushes.size() > 0);
|
assert(brushes.size() > 0);
|
||||||
EditorEvent::get_singleton()->event.emit("terrain_load_data",
|
EditorEvent::get_singleton()->event.emit("terrain_load_data",
|
||||||
varray(brushes));
|
varray(brushes));
|
||||||
@@ -106,19 +101,28 @@ void TerrainEditor::deactivate()
|
|||||||
void TerrainEditor::event_handler(const String &event,
|
void TerrainEditor::event_handler(const String &event,
|
||||||
const Vector<Variant> &args)
|
const Vector<Variant> &args)
|
||||||
{
|
{
|
||||||
|
static Vector3 last_cursor_position;
|
||||||
print_line("TerrainEditor::event: " + event);
|
print_line("TerrainEditor::event: " + event);
|
||||||
if (event == "mouse_press" || event == "mouse_drag") {
|
if (event == "mouse_press" || event == "mouse_drag") {
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
if (cursor_enabled) {
|
if (cursor_enabled) {
|
||||||
if (event == "mouse_press")
|
if (event == "mouse_press") {
|
||||||
pressure += 0.4f;
|
if (last_cursor_position.is_equal_approx(
|
||||||
else if (event == "mouse_drag")
|
get_cursor_position()))
|
||||||
pressure += 0.01f;
|
pressure += 0.6f;
|
||||||
|
} else if (event == "mouse_drag")
|
||||||
|
pressure += 0.1f;
|
||||||
if (pressure > 1.0f)
|
if (pressure > 1.0f)
|
||||||
pressure = 1.0f;
|
pressure = 1.0f;
|
||||||
if (pressure >= 0.8f) {
|
if (pressure >= 0.8f) {
|
||||||
imgmapper->draw_brush(get_cursor_position(),
|
assert(imgmapper.is_valid());
|
||||||
1.0f, 100.0f,
|
imgmapper->draw_brush(
|
||||||
current_brush);
|
get_cursor_position(),
|
||||||
|
brush_curves[current_brush],
|
||||||
|
brush_radius[current_brush],
|
||||||
|
brush_strength[current_brush],
|
||||||
|
brush_flags[current_brush]);
|
||||||
imgmapper->compose();
|
imgmapper->compose();
|
||||||
EditorEvent::get_singleton()->event.emit(
|
EditorEvent::get_singleton()->event.emit(
|
||||||
"terrain_update", varray());
|
"terrain_update", varray());
|
||||||
@@ -126,6 +130,7 @@ void TerrainEditor::event_handler(const String &event,
|
|||||||
varray());
|
varray());
|
||||||
imgmapper->save_png();
|
imgmapper->save_png();
|
||||||
}
|
}
|
||||||
|
last_cursor_position = get_cursor_position();
|
||||||
flecs::log::dbg("pressure: %f", pressure);
|
flecs::log::dbg("pressure: %f", pressure);
|
||||||
/* Raycasting outside physics process */
|
/* Raycasting outside physics process */
|
||||||
Vector2 position = args[0];
|
Vector2 position = args[0];
|
||||||
@@ -234,6 +239,8 @@ end:;
|
|||||||
strength_edit);
|
strength_edit);
|
||||||
ob->get_parent()->set_meta("brush_strength",
|
ob->get_parent()->set_meta("brush_strength",
|
||||||
strength_edit);
|
strength_edit);
|
||||||
|
memnew(LineEditString(strength_edit,
|
||||||
|
"terrain_brush_strength_change"));
|
||||||
} else {
|
} else {
|
||||||
LineEdit *strength_edit = Object::cast_to<LineEdit>(
|
LineEdit *strength_edit = Object::cast_to<LineEdit>(
|
||||||
ob->get_parent()->get_meta("brush_strength"));
|
ob->get_parent()->get_meta("brush_strength"));
|
||||||
@@ -243,10 +250,12 @@ end:;
|
|||||||
struct flag_info {
|
struct flag_info {
|
||||||
String caption;
|
String caption;
|
||||||
};
|
};
|
||||||
struct flag_info flag_data[] = {
|
struct flag_info flag_data[] = { { "Absolute + Offset" },
|
||||||
{ "Absolute" },
|
{ "Absolute" },
|
||||||
{ "Random" },
|
{ "Random" },
|
||||||
};
|
{ "Flatten" },
|
||||||
|
{ "Smooth" },
|
||||||
|
{ "No Increments" } };
|
||||||
if (!ob->get_parent()->has_meta("brush_flags")) {
|
if (!ob->get_parent()->has_meta("brush_flags")) {
|
||||||
VBoxContainer *flags_ui = memnew(VBoxContainer);
|
VBoxContainer *flags_ui = memnew(VBoxContainer);
|
||||||
int flags = brush_flags[id];
|
int flags = brush_flags[id];
|
||||||
@@ -259,6 +268,8 @@ end:;
|
|||||||
cb->set_text(flag_data[f_idx].caption);
|
cb->set_text(flag_data[f_idx].caption);
|
||||||
cb->set_pressed_no_signal(flags & (1 << f_idx));
|
cb->set_pressed_no_signal(flags & (1 << f_idx));
|
||||||
flags_ui->add_child(cb);
|
flags_ui->add_child(cb);
|
||||||
|
memnew(CheckBoxPressHandler(
|
||||||
|
cb, "terrain_brush_flags_change"));
|
||||||
}
|
}
|
||||||
ob->get_parent()->call_deferred("add_child", flags_ui);
|
ob->get_parent()->call_deferred("add_child", flags_ui);
|
||||||
ob->get_parent()->set_meta("brush_flags", flags_ui);
|
ob->get_parent()->set_meta("brush_flags", flags_ui);
|
||||||
@@ -300,7 +311,7 @@ end:;
|
|||||||
if ((data.is_valid_float() || data.is_valid_integer()) &&
|
if ((data.is_valid_float() || data.is_valid_integer()) &&
|
||||||
current_brush >= 0) {
|
current_brush >= 0) {
|
||||||
brush_radius[current_brush] =
|
brush_radius[current_brush] =
|
||||||
MAX(data.to_float(), 1.0f);
|
CLAMP(data.to_float(), 1.0f, 500.0f);
|
||||||
print_line(data);
|
print_line(data);
|
||||||
MeshInstance *cursor_mesh =
|
MeshInstance *cursor_mesh =
|
||||||
get_as_node<MeshInstance>(cursor_name + "/mi2");
|
get_as_node<MeshInstance>(cursor_name + "/mi2");
|
||||||
@@ -313,6 +324,161 @@ end:;
|
|||||||
brush_radius[current_brush] + 3.0f);
|
brush_radius[current_brush] + 3.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (event == "terrain_brush_strength_change") {
|
||||||
|
String data = args[1];
|
||||||
|
data = data.strip_edges();
|
||||||
|
if ((data.is_valid_float() || data.is_valid_integer()) &&
|
||||||
|
current_brush >= 0) {
|
||||||
|
brush_strength[current_brush] =
|
||||||
|
CLAMP(data.to_float(), 0.0f, 100.0f);
|
||||||
|
print_line(data);
|
||||||
|
}
|
||||||
|
} else if (event == "terrain_brush_flags_change") {
|
||||||
|
CheckBox *cb_ = Object::cast_to<CheckBox>(args[0]);
|
||||||
|
assert(cb_);
|
||||||
|
int i;
|
||||||
|
int flags = 0;
|
||||||
|
for (i = 0; i < cb_->get_parent()->get_child_count(); i++) {
|
||||||
|
CheckBox *c = Object::cast_to<CheckBox>(
|
||||||
|
cb_->get_parent()->get_child(i));
|
||||||
|
assert(c);
|
||||||
|
if (c->is_pressed())
|
||||||
|
flags |= (1 << i);
|
||||||
|
}
|
||||||
|
brush_flags[current_brush] = flags;
|
||||||
|
} else if (event == "terrain_menu") {
|
||||||
|
PopupMenu *menu = Object::cast_to<PopupMenu>(args[0]);
|
||||||
|
int id = args[1];
|
||||||
|
print_line("terrain_menu: " + itos(id));
|
||||||
|
switch (id) {
|
||||||
|
case 2000:
|
||||||
|
save_data();
|
||||||
|
break;
|
||||||
|
case 2001: {
|
||||||
|
List<String> building_keys;
|
||||||
|
List<String>::Element *e;
|
||||||
|
BuildingsData::get_singleton()->get_building_keys_list(
|
||||||
|
&building_keys);
|
||||||
|
BuildingsData::get_singleton()->build_building_aabbs();
|
||||||
|
e = building_keys.front();
|
||||||
|
while (e) {
|
||||||
|
const String &key = e->get();
|
||||||
|
const BuildingsData::building &b =
|
||||||
|
BuildingsData::get_singleton()
|
||||||
|
->get_building(key);
|
||||||
|
float i, j;
|
||||||
|
print_line("building type: " + b.id);
|
||||||
|
print_line("building key: " + b.key);
|
||||||
|
print_line("building position: " +
|
||||||
|
(b.xform.origin.operator String()));
|
||||||
|
print_line(
|
||||||
|
"building elevation: " +
|
||||||
|
String::num(imgmapper->get_height_full(
|
||||||
|
b.xform.origin)));
|
||||||
|
AABB aabb = BuildingsData::get_singleton()
|
||||||
|
->building_aabbs[b.id];
|
||||||
|
print_line("building AABB: " +
|
||||||
|
(aabb.operator String()));
|
||||||
|
float max_elevation_c = -Math_INF,
|
||||||
|
min_elevation_c = Math_INF;
|
||||||
|
float extension = 0.0f;
|
||||||
|
if (aabb.size.x >= 10.0f ||
|
||||||
|
aabb.size.z >= 10.0f)
|
||||||
|
extension = 5.0f;
|
||||||
|
for (i = aabb.position.z - extension;
|
||||||
|
i <
|
||||||
|
aabb.position.z + aabb.size.z + extension;
|
||||||
|
i += 1.0f)
|
||||||
|
for (j = aabb.position.x - extension;
|
||||||
|
j < aabb.position.x + aabb.size.x +
|
||||||
|
extension;
|
||||||
|
j += 1.0f) {
|
||||||
|
Vector3 v = b.xform.xform(
|
||||||
|
Vector3(j, 0, i));
|
||||||
|
float h = imgmapper->get_world_pixel(
|
||||||
|
v.x + imgmapper->get_world_size() /
|
||||||
|
2,
|
||||||
|
v.z + imgmapper->get_world_size() /
|
||||||
|
2);
|
||||||
|
if (max_elevation_c < h)
|
||||||
|
max_elevation_c = h;
|
||||||
|
if (min_elevation_c > h)
|
||||||
|
min_elevation_c = h;
|
||||||
|
}
|
||||||
|
float max_elevation = Math::stepify(
|
||||||
|
max_elevation_c * 200.0f - 100.0f,
|
||||||
|
0.25f);
|
||||||
|
print_line("building max_elevation: " +
|
||||||
|
String::num(max_elevation));
|
||||||
|
for (i = aabb.position.z - extension;
|
||||||
|
i <
|
||||||
|
aabb.position.z + aabb.size.z + extension;
|
||||||
|
i += 0.5f) {
|
||||||
|
float mx = 0.0f;
|
||||||
|
for (j = aabb.position.x - extension;
|
||||||
|
j < aabb.position.x + aabb.size.x +
|
||||||
|
extension;
|
||||||
|
j += 0.5f) {
|
||||||
|
float current_c;
|
||||||
|
Vector3 v = b.xform.xform(
|
||||||
|
Vector3(j, 0, i));
|
||||||
|
float h = imgmapper->get_world_pixel(
|
||||||
|
v.x + imgmapper->get_world_size() /
|
||||||
|
2,
|
||||||
|
v.z + imgmapper->get_world_size() /
|
||||||
|
2);
|
||||||
|
float result_c =
|
||||||
|
max_elevation_c;
|
||||||
|
imgmapper->set_world_pixel(
|
||||||
|
v.x + imgmapper->get_world_size() /
|
||||||
|
2,
|
||||||
|
v.z + imgmapper->get_world_size() /
|
||||||
|
2,
|
||||||
|
result_c);
|
||||||
|
mx += 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
float max_elevation2 =
|
||||||
|
imgmapper->get_world_pixel(
|
||||||
|
b.xform.origin.x +
|
||||||
|
imgmapper->get_world_size() /
|
||||||
|
2,
|
||||||
|
b.xform.origin.z +
|
||||||
|
imgmapper->get_world_size() /
|
||||||
|
2) *
|
||||||
|
200.0f -
|
||||||
|
100.0f;
|
||||||
|
print_line(
|
||||||
|
"building max_elevation2: " +
|
||||||
|
String::num(max_elevation2) + " -> " +
|
||||||
|
String::num(max_elevation_c * 200.0f -
|
||||||
|
100.0f));
|
||||||
|
// assert(Math::abs(max_elevation2 -
|
||||||
|
// max_elevation) < 1.0f);
|
||||||
|
#endif
|
||||||
|
Transform xform = BuildingsData::get_singleton()
|
||||||
|
->get_building(key)
|
||||||
|
.xform;
|
||||||
|
xform.origin.y = max_elevation * 1.4998f - 0.5f;
|
||||||
|
editor->editor_command(
|
||||||
|
"update_building_transform",
|
||||||
|
varray(key, xform));
|
||||||
|
#if 0
|
||||||
|
assert(Math::abs(BuildingsData::get_singleton()
|
||||||
|
->get_building(key)
|
||||||
|
.xform.origin.y -
|
||||||
|
max_elevation * 1.4f) < 1.0f);
|
||||||
|
#endif
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
imgmapper->save_dirty_tiles();
|
||||||
|
BuildingsData::get_singleton()->save_buildings();
|
||||||
|
editor->editor_command("nudge_generator", varray());
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,25 +202,40 @@ void MainTabs::_notification(int which)
|
|||||||
/* 1 */
|
/* 1 */
|
||||||
"Brush", 0, "terrain_select_brush",
|
"Brush", 0, "terrain_select_brush",
|
||||||
/* 2 */
|
/* 2 */
|
||||||
"Save brush data", "save_brush_data",
|
"Terrain", 4,
|
||||||
|
2000, "Save brush data", false,
|
||||||
|
-1, "", false,
|
||||||
|
2001, "Fixup Buildingss", false,
|
||||||
|
2002, "Fixup Roads", false,
|
||||||
|
"terrain_menu",
|
||||||
};
|
};
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
HashMap<String, Object *> save_data;
|
HashMap<String, Object *> save_data;
|
||||||
ui_field::ui_field_builder(this, tab,
|
ui_field::ui_field_builder(this, tab,
|
||||||
"l_p{v{lo#!$b#!$}}",
|
"l_p{v{lo#!$m#!$}}",
|
||||||
args_data.data(),
|
args_data.data(),
|
||||||
args_data.size(),
|
args_data.size(),
|
||||||
&save_data);
|
&save_data);
|
||||||
assert(save_data.has("terrain_select_brush"));
|
assert(save_data.has("terrain_select_brush"));
|
||||||
assert(save_data.has("save_brush_data"));
|
assert(save_data.has("terrain_menu"));
|
||||||
OptionButton *ob = Object::cast_to<OptionButton>(
|
OptionButton *ob = Object::cast_to<OptionButton>(
|
||||||
save_data["terrain_select_brush"]);
|
save_data["terrain_select_brush"]);
|
||||||
memnew(OptionButtonHandler(
|
memnew(OptionButtonHandler(
|
||||||
ob, "terrain_brush_select"));
|
ob, "terrain_brush_select"));
|
||||||
Button *b = Object::cast_to<Button>(
|
MenuButton *mb = Object::cast_to<MenuButton>(
|
||||||
save_data["save_brush_data"]);
|
save_data["terrain_menu"]);
|
||||||
memnew(ButtonPressHandler(b,
|
memnew(PopupMenuSelectHandler(mb->get_popup(),
|
||||||
"terrain_save_data"));
|
"terrain_menu"));
|
||||||
|
/*
|
||||||
|
Button *b2 = Object::cast_to<Button>(
|
||||||
|
save_data["fixup_buildings"]);
|
||||||
|
memnew(ButtonPressHandler(
|
||||||
|
b2, "terrain_fixup_buildings"));
|
||||||
|
Button *b3 = Object::cast_to<Button>(
|
||||||
|
save_data["fixup_roads"]);
|
||||||
|
memnew(ButtonPressHandler(
|
||||||
|
b3, "terrain_fixup_roads"));
|
||||||
|
*/
|
||||||
} break;
|
} break;
|
||||||
case 1: {
|
case 1: {
|
||||||
// VBoxContainer *v = memnew(VBoxContainer);
|
// VBoxContainer *v = memnew(VBoxContainer);
|
||||||
|
|||||||
Reference in New Issue
Block a user