Updated systems handling
This commit is contained in:
2
Makefile
2
Makefile
@@ -15,7 +15,7 @@ godot-main: patch
|
||||
scons platform=server target=release_debug tools=yes custom_modules=../modules -j16
|
||||
godot-editor-main: patch
|
||||
cd src/godot; \
|
||||
scons platform=x11 arch=$(ARCH) target=release_debug tools=yes custom_modules=../modules -j16;
|
||||
scons platform=x11 arch=$(ARCH) verbose=yes target=release_debug tools=yes custom_modules=../modules -j16;
|
||||
patch: ./src/godot/scene/animation/skeleton_ik.cpp
|
||||
cd ./src/godot && git reset --hard HEAD && for p in ../patches/*.patch; do git apply $$p; done
|
||||
sed -e 's/ERR_FAIL_COND_V(-1 == p_task->root_bone, false);//g' -i ./src/godot/scene/animation/skeleton_ik.cpp
|
||||
|
||||
@@ -225,7 +225,7 @@ for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBab
|
||||
obj.name = obj.name + "-noimp"
|
||||
bpy.ops.wm.save_as_mainfile(filepath=(basepath + "/assets/blender/scripts/" + mapping.outfile))
|
||||
|
||||
bpy.ops.export_scene.gltf(filepath=mapping.gltf_path.replace(".npc", ".gltf"),
|
||||
bpy.ops.export_scene.gltf(filepath=mapping.gltf_path.replace(".npcshape", ".gltf").replace(".npc", ".gltf"),
|
||||
use_selection=False,
|
||||
check_existing=False,
|
||||
export_format='GLTF_SEPARATE',
|
||||
@@ -252,8 +252,8 @@ for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBab
|
||||
export_morph_normal=True,
|
||||
export_morph_tangent=True,
|
||||
export_lights=False,
|
||||
export_skins=False)
|
||||
shutil.move(mapping.gltf_path.replace(".npc", ".gltf"), mapping.gltf_path)
|
||||
export_skins=True)
|
||||
shutil.move(mapping.gltf_path.replace(".npcshape", ".gltf").replace(".npc", ".gltf"), mapping.gltf_path)
|
||||
|
||||
|
||||
bpy.ops.wm.read_homefile(use_empty=True)
|
||||
|
||||
@@ -17,6 +17,7 @@ if bpy.app.version[0] == 3:
|
||||
from mixamo import mixamo_rig
|
||||
from mixamo.lib.armature import *
|
||||
from settings import VRMDataFemale, VRMDataMale, VRMDataMaleBabyShape, basepath
|
||||
from geometry import tris2quads
|
||||
|
||||
imports = [VRMDataFemale(), VRMDataMale(), VRMDataMaleBabyShape()]
|
||||
|
||||
@@ -81,6 +82,9 @@ for imp in imports:
|
||||
result = bpy.ops.import_scene.vrm(filepath=(basepath + "/assets/vroid/" + imp.path))
|
||||
if result != {"FINISHED"}:
|
||||
raise Exception(f"Failed to import vrm: {result}")
|
||||
for o in bpy.data.objects:
|
||||
if o.type == 'MESH':
|
||||
tris2quads.tris2quads(o)
|
||||
armature_count = 0
|
||||
for obj in bpy.data.objects:
|
||||
if (obj.type == "ARMATURE"):
|
||||
|
||||
@@ -53,7 +53,7 @@ class ExportMappingMale:
|
||||
|
||||
class ExportMappingMaleBabyShape:
|
||||
blend_path = "assets/blender/shapes/male/" + "vrm-vroid-normal-male-chibi.blend"
|
||||
gltf_path = "godot/character-data/vroid-normal-male-chibi.npc"
|
||||
gltf_path = "godot/character-data/vroid-normal-male-chibi.npcshape"
|
||||
inner_path = "Object"
|
||||
objs = ["male", "Body", "Hair", "Face"]
|
||||
armature_name = "male"
|
||||
|
||||
@@ -133,166 +133,6 @@ margin_top = 8.0
|
||||
margin_right = 248.0
|
||||
margin_bottom = 316.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_base"]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 241.0
|
||||
margin_bottom = 301.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
margin_top = 50.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 74.0
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/HBoxContainer"]
|
||||
margin_top = 5.0
|
||||
margin_right = 41.0
|
||||
margin_bottom = 19.0
|
||||
text = "Filter: "
|
||||
|
||||
[node name="road_lines_filter" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 45.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="lines_list" type="ItemList" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 78.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 158.0
|
||||
rect_min_size = Vector2( 0, 80 )
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="line_index" type="SpinBox" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 162.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 186.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
margin_top = 190.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 194.0
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
margin_top = 198.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 212.0
|
||||
text = "Cursor position"
|
||||
|
||||
[node name="road_lines_cursor_position" type="VBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 216.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 240.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_cursor_position"]
|
||||
margin_right = 234.0
|
||||
margin_bottom = 24.0
|
||||
|
||||
[node name="cursor_x" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_cursor_position/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_right = 63.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="cursor_y" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_cursor_position/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 67.0
|
||||
margin_right = 130.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="cursor_z" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_cursor_position/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 134.0
|
||||
margin_right = 197.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="road_lines_set_cursor_position" type="Button" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_cursor_position/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 201.0
|
||||
margin_right = 233.0
|
||||
margin_bottom = 24.0
|
||||
text = "Set"
|
||||
|
||||
[node name="HSeparator4" type="HSeparator" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
margin_top = 244.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 248.0
|
||||
|
||||
[node name="Label3" type="Label" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
margin_top = 252.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 266.0
|
||||
text = "Point position"
|
||||
|
||||
[node name="road_lines_point_position" type="VBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 270.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 294.0
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_point_position"]
|
||||
margin_right = 234.0
|
||||
margin_bottom = 24.0
|
||||
|
||||
[node name="point_x" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_point_position/HBoxContainer2"]
|
||||
unique_name_in_owner = true
|
||||
margin_right = 63.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="point_y" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_point_position/HBoxContainer2"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 67.0
|
||||
margin_right = 130.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="point_z" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_point_position/HBoxContainer2"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 134.0
|
||||
margin_right = 197.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="road_lines_set_point_position" type="Button" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_point_position/HBoxContainer2"]
|
||||
unique_name_in_owner = true
|
||||
margin_left = 201.0
|
||||
margin_right = 233.0
|
||||
margin_bottom = 24.0
|
||||
text = "Set"
|
||||
|
||||
[node name="road_lines_create_new_line_dlg" type="PanelContainer" parent="VBoxContainer/v_road_lines"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 320.0
|
||||
margin_right = 248.0
|
||||
margin_bottom = 382.0
|
||||
|
||||
[node name="v" type="VBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_create_new_line_dlg"]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 241.0
|
||||
margin_bottom = 55.0
|
||||
|
||||
[node name="road_lines_create_new_line_name" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_create_new_line_dlg/v"]
|
||||
unique_name_in_owner = true
|
||||
margin_right = 234.0
|
||||
margin_bottom = 24.0
|
||||
|
||||
[node name="road_lines_create_new_cancel" type="Button" parent="VBoxContainer/v_road_lines/road_lines_create_new_line_dlg/v"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 28.0
|
||||
margin_right = 234.0
|
||||
margin_bottom = 48.0
|
||||
text = "Cancel"
|
||||
|
||||
[node name="road_lines_edit_metadata_dlg" type="PanelContainer" parent="VBoxContainer/v_road_lines"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 386.0
|
||||
|
||||
@@ -5,17 +5,19 @@ Import("env_modules")
|
||||
|
||||
# Godot source files
|
||||
|
||||
module_obj = []
|
||||
env_stream = env_modules.Clone()
|
||||
env_stream.module_obj = []
|
||||
env_stream.Prepend(CPPPATH=["../../meshoptimizer/src"])
|
||||
env_stream.Prepend(CPPPATH=["event"])
|
||||
env_stream.add_source_files(env_stream.module_obj, "*.cpp")
|
||||
env_stream.add_source_files(env_stream.module_obj, "flecs/*.c")
|
||||
env.modules_sources += env_stream.module_obj
|
||||
|
||||
SConscript("buildings/SCsub")
|
||||
SConscript("rtree/SCsub")
|
||||
SConscript("ui/SCsub")
|
||||
SConscript("npc/SCsub")
|
||||
SConscript("event/SCsub")
|
||||
|
||||
env_stream = env_modules.Clone()
|
||||
|
||||
env_stream.Prepend(CPPPATH=["../../meshoptimizer/src"])
|
||||
env_stream.add_source_files(module_obj, "*.cpp")
|
||||
env_stream.add_source_files(module_obj, "flecs/*.c")
|
||||
env.modules_sources += module_obj
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
|
||||
#include "editor_event.h"
|
||||
|
||||
EditorEvent *EditorEvent::singleton = nullptr;
|
||||
|
||||
EditorEvent::EditorEvent()
|
||||
{
|
||||
}
|
||||
|
||||
EditorEvent::~EditorEvent()
|
||||
{
|
||||
}
|
||||
|
||||
EditorEvent *EditorEvent::get_singleton()
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = memnew(EditorEvent);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void EditorEvent::EventHelper::emit(const String &event,
|
||||
const Vector<Variant> &args)
|
||||
{
|
||||
auto evl = listeners.begin();
|
||||
while (evl != listeners.end()) {
|
||||
const event_listener_ptrs &xev = *evl;
|
||||
xev.execute(event, args);
|
||||
evl++;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
#ifndef EDITOR_EVENT_H
|
||||
#define EDITOR_EVENT_H
|
||||
#include <core/ustring.h>
|
||||
#include <list>
|
||||
class EditorEvent {
|
||||
public:
|
||||
class EventHelper {
|
||||
class event_listener_ptrs {
|
||||
public:
|
||||
class H {};
|
||||
H *obj;
|
||||
void (H::*method)(const String &event,
|
||||
const Vector<Variant> &args);
|
||||
void execute(const String &event,
|
||||
const Vector<Variant> &args) const
|
||||
{
|
||||
(obj->*method)(event, args);
|
||||
}
|
||||
};
|
||||
std::list<event_listener_ptrs> listeners;
|
||||
typedef event_listener_ptrs::H *obj_t;
|
||||
typedef void (event_listener_ptrs::H::*method_t)(
|
||||
const String &event, const Vector<Variant> &args);
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
void
|
||||
add_listener(T *obj,
|
||||
void (T::*method)(const String &event,
|
||||
const Vector<Variant> &args));
|
||||
template <class T>
|
||||
void
|
||||
remove_listener(T *obj,
|
||||
void (T::*method)(const String &event,
|
||||
const Vector<Variant> &args));
|
||||
void emit(const String &event, const Vector<Variant> &args);
|
||||
};
|
||||
EventHelper event;
|
||||
|
||||
private:
|
||||
static EditorEvent *singleton;
|
||||
EditorEvent();
|
||||
virtual ~EditorEvent();
|
||||
|
||||
public:
|
||||
static EditorEvent *get_singleton();
|
||||
};
|
||||
template <class T>
|
||||
void EditorEvent::EventHelper::remove_listener(
|
||||
T *obj,
|
||||
void (T::*method)(const String &event, const Vector<Variant> &args))
|
||||
{
|
||||
listeners.remove_if([obj, method](const event_listener_ptrs &e) {
|
||||
return e.obj == reinterpret_cast<obj_t>(obj) &&
|
||||
e.method == reinterpret_cast<method_t>(method);
|
||||
});
|
||||
}
|
||||
template <class T>
|
||||
void EditorEvent::EventHelper::add_listener(
|
||||
T *obj,
|
||||
void (T::*method)(const String &event, const Vector<Variant> &args))
|
||||
{
|
||||
auto evl = listeners.begin();
|
||||
bool bad = false;
|
||||
while (evl != listeners.end()) {
|
||||
const event_listener_ptrs &xev = *evl;
|
||||
if (xev.obj == reinterpret_cast<obj_t>(obj) &&
|
||||
xev.method == reinterpret_cast<method_t>(method)) {
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
evl++;
|
||||
}
|
||||
if (bad)
|
||||
return;
|
||||
event_listener_ptrs ev;
|
||||
ev.obj = reinterpret_cast<obj_t>(obj);
|
||||
ev.method = reinterpret_cast<method_t>(method);
|
||||
listeners.push_back(ev);
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +1,14 @@
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env.stream_building_sources = []
|
||||
env_stream = env_modules.Clone()
|
||||
env_stream.stream_building_sources = []
|
||||
|
||||
env.add_source_files(env.stream_building_sources, "*.cpp")
|
||||
env_stream.add_source_files(env_stream.stream_building_sources, "*.cpp")
|
||||
|
||||
lib = env.add_library("npc", env.stream_building_sources)
|
||||
env.Prepend(LIBS=[lib])
|
||||
env.Prepend(CPPPATH=[".."])
|
||||
env.Prepend(CPPPATH=["../../../meshoptimizer/src"])
|
||||
lib = env_stream.add_library("npc", env_stream.stream_building_sources)
|
||||
env.Append(LIBS=[lib])
|
||||
env_stream.Prepend(CPPPATH=[".."])
|
||||
env_stream.Prepend(CPPPATH=["../../../meshoptimizer/src"])
|
||||
env_stream.Prepend(CPPPATH=["../event"])
|
||||
env_stream.Prepend(CPPPATH=["../persistent_data"])
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include <cassert>
|
||||
#include <modules/gltf/packed_scene_gltf.h>
|
||||
#include <core/io/config_file.h>
|
||||
#include <core/io/compression.h>
|
||||
#include <scene/resources/mesh_library.h>
|
||||
#include "skeleton_data.h"
|
||||
#include "importer.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
@@ -18,6 +21,7 @@ uint32_t EditorImportNPC::get_import_flags() const
|
||||
void EditorImportNPC::get_extensions(List<String> *r_extensions) const
|
||||
{
|
||||
r_extensions->push_back("npc");
|
||||
r_extensions->push_back("npcshape");
|
||||
}
|
||||
Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags,
|
||||
int p_bake_fps, uint32_t p_compress_flags,
|
||||
@@ -27,13 +31,26 @@ Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags,
|
||||
List<Node *> queue;
|
||||
Ref<PackedSceneGLTF> importer;
|
||||
ConfigFile config;
|
||||
String config_path =
|
||||
p_path.replace(".npc", ".conf")
|
||||
.replace("/character-data/", "/character/");
|
||||
Error err = config.load(config_path);
|
||||
print_line("config path: " + config_path);
|
||||
if (err == OK)
|
||||
print_line("config loaded...");
|
||||
String config_path;
|
||||
bool is_shape = false;
|
||||
if (p_path.ends_with(".npc")) {
|
||||
config_path =
|
||||
p_path.replace(".npc", ".conf")
|
||||
.replace("/character-data/", "/character/");
|
||||
Error err = config.load(config_path);
|
||||
print_line("config path: " + config_path);
|
||||
if (err == OK)
|
||||
print_line("config loaded...");
|
||||
} else if (p_path.ends_with(".npcshape")) {
|
||||
is_shape = true;
|
||||
config_path =
|
||||
p_path.replace(".npcshape", ".conf")
|
||||
.replace("/character-data/", "/character/");
|
||||
Error err = config.load(config_path);
|
||||
print_line("config path: " + config_path);
|
||||
if (err == OK)
|
||||
print_line("config loaded...");
|
||||
}
|
||||
importer.instance();
|
||||
result = importer->import_scene(p_path, p_flags, p_bake_fps,
|
||||
p_compress_flags, r_missing_deps, r_err,
|
||||
@@ -92,6 +109,8 @@ Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags,
|
||||
ArrayMesh::PrimitiveType ptype;
|
||||
Array surface, bshapes;
|
||||
String split_name = split[0];
|
||||
print_line("split_name: " +
|
||||
split_name);
|
||||
MeshInstance *split_mi;
|
||||
if (split_meshes.has(
|
||||
split_name))
|
||||
@@ -131,138 +150,155 @@ Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags,
|
||||
new_mesh->get_surface_count() -
|
||||
1,
|
||||
mat);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (mesh_name == "body") {
|
||||
if (mesh.is_valid()) {
|
||||
Ref<ArrayMesh> new_body,
|
||||
clothes;
|
||||
new_body.instance();
|
||||
new_body->set_storage_mode(
|
||||
ArrayMesh::
|
||||
STORAGE_MODE_CPU);
|
||||
int surf_count =
|
||||
mesh->get_surface_count();
|
||||
if (surf_count > 0) {
|
||||
MeshInstance *clothes_mi =
|
||||
memnew(MeshInstance);
|
||||
mi->get_parent()->add_child(
|
||||
clothes_mi);
|
||||
clothes_mi->set_owner(
|
||||
mi->get_owner());
|
||||
clothes.instance();
|
||||
clothes->set_storage_mode(
|
||||
print_line(
|
||||
"split mesh created");
|
||||
if (!is_shape &&
|
||||
config.has_section_key(
|
||||
surf_section,
|
||||
"shape_path")) {
|
||||
print_line("not shape");
|
||||
String shape_path =
|
||||
config.get_value(
|
||||
surf_section,
|
||||
"shape_path");
|
||||
if (shape_path.find(
|
||||
".meshlib") <
|
||||
0)
|
||||
shape_path +=
|
||||
".meshlib";
|
||||
Ref<ArrayMesh>
|
||||
shape_mesh;
|
||||
shape_mesh.instance();
|
||||
shape_mesh->set_storage_mode(
|
||||
ArrayMesh::
|
||||
STORAGE_MODE_CPU);
|
||||
clothes_mi->set_mesh(
|
||||
clothes);
|
||||
}
|
||||
for (i = 0; i < surf_count;
|
||||
i++) {
|
||||
uint32_t sformat =
|
||||
mesh->surface_get_format(
|
||||
i);
|
||||
ArrayMesh::PrimitiveType ptype =
|
||||
mesh->surface_get_primitive_type(
|
||||
i);
|
||||
Array surface =
|
||||
mesh->surface_get_arrays(
|
||||
i);
|
||||
Array bshapes =
|
||||
mesh->surface_get_blend_shape_arrays(
|
||||
i);
|
||||
|
||||
if (i == 0)
|
||||
new_body->add_surface_from_arrays(
|
||||
shape_mesh
|
||||
->add_surface_from_arrays(
|
||||
ptype,
|
||||
surface,
|
||||
bshapes);
|
||||
else
|
||||
clothes->add_surface_from_arrays(
|
||||
ptype,
|
||||
surface,
|
||||
bshapes);
|
||||
Ref<SpatialMaterial> mat =
|
||||
mesh->surface_get_material(
|
||||
i);
|
||||
if (i == 0)
|
||||
new_body->surface_set_material(
|
||||
i, mat);
|
||||
else
|
||||
clothes->surface_set_material(
|
||||
i - 1,
|
||||
mat);
|
||||
if (mat.is_valid()) {
|
||||
String pname =
|
||||
mat->get_name();
|
||||
assert(pname.size() >
|
||||
0);
|
||||
if (i == 0)
|
||||
new_body->surface_set_name(
|
||||
i,
|
||||
pname);
|
||||
else
|
||||
clothes->surface_set_name(
|
||||
i - 1,
|
||||
pname);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < surf_count;
|
||||
i++) {
|
||||
Ref<SpatialMaterial> mat =
|
||||
mesh->surface_get_material(
|
||||
i);
|
||||
if (mat.is_valid()) {
|
||||
mat->set_feature(
|
||||
SpatialMaterial::
|
||||
FEATURE_TRANSPARENT,
|
||||
false);
|
||||
if (i >= 2)
|
||||
mat->set_flag(
|
||||
SpatialMaterial::
|
||||
FLAG_USE_ALPHA_SCISSOR,
|
||||
true);
|
||||
else
|
||||
mat->set_flag(
|
||||
SpatialMaterial::
|
||||
FLAG_USE_ALPHA_SCISSOR,
|
||||
false);
|
||||
}
|
||||
}
|
||||
mi->set_mesh(new_body);
|
||||
new_body->set_storage_mode(
|
||||
ArrayMesh::
|
||||
STORAGE_MODE_GPU);
|
||||
if (clothes.is_valid())
|
||||
clothes->set_storage_mode(
|
||||
surface);
|
||||
shape_mesh->set_storage_mode(
|
||||
ArrayMesh::
|
||||
STORAGE_MODE_GPU);
|
||||
}
|
||||
}
|
||||
if (mesh_name == "hair") {
|
||||
if (mesh.is_valid()) {
|
||||
int surf_count =
|
||||
mesh->get_surface_count();
|
||||
for (i = 0; i < surf_count;
|
||||
i++) {
|
||||
Ref<SpatialMaterial> mat =
|
||||
mesh->surface_get_material(
|
||||
i);
|
||||
if (mat.is_valid()) {
|
||||
mat->set_feature(
|
||||
SpatialMaterial::
|
||||
FEATURE_TRANSPARENT,
|
||||
false);
|
||||
mat->set_flag(
|
||||
SpatialMaterial::
|
||||
FLAG_USE_ALPHA_SCISSOR,
|
||||
false);
|
||||
Ref<MeshLibrary> meshlib;
|
||||
String meshlib_path =
|
||||
shape_path;
|
||||
if (ResourceLoader::exists(
|
||||
meshlib_path,
|
||||
"MeshLibrary")) {
|
||||
meshlib = ResourceLoader::load(
|
||||
shape_path,
|
||||
"MeshLibrary",
|
||||
true);
|
||||
}
|
||||
if (!meshlib.is_valid())
|
||||
meshlib.instance();
|
||||
int item_id =
|
||||
meshlib->find_item_by_name(
|
||||
split_name);
|
||||
if (item_id < 0) {
|
||||
item_id =
|
||||
meshlib->get_last_unused_item_id();
|
||||
meshlib->create_item(
|
||||
item_id);
|
||||
meshlib->set_item_name(
|
||||
item_id,
|
||||
split_name);
|
||||
}
|
||||
meshlib->set_item_mesh(
|
||||
item_id,
|
||||
shape_mesh);
|
||||
ResourceSaver::save(
|
||||
shape_path,
|
||||
meshlib);
|
||||
#if 0
|
||||
if (shape_path.find(".bshape") < 0)
|
||||
shape_path += ".bshape";
|
||||
build_shape_base(
|
||||
surface,
|
||||
shape_path);
|
||||
#endif
|
||||
} else if (is_shape &&
|
||||
config.has_section_key(
|
||||
surf_section,
|
||||
"shape_path")) {
|
||||
print_line(
|
||||
"is a shape");
|
||||
String shape_path =
|
||||
config.get_value(
|
||||
surf_section,
|
||||
"shape_path");
|
||||
if (shape_path.find(
|
||||
".meshlib") <
|
||||
0)
|
||||
shape_path +=
|
||||
".meshlib";
|
||||
Ref<MeshLibrary> meshlib;
|
||||
String meshlib_path =
|
||||
shape_path;
|
||||
if (ResourceLoader::exists(
|
||||
meshlib_path,
|
||||
"MeshLibrary")) {
|
||||
meshlib = ResourceLoader::load(
|
||||
shape_path,
|
||||
"MeshLibrary",
|
||||
true);
|
||||
} else
|
||||
print_error(
|
||||
shape_path +
|
||||
"does not exist");
|
||||
if (meshlib.is_valid() &&
|
||||
config.has_section_key(
|
||||
surf_section,
|
||||
"base_mesh")) {
|
||||
String item_name =
|
||||
config.get_value(
|
||||
surf_section,
|
||||
"base_mesh");
|
||||
int item_id = meshlib->find_item_by_name(
|
||||
item_name);
|
||||
if (!config.has_section_key(
|
||||
surf_section,
|
||||
"shape"))
|
||||
goto out;
|
||||
if (item_id <
|
||||
0) {
|
||||
print_error(
|
||||
"Item not found: " +
|
||||
item_name);
|
||||
goto out;
|
||||
} else {
|
||||
Ref<ArrayMesh> base_mesh =
|
||||
meshlib->get_item_mesh(
|
||||
item_id);
|
||||
if (!base_mesh
|
||||
.is_valid()) {
|
||||
print_error(
|
||||
"Mesh is not valid");
|
||||
goto out;
|
||||
}
|
||||
Array base_surface =
|
||||
base_mesh
|
||||
->surface_get_arrays(
|
||||
0);
|
||||
String out_path = config.get_value(
|
||||
surf_section,
|
||||
"shape",
|
||||
String());
|
||||
if (out_path.find(
|
||||
".bshape") <
|
||||
0)
|
||||
out_path +=
|
||||
".bshape";
|
||||
build_shape_base(
|
||||
base_surface,
|
||||
surface,
|
||||
out_path);
|
||||
}
|
||||
}
|
||||
out:;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
List<String> mesh_keys;
|
||||
split_meshes.get_key_list(&mesh_keys);
|
||||
List<String>::Element *e = mesh_keys.front();
|
||||
@@ -274,6 +310,51 @@ Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags,
|
||||
}
|
||||
do_destroy =
|
||||
config.get_value(section, "destroy", false);
|
||||
} else {
|
||||
Skeleton *skeleton = Object::cast_to<Skeleton>(item);
|
||||
if (skeleton && !is_shape) {
|
||||
if (config.has_section_key("skeleton",
|
||||
"path")) {
|
||||
Ref<SkeletonData> skeleton_data;
|
||||
String skpath = config.get_value(
|
||||
"skeleton", "path", String());
|
||||
if (!skpath.ends_with(".res"))
|
||||
skpath += ".res";
|
||||
skeleton_data.instance();
|
||||
skeleton_data->save_skeleton(skeleton);
|
||||
ResourceSaver::save(skpath,
|
||||
skeleton_data);
|
||||
}
|
||||
} else if (skeleton && is_shape) {
|
||||
if (config.has_section_key("skeleton",
|
||||
"path") &&
|
||||
config.has_section_key("skeleton",
|
||||
"bone_delta")) {
|
||||
Ref<SkeletonData> skeleton_data;
|
||||
String skpath = config.get_value(
|
||||
"skeleton", "path", String());
|
||||
if (!skpath.ends_with(".res"))
|
||||
skpath += ".res";
|
||||
skeleton_data = ResourceLoader::load(
|
||||
skpath, "SkeletonData");
|
||||
String bone_delta_path =
|
||||
config.get_value("skeleton",
|
||||
"bone_delta",
|
||||
String());
|
||||
if (!bone_delta_path.ends_with(
|
||||
".bdelta"))
|
||||
bone_delta_path += ".bdelta";
|
||||
if (skeleton_data.is_valid()) {
|
||||
Skeleton *base_skeleton =
|
||||
memnew(Skeleton);
|
||||
skeleton_data->load_skeleton(
|
||||
base_skeleton);
|
||||
build_bones_delta(
|
||||
base_skeleton, skeleton,
|
||||
bone_delta_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
count = item->get_child_count();
|
||||
for (i = 0; i < count; i++)
|
||||
@@ -281,12 +362,231 @@ Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags,
|
||||
if (do_destroy)
|
||||
item->queue_delete();
|
||||
}
|
||||
print_line("all done");
|
||||
return result;
|
||||
}
|
||||
typedef struct tri_v {
|
||||
float x, y, cx, cy, cz;
|
||||
} tri_p;
|
||||
float edge_cross(const tri_p *a, const tri_p *b, const tri_p *p)
|
||||
{
|
||||
tri_p ab = { b->x - a->x, b->y - a->y };
|
||||
tri_p ap = { p->x - a->x, p->y - a->y };
|
||||
return ab.x * ap.y - ab.y * ap.x;
|
||||
}
|
||||
bool is_top_left(const tri_p *start, const tri_p *end)
|
||||
{
|
||||
tri_p edge = { end->x - start->x, end->y - start->y };
|
||||
bool is_top_edge = edge.y == 0 && edge.x > 0;
|
||||
bool is_left_edge = edge.y < 0;
|
||||
return is_left_edge || is_top_edge;
|
||||
}
|
||||
static void triangle_fill(const tri_p &v0, const tri_p &v1, const tri_p &v2,
|
||||
int stride, float *buffer)
|
||||
{
|
||||
// Finds the bounding box with all candidate pixels
|
||||
float x_min = Math::floor(MIN(MIN(v0.x, v1.x), v2.x));
|
||||
float y_min = Math::floor(MIN(MIN(v0.y, v1.y), v2.y));
|
||||
float x_max = Math::ceil(MAX(MAX(v0.x, v1.x), v2.x));
|
||||
float y_max = Math::ceil(MAX(MAX(v0.y, v1.y), v2.y));
|
||||
|
||||
float area = edge_cross(&v0, &v1, &v2);
|
||||
|
||||
// Compute the constant delta_s that will be used for the horizontal and vertical steps
|
||||
float delta_w0_col = (v1.y - v2.y);
|
||||
float delta_w1_col = (v2.y - v0.y);
|
||||
float delta_w2_col = (v0.y - v1.y);
|
||||
float delta_w0_row = (v2.x - v1.x);
|
||||
float delta_w1_row = (v0.x - v2.x);
|
||||
float delta_w2_row = (v1.x - v0.x);
|
||||
|
||||
// Rasterization fill rule, not 100% precise due to floating point innacuracy
|
||||
float bias0 = is_top_left(&v1, &v2) ? 0 : -0.0001;
|
||||
float bias1 = is_top_left(&v2, &v0) ? 0 : -0.0001;
|
||||
float bias2 = is_top_left(&v0, &v1) ? 0 : -0.0001;
|
||||
|
||||
// Compute the edge functions for the fist (top-left) point
|
||||
tri_p p0 = { x_min + 0.5f, y_min + 0.5f };
|
||||
float w0_row = edge_cross(&v1, &v2, &p0) + bias0;
|
||||
float w1_row = edge_cross(&v2, &v0, &p0) + bias1;
|
||||
float w2_row = edge_cross(&v0, &v1, &p0) + bias2;
|
||||
|
||||
// Loop all candidate pixels inside the bounding box
|
||||
for (int y = y_min; y <= y_max; y++) {
|
||||
float w0 = w0_row;
|
||||
float w1 = w1_row;
|
||||
float w2 = w2_row;
|
||||
for (int x = x_min; x <= x_max; x++) {
|
||||
bool is_inside = w0 >= 0 && w1 >= 0 && w2 >= 0;
|
||||
if (is_inside) {
|
||||
float alpha = w0 / area;
|
||||
float beta = w1 / area;
|
||||
float gamma = w2 / area;
|
||||
// draw_pixel(x, y, color);
|
||||
buffer[y * stride + x * 4 + 0] =
|
||||
(alpha * v0.cx + beta * v1.cx +
|
||||
gamma * v2.cx);
|
||||
|
||||
buffer[y * stride + x * 4 + 1] =
|
||||
(alpha * v0.cy + beta * v1.cy +
|
||||
gamma * v2.cy);
|
||||
buffer[y * stride + x * 4 + 2] =
|
||||
(alpha * v0.cz + beta * v1.cz +
|
||||
gamma * v2.cz);
|
||||
buffer[y * stride + x * 4 + 0] = 0;
|
||||
}
|
||||
w0 += delta_w0_col;
|
||||
w1 += delta_w1_col;
|
||||
w2 += delta_w2_col;
|
||||
}
|
||||
w0_row += delta_w0_row;
|
||||
w1_row += delta_w1_row;
|
||||
w2_row += delta_w2_row;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorImportNPC::build_shape_base(const Array &base_surface,
|
||||
const Array &surfaces,
|
||||
const String &path)
|
||||
{
|
||||
Error err = OK;
|
||||
int size = 1024;
|
||||
const PoolVector<Vector3> &vertices_base =
|
||||
base_surface[ArrayMesh::ARRAY_VERTEX];
|
||||
const PoolVector<Vector3> &vertices = surfaces[ArrayMesh::ARRAY_VERTEX];
|
||||
const PoolVector<Vector3> &normals_base =
|
||||
base_surface[ArrayMesh::ARRAY_NORMAL];
|
||||
const PoolVector<Vector3> &normals = surfaces[ArrayMesh::ARRAY_NORMAL];
|
||||
const PoolVector<Vector2> &uvs_base = surfaces[ArrayMesh::ARRAY_TEX_UV];
|
||||
const PoolVector<Vector2> &uvs = surfaces[ArrayMesh::ARRAY_TEX_UV];
|
||||
const PoolVector<int> &indices_base =
|
||||
base_surface[ArrayMesh::ARRAY_INDEX];
|
||||
const PoolVector<int> &indices = surfaces[ArrayMesh::ARRAY_INDEX];
|
||||
float *buffer;
|
||||
int i, j;
|
||||
if (vertices.size() != vertices_base.size()) {
|
||||
print_error("Bad shape mesh");
|
||||
return;
|
||||
}
|
||||
if (normals.size() != normals_base.size()) {
|
||||
print_error("Bad shape mesh");
|
||||
return;
|
||||
}
|
||||
if (indices.size() != indices_base.size()) {
|
||||
print_error("Bad shape mesh");
|
||||
return;
|
||||
}
|
||||
buffer = memnew_arr(float, size *size * 4);
|
||||
for (i = 0; i < size * size * 4; i++)
|
||||
buffer[i] = 0.0f;
|
||||
for (i = 0; i < indices.size(); i += 3) {
|
||||
int i0 = indices[i + 0];
|
||||
int i1 = indices[i + 1];
|
||||
int i2 = indices[i + 2];
|
||||
if (!uvs[i0].is_equal_approx(uvs_base[i0]) ||
|
||||
!uvs[i1].is_equal_approx(uvs_base[i1]) ||
|
||||
!uvs[i2].is_equal_approx(uvs_base[i2])) {
|
||||
print_error("Bad shape mesh");
|
||||
memdelete_arr(buffer);
|
||||
return;
|
||||
}
|
||||
Vector3 delta0 = vertices[i0] - vertices_base[i0];
|
||||
Vector3 delta1 = vertices[i1] - vertices_base[i1];
|
||||
Vector3 delta2 = vertices[i2] - vertices_base[i2];
|
||||
int amp = size - 1;
|
||||
tri_p v0 = { uvs[i0].x * amp, uvs[i0].y * amp, delta0.x,
|
||||
delta0.y, delta0.z };
|
||||
tri_p v1 = { uvs[i1].x * amp, uvs[i1].y * amp, delta1.x,
|
||||
delta1.y, delta1.z };
|
||||
tri_p v2 = { uvs[i2].x * amp, uvs[i2].y * amp, delta2.x,
|
||||
delta2.y, delta2.z };
|
||||
triangle_fill(v0, v1, v2, size * 4, buffer);
|
||||
}
|
||||
float max_value = -Math_INF;
|
||||
float min_value = Math_INF;
|
||||
|
||||
for (i = 0; i < size * size * 4; i++) {
|
||||
if (max_value < buffer[i])
|
||||
max_value = buffer[i];
|
||||
if (min_value > buffer[i])
|
||||
min_value = buffer[i];
|
||||
}
|
||||
float delta_value = max_value - min_value;
|
||||
print_line("min_value: " + String::num(min_value) +
|
||||
" max_value: " + String::num(max_value) +
|
||||
" delta_value: " + String::num(delta_value));
|
||||
|
||||
FileAccess *fd = FileAccess::open(path, FileAccess::WRITE, &err);
|
||||
if (fd) {
|
||||
uint8_t *dst_buffer = memnew_arr(uint8_t, size * 3);
|
||||
uint8_t *dbuffer = memnew_arr(uint8_t, size * 3);
|
||||
fd->store_float(min_value);
|
||||
fd->store_float(delta_value);
|
||||
fd->store_32(size);
|
||||
fd->store_32(size);
|
||||
for (i = 0; i < size; i++) {
|
||||
for (j = 0; j < size; j++) {
|
||||
dbuffer[j * 3 + 0] =
|
||||
((double)buffer[i * size + j * 4 + 0] -
|
||||
(double)min_value) *
|
||||
255.0 / (double)delta_value;
|
||||
dbuffer[j * 3 + 1] =
|
||||
((double)buffer[i * size + j * 4 + 1] -
|
||||
(double)min_value) *
|
||||
255.0 / (double)delta_value;
|
||||
dbuffer[j * 3 + 2] =
|
||||
((double)buffer[i * size + j * 4 + 2] -
|
||||
(double)min_value) *
|
||||
255.0 / (double)delta_value;
|
||||
}
|
||||
int cmp_size = Compression::compress(
|
||||
dst_buffer, dbuffer, size * 3,
|
||||
Compression::MODE_FASTLZ);
|
||||
fd->store_32(cmp_size);
|
||||
fd->store_buffer(dst_buffer, cmp_size);
|
||||
}
|
||||
fd->close();
|
||||
memdelete_arr(dst_buffer);
|
||||
memdelete_arr(dbuffer);
|
||||
print_line("Stored shape data to: " + path);
|
||||
}
|
||||
memdelete_arr(buffer);
|
||||
}
|
||||
Ref<Animation> EditorImportNPC::import_animation(const String &p_path,
|
||||
uint32_t p_flags,
|
||||
int p_bake_fps)
|
||||
{
|
||||
return Ref<Animation>();
|
||||
}
|
||||
void EditorImportNPC::build_bones_delta(Skeleton *base_skeleton,
|
||||
Skeleton *skeleton, const String &path)
|
||||
{
|
||||
int i;
|
||||
Error err = OK;
|
||||
if (base_skeleton->get_bone_count() != skeleton->get_bone_count()) {
|
||||
print_error("bad skeleton");
|
||||
return;
|
||||
}
|
||||
FileAccess *fd = FileAccess::open(path, FileAccess::WRITE, &err);
|
||||
if (fd) {
|
||||
Vector<String> delta_names;
|
||||
Vector<Transform> delta_xforms;
|
||||
for (i = 0; i < skeleton->get_bone_count(); i++) {
|
||||
Transform r1 = base_skeleton->get_bone_rest(i);
|
||||
Transform r2 = skeleton->get_bone_rest(i);
|
||||
if (!r1.is_equal_approx(r2)) {
|
||||
delta_names.push_back(
|
||||
skeleton->get_bone_name(i));
|
||||
delta_xforms.push_back(
|
||||
skeleton->get_bone_rest(i));
|
||||
}
|
||||
}
|
||||
for (i = 0; i < delta_names.size(); i++) {
|
||||
fd->store_pascal_string(delta_names[i]);
|
||||
fd->store_buffer((uint8_t *)&delta_xforms[i],
|
||||
sizeof(Transform));
|
||||
}
|
||||
}
|
||||
fd->close();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,10 @@ protected:
|
||||
int p_bake_fps, uint32_t p_compress_flags,
|
||||
List<String> *r_missing_deps = nullptr,
|
||||
Error *r_err = nullptr);
|
||||
void build_shape_base(const Array &base_surface, const Array &surfaces,
|
||||
const String &path);
|
||||
void build_bones_delta(Skeleton *base_skeleton, Skeleton *skeleton,
|
||||
const String &path);
|
||||
virtual Ref<Animation> import_animation(const String &p_path,
|
||||
uint32_t p_flags,
|
||||
int p_bake_fps);
|
||||
|
||||
@@ -1,20 +1,50 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <core/os/memory.h>
|
||||
#include <core/vector.h>
|
||||
#include <core/ustring.h>
|
||||
#include <core/math/transform.h>
|
||||
#include <core/object.h>
|
||||
#include <scene/main/scene_tree.h>
|
||||
#include "flecs/flecs.h"
|
||||
#include <core/os/dir_access.h>
|
||||
#include <scene/3d/skeleton.h>
|
||||
#include <core/io/config_file.h>
|
||||
#include "skeleton_data.h"
|
||||
#include "base_data.h"
|
||||
#include "editor_event.h"
|
||||
#include "game_event.h"
|
||||
#include "persistent_data.h"
|
||||
#include "npc.h"
|
||||
|
||||
class NPCSaveData : public PersistentData::SaveHandler {
|
||||
public:
|
||||
NPC *npc;
|
||||
NPCSaveData(NPC *npc)
|
||||
: npc(npc)
|
||||
{
|
||||
}
|
||||
void save(const String &slot_path)
|
||||
{
|
||||
}
|
||||
void load(const String &slot_path)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
NPC *NPC::singleton = nullptr;
|
||||
|
||||
namespace NPCModule
|
||||
{
|
||||
struct NPCBase {
|
||||
int id;
|
||||
String name;
|
||||
};
|
||||
|
||||
struct NPCSkeleton {
|
||||
String skeleton_path;
|
||||
};
|
||||
|
||||
struct NPCNode {
|
||||
Skeleton *skeleton;
|
||||
};
|
||||
|
||||
struct NPCLocation {
|
||||
@@ -67,6 +97,7 @@ struct module {
|
||||
ecs.module<struct module>();
|
||||
ecs.component<struct NPCBase>();
|
||||
ecs.component<struct NPCLocation>();
|
||||
ecs.component<struct NPCSkeleton>();
|
||||
ecs.component<struct NPCTarget>();
|
||||
ecs.component<struct NPCTargetKey>();
|
||||
ecs.component<struct NPCBody>();
|
||||
@@ -74,6 +105,59 @@ struct module {
|
||||
ecs.component<struct NPCResidence>();
|
||||
ecs.component<struct NPCOccupation>();
|
||||
ecs.component<struct NPCLeisure>();
|
||||
ecs.observer<struct NPCSkeleton>()
|
||||
.event(flecs::OnSet)
|
||||
.with<struct NPCBase>()
|
||||
.with<struct NPCLocation>()
|
||||
.write<struct NPCNode>()
|
||||
.each([](flecs::entity e, const NPCSkeleton &s) {
|
||||
Ref<SkeletonData> skeleton_data;
|
||||
String path = s.skeleton_path;
|
||||
if (e.has<NPCNode>()) {
|
||||
if (e.get<NPCNode>()->skeleton) {
|
||||
e.get_mut<NPCNode>()
|
||||
->skeleton
|
||||
->queue_delete();
|
||||
e.get_mut<NPCNode>()->skeleton =
|
||||
nullptr;
|
||||
e.remove<NPCNode>();
|
||||
}
|
||||
}
|
||||
Node *root = SceneTree::get_singleton()
|
||||
->get_current_scene();
|
||||
if (!root) {
|
||||
print_error("No scene");
|
||||
return;
|
||||
}
|
||||
skeleton_data = ResourceLoader::load(
|
||||
path, "SkeletonData");
|
||||
if (skeleton_data.is_valid()) {
|
||||
Skeleton *skeleton = memnew(Skeleton);
|
||||
|
||||
skeleton_data->load_skeleton(skeleton);
|
||||
e.set<NPCNode>({ skeleton });
|
||||
root->call_deferred("add_child",
|
||||
skeleton);
|
||||
} else
|
||||
print_error(
|
||||
"ERROR: Could not load skeleton: " +
|
||||
path);
|
||||
});
|
||||
ecs.observer<struct NPCSkeleton>()
|
||||
.event(flecs::OnRemove)
|
||||
.write<struct NPCNode>()
|
||||
.each([](flecs::entity e, const NPCSkeleton &s) {
|
||||
if (e.has<NPCNode>()) {
|
||||
if (e.get<NPCNode>()->skeleton) {
|
||||
e.get_mut<NPCNode>()
|
||||
->skeleton
|
||||
->queue_delete();
|
||||
e.get_mut<NPCNode>()->skeleton =
|
||||
nullptr;
|
||||
e.remove<NPCNode>();
|
||||
}
|
||||
}
|
||||
});
|
||||
/* moving NPC despawned NPC */
|
||||
ecs.system<NPCBase>("Update").each(
|
||||
[](flecs::entity e, NPCBase &b) {
|
||||
@@ -84,12 +168,18 @@ struct module {
|
||||
|
||||
}
|
||||
|
||||
|
||||
NPC::NPC()
|
||||
{
|
||||
flecs::world ecs = BaseData::get_singleton()->get();
|
||||
ecs.import <NPCModule::module>();
|
||||
flecs::entity npcs_e = ecs.entity("npc");
|
||||
flecs::entity base = ecs.entity("characters");
|
||||
if (base.is_valid()) {
|
||||
/* create components for top level */
|
||||
}
|
||||
EditorEvent::get_singleton()->event.add_listener(
|
||||
this, &NPC::editor_event_handler);
|
||||
GameEvent::get_singleton()->event.add_listener(
|
||||
this, &NPC::game_event_handler);
|
||||
}
|
||||
|
||||
NPC *NPC::get_singleton()
|
||||
@@ -111,3 +201,71 @@ NPC::~NPC()
|
||||
void NPC::update(float delta)
|
||||
{
|
||||
}
|
||||
|
||||
flecs::entity NPC::foreground_character(int id)
|
||||
{
|
||||
String ch_name = "ch_" + itos(id);
|
||||
flecs::world ecs = BaseData::get_singleton()->get();
|
||||
flecs::entity base = ecs.lookup("characters");
|
||||
flecs::entity ch = base.lookup(ch_name.ascii().ptr());
|
||||
if (!ch.is_valid())
|
||||
ch = ecs.entity(ch_name.ascii().ptr()).child_of(base);
|
||||
assert(ch.is_valid());
|
||||
if (!ch.has<NPCModule::NPCBase>())
|
||||
ch.set<NPCModule::NPCBase>({ id });
|
||||
return ch;
|
||||
}
|
||||
|
||||
void NPC::background_character(int id)
|
||||
{
|
||||
String ch_name = "ch_" + itos(id);
|
||||
flecs::world ecs = BaseData::get_singleton()->get();
|
||||
flecs::entity base = ecs.lookup("characters");
|
||||
flecs::entity ch = base.lookup(ch_name.ascii().ptr());
|
||||
assert(ch.is_valid());
|
||||
/* remove all components */
|
||||
std::vector<flecs::entity_t> keep_components = {
|
||||
ecs.component<NPCModule::NPCBase>()
|
||||
};
|
||||
ch.each([&ch, keep_components](flecs::entity_t c) {
|
||||
if (std::find(keep_components.begin(), keep_components.end(),
|
||||
c) == keep_components.end())
|
||||
ch.remove(c);
|
||||
});
|
||||
}
|
||||
|
||||
void NPC::get_character_list(List<int> *character_list)
|
||||
{
|
||||
Error err;
|
||||
DirAccess *d = DirAccess::open("res://character/config", &err);
|
||||
d->list_dir_begin();
|
||||
String conf_path;
|
||||
while ((conf_path = d->get_next()) != "") {
|
||||
ConfigFile config;
|
||||
config.load(conf_path);
|
||||
int id = config.get_value("base", "id");
|
||||
}
|
||||
d->list_dir_end();
|
||||
}
|
||||
|
||||
void NPC::editor_event_handler(const String &event, const Vector<Variant> &args)
|
||||
{
|
||||
if (event == "npc_foreground") {
|
||||
int npc_id = args[0];
|
||||
foreground_character(npc_id);
|
||||
} else if (event == "npc_background") {
|
||||
int npc_id = args[0];
|
||||
background_character(npc_id);
|
||||
}
|
||||
}
|
||||
|
||||
void NPC::game_event_handler(const String &event, const Vector<Variant> &args)
|
||||
{
|
||||
if (event == "npc_foreground") {
|
||||
int npc_id = args[0];
|
||||
foreground_character(npc_id);
|
||||
} else if (event == "npc_background") {
|
||||
int npc_id = args[0];
|
||||
background_character(npc_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifndef NPC_H_
|
||||
#define NPC_H_
|
||||
class ConfigFile;
|
||||
class NPC {
|
||||
static NPC *singleton;
|
||||
NPC();
|
||||
@@ -9,5 +10,14 @@ public:
|
||||
static void cleanup();
|
||||
virtual ~NPC();
|
||||
void update(float delta);
|
||||
flecs::entity foreground_character(int id);
|
||||
void background_character(int id);
|
||||
static void get_character_list(List<int> *character_list);
|
||||
|
||||
private:
|
||||
void editor_event_handler(const String &event,
|
||||
const Vector<Variant> &args);
|
||||
void game_event_handler(const String &event,
|
||||
const Vector<Variant> &args);
|
||||
};
|
||||
#endif
|
||||
38
src/modules/stream/npc/npc_editor.cpp
Normal file
38
src/modules/stream/npc/npc_editor.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <core/object.h>
|
||||
#include <core/os/dir_access.h>
|
||||
#include <core/io/config_file.h>
|
||||
#include "editor_event.h"
|
||||
#include "npc_editor.h"
|
||||
|
||||
void NPCEditor::handle_event(const String &event, const Vector<Variant> &args)
|
||||
{
|
||||
if (event == "npc_list") {
|
||||
#if 0
|
||||
Error err;
|
||||
DirAccess *d = DirAccess::open("res://character/config", &err);
|
||||
d->list_dir_begin();
|
||||
|
||||
String mdata;
|
||||
while ((mdata = d->get_next()) != "") {
|
||||
ConfigFile config;
|
||||
String config_path = "res://character/config/" + mdata;
|
||||
config.load(config_path);
|
||||
}
|
||||
d->list_dir_end();
|
||||
memdelete(d);
|
||||
#endif
|
||||
EditorEvent::get_singleton()->event.emit("npc_list_report",
|
||||
varray());
|
||||
}
|
||||
}
|
||||
|
||||
NPCEditor::NPCEditor(WorldEditor *editor)
|
||||
: editor(editor)
|
||||
{
|
||||
EditorEvent::get_singleton()->event.add_listener(
|
||||
this, &NPCEditor::handle_event);
|
||||
}
|
||||
|
||||
NPCEditor::~NPCEditor()
|
||||
{
|
||||
}
|
||||
9
src/modules/stream/npc/npc_editor.h
Normal file
9
src/modules/stream/npc/npc_editor.h
Normal file
@@ -0,0 +1,9 @@
|
||||
class NPCEditor {
|
||||
class WorldEditor *editor;
|
||||
|
||||
void handle_event(const String &event, const Vector<Variant> &args);
|
||||
|
||||
public:
|
||||
NPCEditor(WorldEditor *editor);
|
||||
virtual ~NPCEditor();
|
||||
};
|
||||
71
src/modules/stream/npc/skeleton_data.cpp
Normal file
71
src/modules/stream/npc/skeleton_data.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// skeleton_data.cpp
|
||||
#include "skeleton_data.h"
|
||||
|
||||
void SkeletonData::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("set_bone_data", "data"),
|
||||
&SkeletonData::set_bone_data);
|
||||
ClassDB::bind_method(D_METHOD("get_bone_data"),
|
||||
&SkeletonData::get_bone_data);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bone_data"), "set_bone_data",
|
||||
"get_bone_data");
|
||||
}
|
||||
|
||||
void SkeletonData::set_bone_data(const Dictionary &data)
|
||||
{
|
||||
bone_data = data;
|
||||
}
|
||||
|
||||
Dictionary SkeletonData::get_bone_data() const
|
||||
{
|
||||
return bone_data;
|
||||
}
|
||||
|
||||
void SkeletonData::save_skeleton(Skeleton *skeleton)
|
||||
{
|
||||
if (!skeleton)
|
||||
return;
|
||||
|
||||
bone_data.clear();
|
||||
int bone_count = skeleton->get_bone_count();
|
||||
for (int i = 0; i < bone_count; i++) {
|
||||
String bone_name = skeleton->get_bone_name(i);
|
||||
Dictionary b;
|
||||
b["id"] = i;
|
||||
b["enabled"] = skeleton->is_bone_enabled(i);
|
||||
b["parent"] = skeleton->get_bone_parent(i);
|
||||
b["rest"] = skeleton->get_bone_rest(i);
|
||||
b["pose"] = skeleton->get_bone_pose(i);
|
||||
b["custom"] = skeleton->get_bone_custom_pose(i);
|
||||
bone_data[bone_name] = b;
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonData::load_skeleton(Skeleton *skeleton)
|
||||
{
|
||||
if (!skeleton)
|
||||
return;
|
||||
List<Variant> keys;
|
||||
List<Variant>::Element *e;
|
||||
bone_data.get_key_list(&keys);
|
||||
e = keys.front();
|
||||
int bsize = keys.size();
|
||||
skeleton->clear_bones();
|
||||
while (e) {
|
||||
String bone_name = e->get();
|
||||
const Dictionary &b = bone_data[bone_name];
|
||||
skeleton->add_bone(bone_name);
|
||||
bool enabled = b["enabled"];
|
||||
int parent = b["parent"];
|
||||
int id = b["id"];
|
||||
const Transform &rest = b["rest"];
|
||||
const Transform &pose = b["pose"];
|
||||
const Transform &custom = b["custom"];
|
||||
skeleton->set_bone_enabled(id, enabled);
|
||||
skeleton->set_bone_parent(id, parent);
|
||||
skeleton->set_bone_rest(id, rest);
|
||||
skeleton->set_bone_pose(id, pose);
|
||||
skeleton->set_bone_custom_pose(id, custom);
|
||||
e = e->next();
|
||||
}
|
||||
}
|
||||
26
src/modules/stream/npc/skeleton_data.h
Normal file
26
src/modules/stream/npc/skeleton_data.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// skeleton_data.h
|
||||
#ifndef SKELETON_DATA_H
|
||||
#define SKELETON_DATA_H
|
||||
|
||||
#include <core/math/transform.h>
|
||||
#include <core/resource.h>
|
||||
#include <scene/3d/skeleton.h>
|
||||
|
||||
class SkeletonData : public Resource {
|
||||
GDCLASS(SkeletonData, Resource);
|
||||
|
||||
private:
|
||||
Dictionary bone_data;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_bone_data(const Dictionary &data);
|
||||
Dictionary get_bone_data() const;
|
||||
|
||||
void save_skeleton(Skeleton *skeleton);
|
||||
void load_skeleton(Skeleton *skeleton);
|
||||
};
|
||||
|
||||
#endif // SKELETON_DATA_H
|
||||
13
src/modules/stream/persistent_data/SCsub
Normal file
13
src/modules/stream/persistent_data/SCsub
Normal file
@@ -0,0 +1,13 @@
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_stream = env_modules.Clone()
|
||||
env_stream.stream_building_sources = []
|
||||
|
||||
env_stream.add_source_files(env_stream.stream_building_sources, "*.cpp")
|
||||
|
||||
lib = env_stream.add_library("lersistent-data", env_stream.stream_building_sources)
|
||||
env.Append(LIBS=[lib])
|
||||
env_stream.Prepend(CPPPATH=[".."])
|
||||
env_stream.Prepend(CPPPATH=["../../../meshoptimizer/src"])
|
||||
env_stream.Prepend(CPPPATH=["../event"])
|
||||
34
src/modules/stream/persistent_data/persistent_data.cpp
Normal file
34
src/modules/stream/persistent_data/persistent_data.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "persistent_data.h"
|
||||
|
||||
PersistentData *PersistentData::singleton;
|
||||
PersistentData::PersistentData()
|
||||
{
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
void PersistentData::save_data(const String &save_slot_path)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < handlers.size(); i++)
|
||||
handlers.ptrw()[i]->save(save_slot_path);
|
||||
}
|
||||
|
||||
void PersistentData::load_data(const String &save_slot_path)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < handlers.size(); i++)
|
||||
handlers.ptrw()[i]->load(save_slot_path);
|
||||
}
|
||||
|
||||
PersistentData *PersistentData::get_singleton()
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = memnew(PersistentData);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void PersistentData::cleanup()
|
||||
{
|
||||
if (singleton)
|
||||
memdelete(singleton);
|
||||
}
|
||||
21
src/modules/stream/persistent_data/persistent_data.h
Normal file
21
src/modules/stream/persistent_data/persistent_data.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <core/vector.h>
|
||||
class PersistentData {
|
||||
static PersistentData *singleton;
|
||||
PersistentData();
|
||||
|
||||
public:
|
||||
class SaveHandler {
|
||||
public:
|
||||
virtual void save(const String &slot_path) = 0;
|
||||
virtual void load(const String &slot_path) = 0;
|
||||
};
|
||||
Vector<SaveHandler *> handlers;
|
||||
void register_handler(SaveHandler *handler)
|
||||
{
|
||||
handlers.push_back(handler);
|
||||
}
|
||||
void save_data(const String &save_slot_path);
|
||||
void load_data(const String &save_slot_path);
|
||||
static PersistentData *get_singleton();
|
||||
static void cleanup();
|
||||
};
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "buildings/building_layout_editor.h"
|
||||
#include "ui/main_tabs.h"
|
||||
#include "npc/importer.h"
|
||||
#include "npc/skeleton_data.h"
|
||||
#include "base_data.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
@@ -28,6 +29,7 @@ void register_stream_types()
|
||||
ClassDB::register_class<LineMetadataEditor>();
|
||||
ClassDB::register_class<BuildingLayoutEditor>();
|
||||
ClassDB::register_class<MainTabs>();
|
||||
ClassDB::register_class<SkeletonData>();
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
|
||||
@@ -78,27 +78,32 @@ public:
|
||||
: Object()
|
||||
, editor(editor)
|
||||
{
|
||||
#if 0
|
||||
LineEdit *filter =
|
||||
editor->get_as_node<LineEdit>("%road_lines_filter");
|
||||
filter->connect("text_changed", this, "filter_handler");
|
||||
filter->connect("text_entered", this, "filter_handler");
|
||||
#endif
|
||||
#if 0
|
||||
ItemList *lines_list =
|
||||
editor->get_as_node<ItemList>("%lines_list");
|
||||
lines_list->connect("item_selected", this, "handler");
|
||||
Button *cursor_set = editor->get_as_node<Button>(
|
||||
"%road_lines_set_cursor_position");
|
||||
Button *cursor_set = editor->cursor_set;
|
||||
assert(cursor_set);
|
||||
cursor_set->connect("pressed", this, "set_cursor_handler");
|
||||
Button *point_set = editor->get_as_node<Button>(
|
||||
"%road_lines_set_point_position");
|
||||
Button *point_set = editor->cursor_set;
|
||||
assert(point_set);
|
||||
point_set->connect("pressed", this, "set_point_handler");
|
||||
#endif
|
||||
}
|
||||
virtual ~HandleSelection()
|
||||
{
|
||||
Button *cursor_set = editor->get_as_node<Button>(
|
||||
"%road_lines_set_cursor_position");
|
||||
#if 0
|
||||
Button *cursor_set = editor->cursor_set;
|
||||
assert(cursor_set);
|
||||
cursor_set->disconnect("pressed", this, "set_cursor_handler");
|
||||
Button *point_set = editor->get_as_node<Button>(
|
||||
"%road_lines_set_point_position");
|
||||
Button *point_set = editor->cursor_set;
|
||||
assert(point_set);
|
||||
point_set->disconnect("pressed", this, "set_point_handler");
|
||||
ItemList *lines_list =
|
||||
editor->get_as_node<ItemList>("%lines_list");
|
||||
@@ -107,6 +112,7 @@ public:
|
||||
editor->get_as_node<LineEdit>("%road_lines_filter");
|
||||
filter->disconnect("text_entered", this, "filter_handler");
|
||||
filter->disconnect("text_changed", this, "filter_handler");
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -122,12 +128,12 @@ protected:
|
||||
{
|
||||
editor->line_list_filter_changed(text);
|
||||
}
|
||||
#if 0
|
||||
void set_cursor_handler()
|
||||
{
|
||||
LineEdit *cursor_x = editor->get_as_node<LineEdit>("%cursor_x");
|
||||
LineEdit *cursor_y = editor->get_as_node<LineEdit>("%cursor_y");
|
||||
LineEdit *cursor_z = editor->get_as_node<LineEdit>("%cursor_z");
|
||||
LineEdit *cursor[] = { cursor_x, cursor_y, cursor_z };
|
||||
LineEdit *cursor_x = editor->cursor_pos[0];
|
||||
LineEdit *cursor_y = editor->cursor_pos[1];
|
||||
LineEdit *cursor_z = editor->cursor_pos[2];
|
||||
Vector3 position;
|
||||
position.x = cursor_x->get_text().to_float();
|
||||
position.y = cursor_y->get_text().to_float();
|
||||
@@ -136,26 +142,28 @@ protected:
|
||||
}
|
||||
void set_point_handler()
|
||||
{
|
||||
LineEdit *point_x = editor->get_as_node<LineEdit>("%point_x");
|
||||
LineEdit *point_y = editor->get_as_node<LineEdit>("%point_y");
|
||||
LineEdit *point_z = editor->get_as_node<LineEdit>("%point_z");
|
||||
LineEdit *point[] = { point_x, point_y, point_z };
|
||||
LineEdit *point_x = editor->point_pos[0];
|
||||
LineEdit *point_y = editor->point_pos[1];
|
||||
LineEdit *point_z = editor->point_pos[2];
|
||||
Vector3 position;
|
||||
position.x = point_x->get_text().to_float();
|
||||
position.y = point_y->get_text().to_float();
|
||||
position.z = point_z->get_text().to_float();
|
||||
editor->set_point_position(position);
|
||||
}
|
||||
#endif
|
||||
static void _bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("handler", "index"),
|
||||
&HandleSelection::handler);
|
||||
ClassDB::bind_method(D_METHOD("filter_handler", "text"),
|
||||
&HandleSelection::filter_handler);
|
||||
#if 0
|
||||
ClassDB::bind_method(D_METHOD("set_cursor_handler"),
|
||||
&HandleSelection::set_cursor_handler);
|
||||
ClassDB::bind_method(D_METHOD("set_point_handler"),
|
||||
&HandleSelection::set_point_handler);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,17 +178,21 @@ public:
|
||||
: Object()
|
||||
, editor(editor)
|
||||
{
|
||||
#if 0
|
||||
SpinBox *sp_line_point =
|
||||
editor->get_as_node<SpinBox>("%line_index");
|
||||
sp_line_point->connect("value_changed", this,
|
||||
"handle_value_change");
|
||||
#endif
|
||||
}
|
||||
virtual ~HandlePointSelection()
|
||||
{
|
||||
#if 0
|
||||
SpinBox *sp_line_point =
|
||||
editor->get_as_node<SpinBox>("%line_index");
|
||||
sp_line_point->disconnect("value_changed", this,
|
||||
"handle_value_change");
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -218,10 +230,6 @@ public:
|
||||
: Object()
|
||||
, editor(editor)
|
||||
{
|
||||
Button *cancel_button = editor->get_as_node<Button>(
|
||||
"%road_lines_create_new_cancel");
|
||||
LineEdit *line_name = editor->get_as_node<LineEdit>(
|
||||
"%road_lines_create_new_line_name");
|
||||
Button *cancel_metadata_button = editor->get_as_node<Button>(
|
||||
"%road_lines_metadata_cancel");
|
||||
Button *update_metadata_button = editor->get_as_node<Button>(
|
||||
@@ -230,9 +238,6 @@ public:
|
||||
"%road_lines_metadata_edit");
|
||||
Button *line_buildings_close =
|
||||
editor->get_as_node<Button>("%line_buildings_close");
|
||||
cancel_button->connect("pressed", this, "cancel_handler");
|
||||
line_name->connect("text_entered", this, "entered_handler");
|
||||
line_name->connect("text_changed", this, "changed_handler");
|
||||
cancel_metadata_button->connect("pressed", this,
|
||||
"cancel_metadata_handler");
|
||||
update_metadata_button->connect("pressed", this,
|
||||
@@ -252,10 +257,6 @@ public:
|
||||
"%road_lines_metadata_update");
|
||||
Button *cancel_metadata_button = editor->get_as_node<Button>(
|
||||
"%road_lines_metadata_cancel");
|
||||
Button *cancel_button = editor->get_as_node<Button>(
|
||||
"%road_lines_create_new_cancel");
|
||||
LineEdit *line_name = editor->get_as_node<LineEdit>(
|
||||
"%road_lines_create_new_line_name");
|
||||
line_buildings_close->disconnect(
|
||||
"pressed", this, "line_buildings_close_handler");
|
||||
metadata_edit->disconnect("text_changed", this,
|
||||
@@ -264,9 +265,6 @@ public:
|
||||
"update_metadata_handler");
|
||||
cancel_metadata_button->disconnect("pressed", this,
|
||||
"cancel_metadata_handler");
|
||||
line_name->disconnect("text_changed", this, "changed_handler");
|
||||
line_name->disconnect("text_entered", this, "entered_handler");
|
||||
cancel_button->disconnect("pressed", this, "cancel_handler");
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -298,53 +296,6 @@ protected:
|
||||
items->add_item(key);
|
||||
}
|
||||
}
|
||||
void cancel_handler()
|
||||
{
|
||||
LineEdit *line_name = editor->get_as_node<LineEdit>(
|
||||
"%road_lines_create_new_line_name");
|
||||
editor->get_as_node<Control>("%road_lines_base")->show();
|
||||
editor->get_as_node<Control>("%road_lines_create_new_line_dlg")
|
||||
->hide();
|
||||
line_name->set_text("");
|
||||
}
|
||||
bool check_line_name(const String &line_name)
|
||||
{
|
||||
String text = line_name.strip_edges();
|
||||
if (editor->line_exists(text) || text.length() < 5 ||
|
||||
text.find("_") < 0 || text.ends_with("_"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
void entered_handler(const String &new_text)
|
||||
{
|
||||
String text = new_text.strip_edges();
|
||||
LineEdit *line_name = editor->get_as_node<LineEdit>(
|
||||
"%road_lines_create_new_line_name");
|
||||
if (!check_line_name(text)) {
|
||||
line_name->add_color_override(
|
||||
"font_color", Color(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
return;
|
||||
} else
|
||||
line_name->remove_color_override("font_color");
|
||||
editor->create_new_line_at_cursor(text);
|
||||
/* clean text */
|
||||
line_name->set_text("");
|
||||
editor->get_as_node<Control>("%road_lines_base")->show();
|
||||
editor->get_as_node<Control>("%road_lines_create_new_line_dlg")
|
||||
->hide();
|
||||
}
|
||||
void changed_handler(const String &new_text)
|
||||
{
|
||||
LineEdit *line_name = editor->get_as_node<LineEdit>(
|
||||
"%road_lines_create_new_line_name");
|
||||
String text = new_text.strip_edges();
|
||||
if (!check_line_name(text)) {
|
||||
line_name->add_color_override(
|
||||
"font_color", Color(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
return;
|
||||
} else
|
||||
line_name->remove_color_override("font_color");
|
||||
}
|
||||
void cancel_metadata_handler()
|
||||
{
|
||||
TextEdit *metadata_text = editor->get_as_node<TextEdit>(
|
||||
@@ -404,12 +355,6 @@ protected:
|
||||
}
|
||||
static void _bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("cancel_handler"),
|
||||
&HandleCreateNewLine::cancel_handler);
|
||||
ClassDB::bind_method(D_METHOD("entered_handler", "new_text"),
|
||||
&HandleCreateNewLine::entered_handler);
|
||||
ClassDB::bind_method(D_METHOD("changed_handler", "new_text"),
|
||||
&HandleCreateNewLine::changed_handler);
|
||||
ClassDB::bind_method(
|
||||
D_METHOD("cancel_metadata_handler"),
|
||||
&HandleCreateNewLine::cancel_metadata_handler);
|
||||
@@ -442,6 +387,12 @@ RoadLinesEditor::RoadLinesEditor(WorldEditor *editor)
|
||||
, filter_text("")
|
||||
, camera_moved(false)
|
||||
, update_roads(false)
|
||||
#if 0
|
||||
, cursor_pos{ 0, 0, 0 }
|
||||
, cursor_set(nullptr)
|
||||
, point_pos{ 0, 0, 0 }
|
||||
, point_set(nullptr)
|
||||
#endif
|
||||
, debug_road_nodes(false)
|
||||
, debug_road_edges(false)
|
||||
, debug_road_wedges(false)
|
||||
@@ -533,10 +484,8 @@ void RoadLinesEditor::update_line_geometry()
|
||||
}
|
||||
void RoadLinesEditor::update_line_index_ui()
|
||||
{
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||
sp_line_index->set_max(rld->lines(current_line).points.size() - 1);
|
||||
sp_line_index->set_min(0);
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_update_line_index_ui", varray(current_line));
|
||||
}
|
||||
void RoadLinesEditor::select_line(const String &line_name)
|
||||
{
|
||||
@@ -546,8 +495,8 @@ void RoadLinesEditor::select_line(const String &line_name)
|
||||
if (current_line != line_name) {
|
||||
current_line = line_name;
|
||||
update_line_index_ui();
|
||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||
sp_line_index->set_value(0);
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_clear_selected_line_ui", varray());
|
||||
/* as actual index of SpinBox might not change
|
||||
call point selection explicitly */
|
||||
set_line_index(0);
|
||||
@@ -577,9 +526,8 @@ void RoadLinesEditor::line_create_point()
|
||||
varray(current_line));
|
||||
update_line_geometry();
|
||||
update_line_index_ui();
|
||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||
sp_line_index->set_value(index + 1);
|
||||
// move_cursor_to_point();
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_set_line_index_ui", varray(line_index + 1));
|
||||
}
|
||||
|
||||
void RoadLinesEditor::line_delete_point()
|
||||
@@ -595,10 +543,11 @@ void RoadLinesEditor::line_delete_point()
|
||||
varray(current_line));
|
||||
update_line_geometry();
|
||||
update_line_index_ui();
|
||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||
sp_line_index->set_value(0);
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_update_line_index_ui", varray(current_line));
|
||||
index = MAX(0, index - 1);
|
||||
sp_line_index->set_value(index);
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_set_line_index_ui", varray(index));
|
||||
}
|
||||
|
||||
static const String cursor_name = "%line_cursor";
|
||||
@@ -619,10 +568,7 @@ void RoadLinesEditor::set_point_to_cursor()
|
||||
|
||||
int RoadLinesEditor::get_line_index()
|
||||
{
|
||||
print_line("get_line_index");
|
||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||
int index = (int)sp_line_index->get_value();
|
||||
return index;
|
||||
return line_index;
|
||||
}
|
||||
|
||||
void RoadLinesEditor::move_cursor_to_point()
|
||||
@@ -739,14 +685,12 @@ void RoadLinesEditor::update_ui()
|
||||
{
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
get_as_node<Control>("%road_lines_base")->show();
|
||||
get_as_node<Control>("%road_lines_create_new_line_dlg")->hide();
|
||||
get_as_node<Control>("%road_lines_edit_metadata_dlg")->hide();
|
||||
get_as_node<Control>("%road_lines_buildings")->hide();
|
||||
ItemList *lines_list = get_as_node<ItemList>("%lines_list");
|
||||
PoolVector<String> elements;
|
||||
List<String> line_keys;
|
||||
rld->get_lines_key_list(&line_keys);
|
||||
List<String>::Element *e = line_keys.front();
|
||||
lines_list->clear();
|
||||
if (!re.is_valid())
|
||||
re.instance();
|
||||
re->compile(filter_text);
|
||||
@@ -763,14 +707,19 @@ void RoadLinesEditor::update_ui()
|
||||
}
|
||||
if (key == current_line)
|
||||
selected_index = index;
|
||||
lines_list->add_item(key);
|
||||
elements.push_back(key);
|
||||
e = e->next();
|
||||
index++;
|
||||
}
|
||||
#if 0
|
||||
if (selected_index >= 0)
|
||||
lines_list->set_current(selected_index);
|
||||
else
|
||||
lines_list->set_current(0);
|
||||
#endif
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_update_lines_list",
|
||||
varray(elements, selected_index));
|
||||
}
|
||||
|
||||
void RoadLinesEditor::create_new_line_at_cursor(const String &line_name)
|
||||
@@ -788,6 +737,7 @@ void RoadLinesEditor::create_new_line_at_cursor(const String &line_name)
|
||||
Transform cursor_position(Basis(), get_cursor_position());
|
||||
rline.points.push_back(cursor_position);
|
||||
rld->set_line(line_name, rline);
|
||||
assert(rld->has_line(line_name));
|
||||
update_line_index_ui();
|
||||
update_ui();
|
||||
}
|
||||
@@ -827,21 +777,31 @@ void RoadLinesEditor::set_point_position(const Vector3 &position)
|
||||
}
|
||||
void RoadLinesEditor::set_ui_cursor_position(const Vector3 &cursor_position)
|
||||
{
|
||||
LineEdit *cursor_x = get_as_node<LineEdit>("%cursor_x");
|
||||
LineEdit *cursor_y = get_as_node<LineEdit>("%cursor_y");
|
||||
LineEdit *cursor_z = get_as_node<LineEdit>("%cursor_z");
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_set_ui_cursor_position",
|
||||
varray(cursor_position));
|
||||
#if 0
|
||||
LineEdit *cursor_x = cursor_pos[0];
|
||||
LineEdit *cursor_y = cursor_pos[1];
|
||||
LineEdit *cursor_z = cursor_pos[2];
|
||||
cursor_x->set_text(String::num(cursor_position.x));
|
||||
cursor_y->set_text(String::num(cursor_position.y));
|
||||
cursor_z->set_text(String::num(cursor_position.z));
|
||||
#endif
|
||||
}
|
||||
void RoadLinesEditor::set_ui_point_position(const Vector3 &point_position)
|
||||
{
|
||||
LineEdit *point_x = get_as_node<LineEdit>("%point_x");
|
||||
LineEdit *point_y = get_as_node<LineEdit>("%point_y");
|
||||
LineEdit *point_z = get_as_node<LineEdit>("%point_z");
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_set_ui_point_position",
|
||||
varray(point_position));
|
||||
#if 0
|
||||
LineEdit *point_x = point_pos[0];
|
||||
LineEdit *point_y = point_pos[1];
|
||||
LineEdit *point_z = point_pos[2];
|
||||
point_x->set_text(String::num(point_position.x));
|
||||
point_y->set_text(String::num(point_position.y));
|
||||
point_z->set_text(String::num(point_position.z));
|
||||
#endif
|
||||
}
|
||||
|
||||
void RoadLinesEditor::set_line_index(int index)
|
||||
@@ -851,6 +811,7 @@ void RoadLinesEditor::set_line_index(int index)
|
||||
assert(index < (int)rld->lines(current_line).points.size());
|
||||
Vector3 point_position = rld->lines(current_line).points[index].origin;
|
||||
Vector3 cursor_position = point_position;
|
||||
line_index = index;
|
||||
set_cursor_position(cursor_position);
|
||||
set_ui_cursor_position(cursor_position);
|
||||
set_ui_point_position(point_position);
|
||||
@@ -1150,5 +1111,55 @@ void RoadLinesEditor::event_handler(const String &event,
|
||||
rebuild_roads();
|
||||
} else if (event == "result:get_building_types") {
|
||||
/* TODO:: implement */
|
||||
#if 0
|
||||
} else if (event == "road_lines_setup_cursor_ui") {
|
||||
cursor_pos[0] = Object::cast_to<LineEdit>(args[0]);
|
||||
cursor_pos[1] = Object::cast_to<LineEdit>(args[1]);
|
||||
cursor_pos[2] = Object::cast_to<LineEdit>(args[2]);
|
||||
cursor_set = Object::cast_to<Button>(args[3]);
|
||||
assert(cursor_set);
|
||||
} else if (event == "road_lines_setup_point_ui") {
|
||||
point_pos[0] = Object::cast_to<LineEdit>(args[0]);
|
||||
point_pos[1] = Object::cast_to<LineEdit>(args[1]);
|
||||
point_pos[2] = Object::cast_to<LineEdit>(args[2]);
|
||||
point_set = Object::cast_to<Button>(args[3]);
|
||||
assert(cursor_set);
|
||||
#endif
|
||||
} else if (event == "road_lines_editor_set_cursor_position") {
|
||||
Vector3 position = args[0];
|
||||
set_cursor_position(position);
|
||||
} else if (event == "road_lines_editor_set_point_position") {
|
||||
Vector3 position = args[0];
|
||||
set_point_position(position);
|
||||
} else if (event == "road_lines_filter") {
|
||||
String text = args[1];
|
||||
line_list_filter_changed(text);
|
||||
} else if (event == "road_lines_editor_set_line_index") {
|
||||
int index = (int)args[1];
|
||||
set_line_index(index);
|
||||
} else if (event == "road_lines_create_new_line_name:entered") {
|
||||
String new_text = args[1];
|
||||
String text = new_text.strip_edges();
|
||||
LineEdit *le = Object::cast_to<LineEdit>(args[0]);
|
||||
if (line_exists(text) || text.length() < 5 ||
|
||||
text.find("_") < 0 || text.ends_with("_")) {
|
||||
le->add_color_override("font_color",
|
||||
Color(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
return;
|
||||
} else {
|
||||
le->remove_color_override("font_color");
|
||||
create_new_line_at_cursor(text);
|
||||
}
|
||||
} else if (event == "road_lines_create_new_line_name:changed") {
|
||||
String new_text = args[1];
|
||||
String text = new_text.strip_edges();
|
||||
LineEdit *le = Object::cast_to<LineEdit>(args[0]);
|
||||
if (line_exists(text) || text.length() < 5 ||
|
||||
text.find("_") < 0 || text.ends_with("_")) {
|
||||
le->add_color_override("font_color",
|
||||
Color(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
return;
|
||||
} else
|
||||
le->remove_color_override("font_color");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "world_editor.h"
|
||||
class ItemList;
|
||||
class RegEx;
|
||||
class LineEdit;
|
||||
class Button;
|
||||
class RoadLinesEditor {
|
||||
bool active;
|
||||
WorldEditor *editor;
|
||||
@@ -11,6 +13,17 @@ class RoadLinesEditor {
|
||||
Ref<RegEx> re;
|
||||
bool camera_moved;
|
||||
Vector3 camera_motion;
|
||||
int line_index;
|
||||
|
||||
#if 0
|
||||
public:
|
||||
LineEdit *cursor_pos[3];
|
||||
Button *cursor_set;
|
||||
LineEdit *point_pos[3];
|
||||
Button *point_set;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void event_handler(const String &event, const Vector<Variant> &args);
|
||||
bool update_roads; // 201
|
||||
bool debug_road_nodes; // 210
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include <scene/gui/option_button.h>
|
||||
#include <scene/gui/button.h>
|
||||
#include <scene/gui/line_edit.h>
|
||||
#include <scene/gui/item_list.h>
|
||||
#include <scene/gui/check_box.h>
|
||||
#include <scene/gui/spin_box.h>
|
||||
#include "editor_event.h"
|
||||
|
||||
#define _GODOT_HANDLER_METHOD(class_name, obj_name, sig_name, event_name, \
|
||||
@@ -97,9 +99,16 @@ GODOT_HANDLER_EVENT_METHOD(ButtonPressHandler, Button, pressed, (), (),
|
||||
GODOT_HANDLER_EVENT_METHOD(LineEditString, LineEdit, text_changed,
|
||||
(const String &text), (text),
|
||||
D_METHOD("handler", "text"))
|
||||
GODOT_HANDLER_EVENT_METHOD(LineEditEnterString, LineEdit, text_entered,
|
||||
(const String &text), (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"))
|
||||
GODOT_HANDLER_EVENT_METHOD(ItemListHandler, ItemList, item_selected, (int id),
|
||||
(id), D_METHOD("handler", "id"))
|
||||
GODOT_HANDLER_EVENT_METHOD(SpinBoxHandler, SpinBox, value_changed,
|
||||
(float value), (value), D_METHOD("handler", "value"))
|
||||
|
||||
#endif // SIGNAL_HANDLER_H_
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "road_processing.h"
|
||||
#include "road_debug.h"
|
||||
#include "buildings_data.h"
|
||||
#include "base_data.h"
|
||||
#include "npc/npc.h"
|
||||
#include "stream.h"
|
||||
|
||||
#define data() (BuildingsData::get_singleton())
|
||||
@@ -455,6 +457,10 @@ StreamWorld::StreamWorld()
|
||||
map_it++;
|
||||
}
|
||||
view_distance = config.get_value("world", "view_distance");
|
||||
NPC *npc = NPC::get_singleton();
|
||||
if (!npc) {
|
||||
assert(false);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
void StreamWorld::cleanup()
|
||||
|
||||
@@ -15,5 +15,6 @@ env.add_source_files(env.stream_building_sources, "*.cpp")
|
||||
lib = env.add_library("ui", env.stream_building_sources)
|
||||
env.Prepend(LIBS=[lib])
|
||||
env.Prepend(CPPPATH=["../rtree"])
|
||||
env.Prepend(CPPPATH=["../event"])
|
||||
env.Prepend(CPPPATH=[".."])
|
||||
env.Prepend(CPPPATH=["../../../meshoptimizer/src"])
|
||||
|
||||
@@ -88,6 +88,114 @@ void MainTabs::handle_event(const String &event, const Vector<Variant> &args)
|
||||
brushes->add_item(brush_data[id], id);
|
||||
be = be->next();
|
||||
}
|
||||
} else if (event == "road_lines_editor_set_ui_cursor_position") {
|
||||
LineEdit *cursor_x =
|
||||
Object::cast_to<LineEdit>(ui_data["cursor_x"]);
|
||||
LineEdit *cursor_y =
|
||||
Object::cast_to<LineEdit>(ui_data["cursor_y"]);
|
||||
LineEdit *cursor_z =
|
||||
Object::cast_to<LineEdit>(ui_data["cursor_z"]);
|
||||
Vector3 position = args[0];
|
||||
cursor_x->set_text(String::num(position.x));
|
||||
cursor_y->set_text(String::num(position.y));
|
||||
cursor_z->set_text(String::num(position.z));
|
||||
} else if (event == "road_lines_editor_set_ui_point_position") {
|
||||
LineEdit *point_x =
|
||||
Object::cast_to<LineEdit>(ui_data["point_x"]);
|
||||
LineEdit *point_y =
|
||||
Object::cast_to<LineEdit>(ui_data["point_y"]);
|
||||
LineEdit *point_z =
|
||||
Object::cast_to<LineEdit>(ui_data["point_z"]);
|
||||
Vector3 position = args[0];
|
||||
point_x->set_text(String::num(position.x));
|
||||
point_y->set_text(String::num(position.y));
|
||||
point_z->set_text(String::num(position.z));
|
||||
} else if (event == "road_lines_set_cursor_position") {
|
||||
LineEdit *cursor_x =
|
||||
Object::cast_to<LineEdit>(ui_data["cursor_x"]);
|
||||
LineEdit *cursor_y =
|
||||
Object::cast_to<LineEdit>(ui_data["cursor_y"]);
|
||||
LineEdit *cursor_z =
|
||||
Object::cast_to<LineEdit>(ui_data["cursor_z"]);
|
||||
Vector3 position;
|
||||
position.x = cursor_x->get_text().to_float();
|
||||
position.y = cursor_y->get_text().to_float();
|
||||
position.z = cursor_z->get_text().to_float();
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_set_cursor_position",
|
||||
varray(position));
|
||||
} else if (event == "road_lines_set_point_position") {
|
||||
LineEdit *point_x =
|
||||
Object::cast_to<LineEdit>(ui_data["point_x"]);
|
||||
LineEdit *point_y =
|
||||
Object::cast_to<LineEdit>(ui_data["point_y"]);
|
||||
LineEdit *point_z =
|
||||
Object::cast_to<LineEdit>(ui_data["point_z"]);
|
||||
Vector3 position;
|
||||
position.x = point_x->get_text().to_float();
|
||||
position.y = point_y->get_text().to_float();
|
||||
position.z = point_z->get_text().to_float();
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_editor_set_point_position",
|
||||
varray(position));
|
||||
} else if (event == "road_lines_editor_update_lines_list") {
|
||||
const PoolVector<String> &elements = args[0];
|
||||
int selected_index = args[1];
|
||||
assert(ui_data.has("lines_list"));
|
||||
ItemList *lines_list =
|
||||
Object::cast_to<ItemList>(ui_data["lines_list"]);
|
||||
assert(lines_list);
|
||||
lines_list->clear();
|
||||
for (i = 0; i < (int)elements.size(); i++)
|
||||
lines_list->add_item(elements.read()[i]);
|
||||
if (selected_index >= 0)
|
||||
lines_list->set_current(selected_index);
|
||||
else
|
||||
lines_list->set_current(0);
|
||||
} else if (event == "road_lines_editor_update_line_index_ui") {
|
||||
String current_line = args[0];
|
||||
if (current_line.length() > 0) {
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
SpinBox *sp_line_index =
|
||||
Object::cast_to<SpinBox>(ui_data["line_index"]);
|
||||
int index = sp_line_index->get_value();
|
||||
sp_line_index->set_value(0);
|
||||
sp_line_index->set_max(
|
||||
rld->lines(current_line).points.size() - 1);
|
||||
sp_line_index->set_min(0);
|
||||
index = MIN(
|
||||
index,
|
||||
(int)rld->lines(current_line).points.size() -
|
||||
1);
|
||||
sp_line_index->set_value(index);
|
||||
}
|
||||
} else if (event == "road_lines_editor_clear_selected_line_ui") {
|
||||
SpinBox *sp_line_index =
|
||||
Object::cast_to<SpinBox>(ui_data["line_index"]);
|
||||
sp_line_index->set_value(0);
|
||||
} else if (event == "road_lines_editor_set_line_index_ui") {
|
||||
int index = args[0];
|
||||
SpinBox *sp_line_index =
|
||||
Object::cast_to<SpinBox>(ui_data["line_index"]);
|
||||
sp_line_index->set_value(0);
|
||||
sp_line_index->set_value(index);
|
||||
} else if (event == "road_lines_create_new_line_name:entered") {
|
||||
Control *dlg = Object::cast_to<Control>(
|
||||
ui_data["road_lines_create_new_line_dlg"]);
|
||||
dlg->hide();
|
||||
LineEdit *le = Object::cast_to<LineEdit>(args[0]);
|
||||
le->set_text("");
|
||||
} else if (event == "road_lines_create_new_cancel") {
|
||||
Control *dlg = Object::cast_to<Control>(
|
||||
ui_data["road_lines_create_new_line_dlg"]);
|
||||
dlg->hide();
|
||||
LineEdit *le = Object::cast_to<LineEdit>(
|
||||
ui_data["road_lines_create_new_line_name"]);
|
||||
le->set_text("");
|
||||
} else if (event == "road_lines_create_new_line_show") {
|
||||
Control *dlg = Object::cast_to<Control>(
|
||||
ui_data["road_lines_create_new_line_dlg"]);
|
||||
dlg->show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,13 +483,73 @@ void MainTabs::_notification(int which)
|
||||
"", "point_y",
|
||||
"", "point_z",
|
||||
"Set", "road_lines_set_point_position",
|
||||
"road_lines_create_new_line_dlg",
|
||||
"", "road_lines_create_new_line_name",
|
||||
"Cancel", "road_lines_create_new_cancel"
|
||||
/* clang-format on */
|
||||
};
|
||||
HashMap<String, Object *> save_data;
|
||||
ui_field::ui_field_builder(
|
||||
this, tab,
|
||||
"v{p#!{v{lh#!{m#!m#!m#!m#!m#!}_lh{le#!}i.#!x#!_lv#!{h{e#!e#!e#!b#!}}_lv#!{h{e#!e#!e#!b#!}}}}}",
|
||||
"v{p#!{v{lh#!{m#!m#!m#!m#!m#!}_lh{le#!$}i.#!$x#!$_lv#!{h{e#!$e#!$e#!$b#$}}_lv#!{h{e#!$e#!$e#!$b#$}}}}p#!${v{e#!$b#!$}}}",
|
||||
// "p{v{lh#!{m#!m#!m#!m#!m#!}_lh{le#!}i.#!x#!_lv#!{h{e#!e#!e#!b#!}}_lv#!{h{e#!e#!e#!b#!}}}}",
|
||||
args_data.data(), args_data.size());
|
||||
args_data.data(), args_data.size(),
|
||||
&save_data);
|
||||
std::vector<String> elements = {
|
||||
"cursor_x",
|
||||
"cursor_y",
|
||||
"cursor_z",
|
||||
"road_lines_set_cursor_position",
|
||||
"point_x",
|
||||
"point_y",
|
||||
"point_z",
|
||||
"road_lines_set_point_position",
|
||||
"lines_list",
|
||||
"road_lines_filter",
|
||||
"line_index",
|
||||
"road_lines_create_new_line_dlg",
|
||||
"road_lines_create_new_line_name",
|
||||
"road_lines_create_new_cancel"
|
||||
};
|
||||
int el;
|
||||
for (el = 0; el < (int)elements.size(); el++) {
|
||||
String elname = elements[el];
|
||||
assert(save_data.has(elname));
|
||||
ui_data[elname] = save_data[elname];
|
||||
Button *button =
|
||||
Object::cast_to<Button>(
|
||||
ui_data[elname]);
|
||||
if (button)
|
||||
memnew(ButtonPressHandler(
|
||||
button, elname));
|
||||
if (elname == "road_lines_filter") {
|
||||
LineEdit *le = Object::cast_to<
|
||||
LineEdit>(
|
||||
ui_data[elname]);
|
||||
memnew(LineEditString(le,
|
||||
elname));
|
||||
}
|
||||
if (elname == "line_index") {
|
||||
SpinBox *sb =
|
||||
Object::cast_to<SpinBox>(
|
||||
ui_data[elname]);
|
||||
memnew(SpinBoxHandler(
|
||||
sb,
|
||||
"road_lines_editor_set_line_index"));
|
||||
}
|
||||
if (elname ==
|
||||
"road_lines_create_new_line_name") {
|
||||
LineEdit *le = Object::cast_to<
|
||||
LineEdit>(
|
||||
ui_data[elname]);
|
||||
memnew(LineEditEnterString(
|
||||
le,
|
||||
elname + ":entered"));
|
||||
memnew(LineEditString(
|
||||
le,
|
||||
elname + ":changed"));
|
||||
}
|
||||
};
|
||||
} break;
|
||||
case 5: {
|
||||
std::vector<Variant> args_data = {
|
||||
|
||||
@@ -8,6 +8,7 @@ class MainTabs : public TabContainer {
|
||||
Vector<Object *> handlers;
|
||||
WindowDialog *npc_editor;
|
||||
WindowDialog *building_layouts_editor;
|
||||
HashMap<String, Object *> ui_data;
|
||||
template <class T>
|
||||
inline void mode_visibility(int mode, const String &path);
|
||||
void handle_event(const String &event, const Vector<Variant> &args);
|
||||
|
||||
@@ -97,10 +97,8 @@ public:
|
||||
break;
|
||||
case 21:
|
||||
/* Create line */
|
||||
editor->get_as_node<Control>("%road_lines_base")->hide();
|
||||
editor->get_as_node<Control>(
|
||||
"%road_lines_create_new_line_dlg")
|
||||
->show();
|
||||
EditorEvent::get_singleton()->event.emit(
|
||||
"road_lines_create_new_line_show", varray());
|
||||
break;
|
||||
case 22:
|
||||
/* delete line */
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "base_data.h"
|
||||
#include "buildings_editor.h"
|
||||
#include "terrain_editor.h"
|
||||
#include "npc/npc_editor.h"
|
||||
#include "world_editor.h"
|
||||
|
||||
class HandleCommandButton : public Object {
|
||||
@@ -79,6 +80,7 @@ WorldEditor::WorldEditor()
|
||||
, road_lines_editor(memnew(RoadLinesEditor(this)))
|
||||
, buildings_editor(memnew(BuildingsEditor(this)))
|
||||
, terrain_editor(memnew(TerrainEditor(this)))
|
||||
, npc_editor(memnew(NPCEditor(this)))
|
||||
{
|
||||
flecs::entity e;
|
||||
flecs::world ecs = BaseData::get_singleton()->get();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
class RoadLinesEditor;
|
||||
class BuildingsEditor;
|
||||
class TerrainEditor;
|
||||
class NPCEditor;
|
||||
class WorldEditor : public Spatial {
|
||||
GDCLASS(WorldEditor, Spatial)
|
||||
protected:
|
||||
@@ -42,6 +43,7 @@ private:
|
||||
RoadLinesEditor *road_lines_editor;
|
||||
BuildingsEditor *buildings_editor;
|
||||
TerrainEditor *terrain_editor;
|
||||
NPCEditor *npc_editor;
|
||||
|
||||
public:
|
||||
enum {
|
||||
|
||||
Reference in New Issue
Block a user