Started buildings layout editor

This commit is contained in:
2024-10-05 03:35:32 +03:00
parent db39715354
commit 166e6d6b4a
12 changed files with 2129 additions and 7 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
extends Spatial
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View File

@@ -0,0 +1,306 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://main/building_layout_editor.gd" type="Script" id=1]
[ext_resource path="res://astream/building-layouts/building-elements.glb" type="PackedScene" id=2]
[sub_resource type="CubeMesh" id=1]
size = Vector3( 40, 1, 40 )
[node name="building_layout_editor" type="Spatial"]
script = ExtResource( 1 )
[node name="menu_panel" type="HBoxContainer" parent="."]
unique_name_in_owner = true
margin_right = 1024.0
margin_bottom = 20.0
[node name="FileMenu" type="MenuButton" parent="menu_panel"]
margin_right = 35.0
margin_bottom = 20.0
text = "File"
items = [ "Save", null, 0, false, false, 100, 0, null, "", false ]
switch_on_hover = true
[node name="ElementMenu" type="MenuButton" parent="menu_panel"]
margin_left = 39.0
margin_right = 104.0
margin_bottom = 20.0
focus_mode = 2
text = "Element"
items = [ "Layout...", null, 0, false, false, 200, 0, null, "", false, "Element types...", null, 0, false, false, 201, 0, null, "", false, "Elements...", null, 0, false, false, 202, 0, null, "", false, "", null, 0, false, true, 3, 0, null, "", true ]
switch_on_hover = true
[node name="ExteriorMenu" type="MenuButton" parent="menu_panel"]
margin_left = 108.0
margin_right = 169.0
margin_bottom = 20.0
focus_mode = 2
text = "Exterior"
switch_on_hover = true
[node name="InteriorMenu" type="MenuButton" parent="menu_panel"]
margin_left = 173.0
margin_right = 233.0
margin_bottom = 20.0
focus_mode = 2
text = "Interior"
switch_on_hover = true
[node name="MeshInstance" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0 )
mesh = SubResource( 1 )
[node name="DirectionalLight" type="DirectionalLight" parent="."]
transform = Transform( 1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 100, 0 )
[node name="Camera" type="Camera" parent="."]
transform = Transform( 0.707107, 0.5, -0.5, 0, 0.707107, 0.707107, 0.707107, -0.5, 0.5, -25, 25, 25 )
[node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_left = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -314.0
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"]
margin_right = 314.0
margin_bottom = 4.0
[node name="Label" type="Label" parent="VBoxContainer"]
margin_top = 8.0
margin_right = 314.0
margin_bottom = 22.0
text = "Properties"
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
margin_top = 26.0
margin_right = 314.0
margin_bottom = 30.0
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"]
margin_top = 34.0
margin_right = 314.0
margin_bottom = 134.0
rect_min_size = Vector2( 0, 100 )
size_flags_vertical = 3
scroll_horizontal_enabled = false
[node name="layout_mesh_buttons" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"]
unique_name_in_owner = true
margin_right = 302.0
margin_bottom = 168.0
rect_min_size = Vector2( 100, 0 )
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="socket_editor" type="PanelContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 138.0
margin_right = 314.0
margin_bottom = 420.0
[node name="v" type="VBoxContainer" parent="VBoxContainer/socket_editor"]
margin_left = 7.0
margin_top = 7.0
margin_right = 307.0
margin_bottom = 275.0
[node name="socket_new_element" type="Button" parent="VBoxContainer/socket_editor/v"]
unique_name_in_owner = true
margin_right = 300.0
margin_bottom = 20.0
text = "New Element Type"
[node name="socket_new_element_name" type="LineEdit" parent="VBoxContainer/socket_editor/v"]
unique_name_in_owner = true
margin_top = 24.0
margin_right = 300.0
margin_bottom = 48.0
[node name="element_type_list" type="ItemList" parent="VBoxContainer/socket_editor/v"]
unique_name_in_owner = true
margin_top = 52.0
margin_right = 300.0
margin_bottom = 112.0
rect_min_size = Vector2( 0, 60 )
items = [ "Item 0", null, false, "Item 1", null, false, "Item 2", null, false, "Item 3", null, false ]
[node name="socket_list" type="ItemList" parent="VBoxContainer/socket_editor/v"]
unique_name_in_owner = true
margin_top = 116.0
margin_right = 300.0
margin_bottom = 176.0
rect_min_size = Vector2( 0, 60 )
items = [ "floor", null, false, "west_wall", null, false, "east_wall", null, false, "north_wall", null, false, "south_wall", null, false, "diagonal_wall", null, false, "diagonal2_wall", null, false ]
[node name="socket_transform_editor" type="VBoxContainer" parent="VBoxContainer/socket_editor/v"]
unique_name_in_owner = true
margin_top = 180.0
margin_right = 300.0
margin_bottom = 268.0
[node name="offset_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor"]
margin_right = 300.0
margin_bottom = 14.0
text = "Offset"
[node name="socket_editor_offset_base" type="HBoxContainer" parent="VBoxContainer/socket_editor/v/socket_transform_editor"]
unique_name_in_owner = true
margin_top = 18.0
margin_right = 300.0
margin_bottom = 42.0
[node name="x_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_top = 5.0
margin_right = 8.0
margin_bottom = 19.0
text = "X"
[node name="x_edit" type="LineEdit" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_left = 12.0
margin_right = 85.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="y_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_left = 89.0
margin_top = 5.0
margin_right = 96.0
margin_bottom = 19.0
text = "Y"
[node name="y_edit" type="LineEdit" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_left = 100.0
margin_right = 174.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="z_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_left = 178.0
margin_top = 5.0
margin_right = 186.0
margin_bottom = 19.0
text = "Z"
[node name="z_edit" type="LineEdit" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_left = 190.0
margin_right = 263.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="set" type="Button" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_offset_base"]
margin_left = 267.0
margin_right = 299.0
margin_bottom = 24.0
text = "Set"
[node name="rotation_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor"]
margin_top = 46.0
margin_right = 300.0
margin_bottom = 60.0
text = "Rotation"
[node name="socket_editor_rotation_base" type="HBoxContainer" parent="VBoxContainer/socket_editor/v/socket_transform_editor"]
unique_name_in_owner = true
margin_top = 64.0
margin_right = 300.0
margin_bottom = 88.0
[node name="x_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_top = 5.0
margin_right = 8.0
margin_bottom = 19.0
text = "X"
[node name="x_edit" type="LineEdit" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_left = 12.0
margin_right = 85.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="y_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_left = 89.0
margin_top = 5.0
margin_right = 96.0
margin_bottom = 19.0
text = "Y"
[node name="y_edit" type="LineEdit" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_left = 100.0
margin_right = 174.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="z_label" type="Label" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_left = 178.0
margin_top = 5.0
margin_right = 186.0
margin_bottom = 19.0
text = "Z"
[node name="z_edit" type="LineEdit" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_left = 190.0
margin_right = 263.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="set" type="Button" parent="VBoxContainer/socket_editor/v/socket_transform_editor/socket_editor_rotation_base"]
margin_left = 267.0
margin_right = 299.0
margin_bottom = 24.0
text = "Set"
[node name="element_editor" type="PanelContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 424.0
margin_right = 314.0
margin_bottom = 691.0
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/element_editor"]
margin_left = 7.0
margin_top = 7.0
margin_right = 307.0
margin_bottom = 260.0
[node name="element_new_element" type="Button" parent="VBoxContainer/element_editor/VBoxContainer"]
unique_name_in_owner = true
margin_right = 300.0
margin_bottom = 20.0
text = "New element"
[node name="element_new_element_name" type="LineEdit" parent="VBoxContainer/element_editor/VBoxContainer"]
unique_name_in_owner = true
margin_top = 24.0
margin_right = 300.0
margin_bottom = 48.0
[node name="element_list" type="ItemList" parent="VBoxContainer/element_editor/VBoxContainer"]
unique_name_in_owner = true
margin_top = 52.0
margin_right = 300.0
margin_bottom = 97.0
rect_min_size = Vector2( 0, 45 )
[node name="element_type_select" type="OptionButton" parent="VBoxContainer/element_editor/VBoxContainer"]
unique_name_in_owner = true
margin_top = 101.0
margin_right = 300.0
margin_bottom = 121.0
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/element_editor/VBoxContainer"]
margin_top = 125.0
margin_right = 300.0
margin_bottom = 253.0
rect_min_size = Vector2( 300, 128 )
size_flags_horizontal = 3
[node name="element_mesh_select" type="GridContainer" parent="VBoxContainer/element_editor/VBoxContainer/ScrollContainer"]
unique_name_in_owner = true
margin_right = 300.0
margin_bottom = 128.0
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 2
[node name="BuildingLayoutEditor" type="BuildingLayoutEditor" parent="."]
source = ExtResource( 2 )

View File

@@ -3,12 +3,15 @@
Import("env")
Import("env_modules")
env_stream = env_modules.Clone()
# Godot source files
module_obj = []
SConscript("buildings/SCsub")
env_stream.add_source_files(module_obj, "*.cpp")
env_stream.add_source_files(module_obj, "flecs/*.c")
env.modules_sources += module_obj

View File

@@ -0,0 +1,16 @@
Import("env")
Import("env_modules")
#env_modules.stream_building_sources = []
#
#env_modules.add_source_files(env_modules.stream_building_sources, "*.cpp")
#
#lib = env_modules.add_library("buildings", env_modules.stream_building_sources)
#env_modules.Prepend(LIBS=[lib])
env.stream_building_sources = []
env.add_source_files(env.stream_building_sources, "*.cpp")
lib = env.add_library("buildings", env.stream_building_sources)
env.Prepend(LIBS=[lib])

View File

@@ -0,0 +1,659 @@
#undef NDEBUG
#include <cassert>
#include <main/main.h>
#include <core/engine.h>
#include <scene/resources/packed_scene.h>
#include <scene/3d/mesh_instance.h>
#include <scene/gui/box_container.h>
#include <scene/gui/texture_button.h>
#include <scene/gui/option_button.h>
#include <scene/gui/label.h>
#include <scene/gui/button.h>
#include <scene/gui/menu_button.h>
#include <editor/editor_node.h>
#include "building_layout_editor.h"
/* Taken from Godot code editor/editor_plugin.cpp */
BuildingLayoutEditor::BuildingLayoutEditor()
: meshes_ready(false)
, current_mode(-1)
, current_element_type("")
, current_element("")
, current_socket(-1)
{
}
template <class T> T *get_as_node(const String &path)
{
Node *scene;
if (Engine::get_singleton()->is_editor_hint())
scene = EditorNode::get_singleton()->get_edited_scene();
else
scene = SceneTree::get_singleton()->get_current_scene();
assert(scene);
Node *node = scene->get_node(NodePath(path));
if (!node)
print_error("Failed to get " + path);
assert(node);
T *ret = Object::cast_to<T>(node);
if (!ret)
print_error("Failed to assign " + path);
assert(ret);
return ret;
}
Vector<Ref<Texture> >
BuildingLayoutEditor::make_mesh_previews(const Vector<Ref<Mesh> > &p_meshes,
Vector<Transform> *p_transforms,
int p_preview_size)
{
int size = p_preview_size;
RID scenario = RID_PRIME(VS::get_singleton()->scenario_create());
RID viewport = RID_PRIME(VS::get_singleton()->viewport_create());
VS::get_singleton()->viewport_set_update_mode(
viewport, VS::VIEWPORT_UPDATE_ALWAYS);
VS::get_singleton()->viewport_set_vflip(viewport, true);
VS::get_singleton()->viewport_set_scenario(viewport, scenario);
VS::get_singleton()->viewport_set_size(viewport, size, size);
VS::get_singleton()->viewport_set_transparent_background(viewport,
true);
VS::get_singleton()->viewport_set_active(viewport, true);
RID viewport_texture =
VS::get_singleton()->viewport_get_texture(viewport);
RID camera = RID_PRIME(VS::get_singleton()->camera_create());
VS::get_singleton()->viewport_attach_camera(viewport, camera);
RID light = RID_PRIME(VS::get_singleton()->directional_light_create());
RID light_instance =
VS::get_singleton()->instance_create2(light, scenario);
RID light2 = VS::get_singleton()->directional_light_create();
VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
RID light_instance2 =
VS::get_singleton()->instance_create2(light2, scenario);
Vector<Ref<Texture> > textures;
for (int i = 0; i < p_meshes.size(); i++) {
Ref<Mesh> mesh = p_meshes[i];
if (!mesh.is_valid()) {
textures.push_back(Ref<Texture>());
continue;
}
Transform mesh_xform;
if (p_transforms != nullptr) {
mesh_xform = (*p_transforms)[i];
}
RID inst = VS::get_singleton()->instance_create2(
mesh->get_rid(), scenario);
VS::get_singleton()->instance_set_transform(inst, mesh_xform);
AABB aabb = mesh->get_aabb();
Vector3 ofs = aabb.position + aabb.size * 0.5;
aabb.position -= ofs;
Transform xform;
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6);
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) *
xform.basis;
AABB rot_aabb = xform.xform(aabb);
float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5;
if (m == 0) {
textures.push_back(Ref<Texture>());
continue;
}
xform.origin = -xform.basis.xform(ofs); //-ofs*m;
xform.origin.z -= rot_aabb.size.z * 2;
xform.invert();
xform = mesh_xform * xform;
VS::get_singleton()->camera_set_transform(
camera, xform * Transform(Basis(), Vector3(0, 0, 3)));
VS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01,
1000.0);
VS::get_singleton()->instance_set_transform(
light_instance,
xform * Transform().looking_at(Vector3(-2, -1, -1),
Vector3(0, 1, 0)));
VS::get_singleton()->instance_set_transform(
light_instance2,
xform * Transform().looking_at(Vector3(+1, -1, -2),
Vector3(0, 1, 0)));
Main::iteration();
Main::iteration();
Ref<Image> img =
VS::get_singleton()->texture_get_data(viewport_texture);
ERR_CONTINUE(!img.is_valid() || img->empty());
Ref<ImageTexture> it(memnew(ImageTexture));
it->create_from_image(img);
VS::get_singleton()->free(inst);
textures.push_back(it);
}
VS::get_singleton()->free(viewport);
VS::get_singleton()->free(light);
VS::get_singleton()->free(light_instance);
VS::get_singleton()->free(light2);
VS::get_singleton()->free(light_instance2);
VS::get_singleton()->free(camera);
VS::get_singleton()->free(scenario);
return textures;
}
void BuildingLayoutEditor::set_source(const Ref<PackedScene> &src)
{
source = src;
if (is_inside_tree()) {
prepare_meshes();
meshes_ready = true;
update_mesh_buttons();
}
}
Ref<PackedScene> BuildingLayoutEditor::get_source() const
{
return source;
}
void BuildingLayoutEditor::_notification(int which)
{
switch (which) {
case NOTIFICATION_READY:
connect_signals();
if (!meshes_ready) {
prepare_meshes();
update_mesh_buttons();
}
select_mode(0);
break;
}
}
void BuildingLayoutEditor::prepare_meshes()
{
int i;
if (!source.is_valid())
return;
Vector<String> mesh_names;
Vector<Ref<Mesh> > preview_meshes;
Vector<Ref<Texture> > preview_textures;
Node *scene = source->instance();
List<Node *> queue;
queue.push_back(scene);
while (!queue.empty()) {
Node *item = queue.front()->get();
MeshInstance *mi = Object::cast_to<MeshInstance>(item);
if (mi) {
mesh_names.push_back(mi->get_name());
preview_meshes.push_back(mi->get_mesh());
}
queue.pop_front();
for (i = 0; i < item->get_child_count(); i++)
queue.push_back(item->get_child(i));
}
preview_textures = make_mesh_previews(preview_meshes, nullptr, 64);
assert(preview_textures.size() == preview_meshes.size());
if (scene)
scene->queue_delete();
for (i = 0; i < preview_meshes.size(); i++) {
struct mesh_data md;
md.mesh = preview_meshes[i];
md.mesh_name = mesh_names[i];
md.preview = preview_textures[i];
int poff = mesh_names[i].find_char('_');
if (poff < 0)
md.category = "unknown";
else
md.category = mesh_names[i].substr(0, poff);
meshes[mesh_names[i]] = md;
}
}
void BuildingLayoutEditor::update_mesh_buttons()
{
Node *layout_mesh_buttons = get_node(NodePath("%layout_mesh_buttons"));
List<String> mlist;
meshes.get_key_list(&mlist);
HashMap<String, Node *> categories;
List<String>::Element *e = mlist.front();
while (e) {
const struct mesh_data &md = meshes[e->get()];
if (!categories.has(md.category)) {
VBoxContainer *cat = memnew(VBoxContainer);
categories[md.category] = cat;
layout_mesh_buttons->add_child(cat);
}
Label *l = memnew(Label);
l->set_text(md.mesh_name);
categories[md.category]->add_child(l);
TextureButton *b = memnew(TextureButton);
b->set_normal_texture(md.preview);
b->set_pressed_texture(md.preview);
b->set_hover_texture(md.preview);
categories[md.category]->add_child(b);
e = e->next();
}
}
void BuildingLayoutEditor::_bind_methods()
{
ClassDB::bind_method(D_METHOD("set_source", "src"),
&BuildingLayoutEditor::set_source);
ClassDB::bind_method(D_METHOD("get_source"),
&BuildingLayoutEditor::get_source);
ClassDB::bind_method(D_METHOD("select_mode", "mode"),
&BuildingLayoutEditor::select_mode);
ClassDB::bind_method(D_METHOD("enter_name", "text"),
&BuildingLayoutEditor::enter_name);
ClassDB::bind_method(D_METHOD("enter_element_name", "text"),
&BuildingLayoutEditor::enter_element_name);
ClassDB::bind_method(D_METHOD("select_element_type", "element"),
&BuildingLayoutEditor::select_element_type);
ClassDB::bind_method(D_METHOD("select_element", "element"),
&BuildingLayoutEditor::select_element);
ClassDB::bind_method(D_METHOD("select_socket", "socket"),
&BuildingLayoutEditor::select_socket);
ClassDB::bind_method(D_METHOD("set_socket_offset"),
&BuildingLayoutEditor::set_socket_offset);
ClassDB::bind_method(D_METHOD("set_socket_rotation"),
&BuildingLayoutEditor::set_socket_rotation);
ClassDB::bind_method(D_METHOD("menu_control"),
&BuildingLayoutEditor::menu_control);
ClassDB::bind_method(D_METHOD("mesh_selected", "mesh_idx", "socket"),
&BuildingLayoutEditor::mesh_selected);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "source",
PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"),
"set_source", "get_source");
}
void BuildingLayoutEditor::connect_signals()
{
int i;
if (Engine::get_singleton()->is_editor_hint())
return;
get_as_node<Button>("%socket_new_element")
->connect("pressed", this, "enter_name", varray(""));
get_as_node<LineEdit>("%socket_new_element_name")
->connect("text_entered", this, "enter_name");
get_as_node<ItemList>("%element_type_list")
->connect("item_selected", this, "select_element_type");
get_as_node<ItemList>("%socket_list")
->connect("item_selected", this, "select_socket");
get_as_node<Button>("%socket_editor_offset_base/set")
->connect("pressed", this, "set_socket_offset");
get_as_node<Button>("%socket_editor_rotation_base/set")
->connect("pressed", this, "set_socket_rotation");
get_as_node<ItemList>("%element_list")
->connect("item_selected", this, "select_element");
get_as_node<Button>("%element_new_element")
->connect("pressed", this, "enter_element_name", varray(""));
get_as_node<LineEdit>("%element_new_element_name")
->connect("text_entered", this, "enter_element_name");
Node *menu_panel = get_node(NodePath("%menu_panel"));
for (i = 0; i < menu_panel->get_child_count(); i++) {
Node *m = menu_panel->get_child(i);
MenuButton *mb = Object::cast_to<MenuButton>(m);
mb->get_popup()->connect("id_pressed", this, "menu_control");
}
}
void BuildingLayoutEditor::select_mode(int mode)
{
int i;
List<String> element_keys;
List<String>::Element *e;
print_line("set mode: " + itos(mode));
if (Engine::get_singleton()->is_editor_hint())
return;
if (current_mode != mode) {
switch (current_mode) {
case 0:
break;
case 1:
break;
}
current_mode = mode;
switch (mode) {
case 0:
get_as_node<Control>("%socket_editor")->hide();
get_as_node<Control>("%element_editor")->hide();
if (elements.size() == 0)
print_error("No elements");
break;
case 1:
get_as_node<Control>("%element_editor")->hide();
get_as_node<ItemList>("%element_type_list")->clear();
print_line("Restoring UI");
element_keys.clear();
element_type.get_key_list(&element_keys);
e = element_keys.front();
while (e) {
get_as_node<ItemList>("%element_type_list")
->add_item(e->get());
print_line("Added item: " + e->get());
e = e->next();
}
get_as_node<ItemList>("%socket_list")->hide();
get_as_node<Control>("%socket_editor")->show();
get_as_node<LineEdit>("%socket_new_element_name")
->hide();
get_as_node<ItemList>("%socket_list")->hide();
get_as_node<Control>("%socket_transform_editor")->hide();
element_keys.clear();
break;
case 2:
if (element_type.size() == 0)
print_error("No element types");
get_as_node<Control>("%socket_editor")->hide();
get_as_node<Control>("%element_editor")->show();
get_as_node<LineEdit>("%element_new_element_name")
->hide();
get_as_node<ItemList>("%element_list")->clear();
print_line("Restoring UI");
element_keys.clear();
elements.get_key_list(&element_keys);
e = element_keys.front();
while (e) {
get_as_node<ItemList>("%element_list")
->add_item(e->get());
print_line("Added item: " + e->get());
e = e->next();
}
element_keys.clear();
element_type.get_key_list(&element_keys);
e = element_keys.front();
while (e) {
get_as_node<OptionButton>(
"%element_type_select")
->add_item(e->get());
print_line("Added item: " + e->get());
e = e->next();
}
get_as_node<ItemList>("%element_list")->select(0);
ItemList *sl = get_as_node<ItemList>("%socket_list");
Control *mb =
get_as_node<Control>("%element_mesh_select");
used_socket_count = sl->get_item_count();
if (mb->get_child_count() == 0) {
for (i = 0; i < used_socket_count; i++) {
String socket_name =
sl->get_item_text(i);
Label *label = memnew(Label);
label->set_text(socket_name);
OptionButton *ob = memnew(OptionButton);
mb->add_child(label);
mb->add_child(ob);
List<String> mesh_list;
meshes.get_key_list(&mesh_list);
List<String>::Element *me =
mesh_list.front();
ob->clear();
ob->add_item("");
int index = 1;
int selected = 0;
String selected_mesh;
if (elements.has(current_element))
selected_mesh =
elements[current_element]
.mesh_names[i];
while (me) {
if (selected_mesh == me->get())
selected = index;
ob->add_item(me->get());
ob->set_item_icon(
index,
meshes[me->get()]
.preview);
mesh_select_buttons[i] = ob;
me = me->next();
index++;
}
ob->select(selected);
ob->connect("item_selected", this,
"mesh_selected", varray(i));
}
}
select_element(0);
break;
}
}
}
void BuildingLayoutEditor::enter_name(const String &text)
{
bool added = false;
if (text == "") {
get_as_node<LineEdit>("%socket_new_element_name")->show();
get_as_node<LineEdit>("%socket_new_element_name")
->grab_click_focus();
get_as_node<LineEdit>("%socket_new_element_name")->grab_focus();
} else {
String key = text.strip_edges();
assert(!element_type.has(key));
if (!element_type.has(key)) {
struct grid_element_type g;
g.name = key;
element_type[key] = g;
get_as_node<ItemList>("%element_type_list")
->add_item(key);
added = true;
}
assert(added);
get_as_node<LineEdit>("%socket_new_element_name")->set_text("");
get_as_node<LineEdit>("%socket_new_element_name")
->release_focus();
get_as_node<LineEdit>("%socket_new_element_name")->hide();
if (added) {
get_as_node<ItemList>("%element_type_list")
->grab_click_focus();
get_as_node<ItemList>("%element_type_list")
->grab_focus();
}
}
}
void BuildingLayoutEditor::enter_element_name(const String &text)
{
bool added = false;
if (text == "") {
get_as_node<LineEdit>("%element_new_element_name")->show();
get_as_node<LineEdit>("%element_new_element_name")
->grab_click_focus();
get_as_node<LineEdit>("%element_new_element_name")->grab_focus();
} else {
String key = text.strip_edges();
assert(!elements.has(key));
if (!elements.has(key)) {
struct grid_element g;
g.name = key;
elements[key] = g;
get_as_node<ItemList>("%element_list")->add_item(key);
added = true;
}
assert(added);
get_as_node<LineEdit>("%element_new_element_name")->set_text("");
get_as_node<LineEdit>("%element_new_element_name")
->release_focus();
get_as_node<LineEdit>("%element_new_element_name")->hide();
if (added) {
get_as_node<ItemList>("%element_list")
->grab_click_focus();
get_as_node<ItemList>("%element_list")->grab_focus();
}
}
}
void BuildingLayoutEditor::select_element_type(int element)
{
String item = get_as_node<ItemList>("%element_type_list")
->get_item_text(element);
print_line("item: " + item);
current_element_type = item;
get_as_node<ItemList>("%socket_list")->show();
get_as_node<ItemList>("%socket_list")->select(0);
// just in case
select_socket(0);
}
void BuildingLayoutEditor::select_socket(int socket)
{
current_socket = socket;
String item =
get_as_node<ItemList>("%socket_list")->get_item_text(socket);
get_as_node<Control>("%socket_transform_editor")->show();
print_line("socket: " + item);
Vector3 f = element_type[current_element_type].sockets[socket].origin;
f = Vector3(Math::stepify(f.x, 0.01f), Math::stepify(f.y, 0.01f),
Math::stepify(f.z, 0.01f));
get_as_node<LineEdit>("%socket_editor_offset_base/x_edit")
->set_text(String::num(f.x));
get_as_node<LineEdit>("%socket_editor_offset_base/y_edit")
->set_text(String::num(f.y));
get_as_node<LineEdit>("%socket_editor_offset_base/z_edit")
->set_text(String::num(f.z));
Vector3 r = element_type[current_element_type]
.sockets[socket]
.basis.get_rotation_euler() *
180.0f / Math_PI;
r = Vector3(Math::stepify(r.x, 0.01f), Math::stepify(r.y, 0.01f),
Math::stepify(r.z, 0.01f));
get_as_node<LineEdit>("%socket_editor_rotation_base/x_edit")
->set_text(String::num(r.x));
get_as_node<LineEdit>("%socket_editor_rotation_base/y_edit")
->set_text(String::num(r.y));
get_as_node<LineEdit>("%socket_editor_rotation_base/z_edit")
->set_text(String::num(r.z));
}
void BuildingLayoutEditor::set_socket_offset()
{
float x = get_as_node<LineEdit>("%socket_editor_offset_base/x_edit")
->get_text()
.to_float();
x = Math::stepify(x, 0.01f);
float y = get_as_node<LineEdit>("%socket_editor_offset_base/y_edit")
->get_text()
.to_float();
y = Math::stepify(y, 0.01f);
float z = get_as_node<LineEdit>("%socket_editor_offset_base/z_edit")
->get_text()
.to_float();
z = Math::stepify(z, 0.01f);
element_type[current_element_type].sockets[current_socket].origin =
Vector3(x, y, z);
}
void BuildingLayoutEditor::set_socket_rotation()
{
float x = Math::stepify(get_as_node<LineEdit>(
"%socket_editor_rotation_base/x_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
float y = Math::stepify(get_as_node<LineEdit>(
"%socket_editor_rotation_base/y_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
float z = Math::stepify(get_as_node<LineEdit>(
"%socket_editor_rotation_base/z_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
Basis basis(Vector3(x, y, z));
element_type[current_element_type].sockets[current_socket].basis =
basis;
}
void BuildingLayoutEditor::menu_control(int id)
{
print_line("menu_control: " + itos(id));
switch (id) {
case 100:
save_data();
break;
case 200: // layout mode
get_as_node<Control>("%socket_editor")->hide();
select_mode(0);
break;
case 201: // element type editor
get_as_node<Control>("%socket_editor")->show();
select_mode(1);
break;
case 202: // element editor
get_as_node<Control>("%socket_editor")->hide();
select_mode(2);
break;
}
}
void BuildingLayoutEditor::select_element(int element)
{
int i, j;
print_line("selected element: " + itos(element));
String item =
get_as_node<ItemList>("%element_list")->get_item_text(element);
print_line("selected element: " + item);
current_element = item;
String type = elements[current_element].type;
if (type.length() > 0) {
OptionButton *b =
get_as_node<OptionButton>("%element_type_select");
for (i = 0; i < b->get_item_count(); i++) {
if (b->get_item_text(i) == type) {
b->select(i);
break;
}
}
} else {
OptionButton *b =
get_as_node<OptionButton>("%element_type_select");
elements[current_element].type = b->get_item_text(0);
}
int selected = 0;
for (i = 0; i < used_socket_count; i++) {
String selected_mesh = elements[current_element].mesh_names[i];
selected = 0;
for (j = 0; j < mesh_select_buttons[i]->get_item_count(); j++) {
String mesh_item =
mesh_select_buttons[i]->get_item_text(j);
if (mesh_item == selected_mesh) {
selected = j;
break;
}
}
print_line(itos(i) + ": selecting mesh: " + itos(selected));
mesh_select_buttons[i]->select(selected);
}
}
void BuildingLayoutEditor::mesh_selected(int mesh_idx, int socket)
{
OptionButton *ob = mesh_select_buttons[socket];
String mesh_name =
Object::cast_to<OptionButton>(ob)->get_item_text(mesh_idx);
if (mesh_name.length() > 0) {
elements[current_element].mesh_names[socket] = mesh_name;
} else {
elements[current_element].mesh_names[socket] = "";
}
}
void BuildingLayoutEditor::save_data()
{
print_line("save_data");
}

View File

@@ -0,0 +1,61 @@
#include <scene/main/node.h>
#include <scene/resources/packed_scene.h>
class Mesh;
class OptionButton;
class BuildingLayoutEditor : public Node {
GDCLASS(BuildingLayoutEditor, Node);
Ref<PackedScene> source;
struct mesh_data {
Ref<Mesh> mesh;
String mesh_name;
String category;
Ref<Texture> preview;
};
HashMap<String, struct mesh_data> meshes;
HashMap<int, OptionButton *> mesh_select_buttons;
int used_socket_count;
#define ELEMENT_SOCKETS 16
struct grid_element_type {
String name;
Transform sockets[ELEMENT_SOCKETS];
};
struct grid_element {
String name;
String type;
String mesh_names[ELEMENT_SOCKETS];
};
HashMap<String, struct grid_element_type> element_type;
HashMap<String, struct grid_element> elements;
bool meshes_ready;
int current_mode;
String current_element_type;
String current_element;
int current_socket;
public:
BuildingLayoutEditor();
Vector<Ref<Texture> >
make_mesh_previews(const Vector<Ref<Mesh> > &p_meshes,
Vector<Transform> *p_transforms, int p_preview_size);
void set_source(const Ref<PackedScene> &src);
Ref<PackedScene> get_source() const;
protected:
void _notification(int which);
void prepare_meshes();
void update_mesh_buttons();
static void _bind_methods();
void connect_signals();
void select_mode(int mode);
void enter_name(const String &text);
void enter_element_name(const String &text);
void select_element_type(int element);
void select_socket(int socket);
void set_socket_offset();
void set_socket_rotation();
void menu_control(int id);
void select_element(int element);
void mesh_selected(int mesh_idx, int socket);
void save_data();
};

View File

@@ -4,6 +4,7 @@
#include "world_editor.h"
#include "nav_panel.h"
#include "line_metadata_editor.h"
#include "buildings/building_layout_editor.h"
void register_stream_types()
{
@@ -12,6 +13,7 @@ void register_stream_types()
ClassDB::register_class<WorldEditor>();
ClassDB::register_class<NavPanel>();
ClassDB::register_class<LineMetadataEditor>();
ClassDB::register_class<BuildingLayoutEditor>();
}
void unregister_stream_types()

View File

@@ -703,13 +703,6 @@ void RoadLinesData::update_road_lines_nodes(
nidx) == ::lines[r].indices.end());
::lines.insert_line_index(k, i + 1, nidx);
::lines.insert_line_index(r, j + 1, nidx);
#if 0
// FIXME: WTF???
::lines[k].indices.insert(
::lines[k].indices.begin() + i + 1, nidx);
::lines[r].indices.insert(
::lines[k].indices.begin() + j + 1, nidx);
#endif
}
}
}