|
|
|
@@ -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");
|
|
|
|
|
}
|