Almost separated the buildings editor
This commit is contained in:
@@ -10,9 +10,9 @@ onready var vmode = {
|
||||
7: $"%v_npc",
|
||||
}
|
||||
|
||||
func change_building_type(index):
|
||||
var item = $"%building_type".get_item_text(index)
|
||||
$WorldEditor.editor_command("change_building_type", [selected_building, item])
|
||||
#func change_building_type(index):
|
||||
# var item = $"%building_type".get_item_text(index)
|
||||
# $WorldEditor.editor_command("change_building_type", [selected_building, item])
|
||||
|
||||
func _ready():
|
||||
for b in [
|
||||
@@ -27,9 +27,9 @@ func _ready():
|
||||
$WorldEditor.connect("editor_event", self, "editor_event")
|
||||
for k in vmode.keys():
|
||||
vmode[k].hide()
|
||||
$building_cursor.hide()
|
||||
$"%building_cursor".hide()
|
||||
$"%line_cursor".hide()
|
||||
$"%building_type".connect("item_selected", self, "change_building_type")
|
||||
# $"%building_type".connect("item_selected", self, "change_building_type")
|
||||
|
||||
func editor_event(evname: String, args: Array):
|
||||
print(evname, args)
|
||||
@@ -49,8 +49,9 @@ func editor_event(evname: String, args: Array):
|
||||
elif mode_next == 6:
|
||||
$WorldEditor.editor_command("get_lines_list", [])
|
||||
elif evname == "result:get_closest_building":
|
||||
print(evname, args)
|
||||
select_building(args[0], args[3], args[4])
|
||||
pass
|
||||
# print(evname, args)
|
||||
# select_building(args[0], args[3], args[4])
|
||||
elif evname == "result:get_building_types":
|
||||
print(evname, args)
|
||||
var btypes = args[0]
|
||||
@@ -63,9 +64,11 @@ func editor_event(evname: String, args: Array):
|
||||
# elif evname == "edit_update_building":
|
||||
# check_edit_building()
|
||||
elif evname == "mouse_press":
|
||||
mouse_press(args[0])
|
||||
pass
|
||||
# mouse_press(args[0])
|
||||
elif evname == "mouse_drag":
|
||||
mouse_drag(args[0])
|
||||
pass
|
||||
# mouse_drag(args[0])
|
||||
elif evname == "mouse_drag_on":
|
||||
pass
|
||||
elif evname == "mouse_drag_off":
|
||||
@@ -74,87 +77,87 @@ func editor_event(evname: String, args: Array):
|
||||
pass
|
||||
else:
|
||||
breakpoint
|
||||
func mouse_drag(position):
|
||||
if $WorldEditor.get_current_mode() != 2:
|
||||
return
|
||||
if $WorldEditor.get_camera_mode() != 3:
|
||||
return
|
||||
# breakpoint
|
||||
var camera = get_viewport().get_camera()
|
||||
var start = camera.project_ray_origin(position)
|
||||
var normal = camera.project_ray_normal(position)
|
||||
var end = start + normal * camera.get_zfar()
|
||||
var space_state = get_world().direct_space_state
|
||||
var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
||||
if result.has("collider"):
|
||||
var proj = result.position
|
||||
var mode = $"%buildings_edit_mode".selected
|
||||
if mode == 1:
|
||||
# move
|
||||
print(proj)
|
||||
var newpos = proj
|
||||
newpos.x = stepify(newpos.x, 2.0)
|
||||
newpos.z = stepify(newpos.z, 2.0)
|
||||
var gen: VoxelGeneratorImgMapper = $VoxelLodTerrain.generator
|
||||
var hpos = gen.get_height_full(newpos)
|
||||
newpos.y = hpos
|
||||
$WorldEditor.editor_command("update_building_transform", [selected_building, Transform(selected_building_xform.basis, newpos)])
|
||||
selected_building_xform = Transform(selected_building_xform.basis, newpos)
|
||||
$building_cursor.global_transform.origin = newpos
|
||||
elif mode == 2:
|
||||
# rotate
|
||||
var m = proj
|
||||
m.y = selected_building_xform.origin.y
|
||||
var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
||||
$WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
||||
$building_rot_cursor.global_transform = xform
|
||||
selected_building_xform = xform
|
||||
func mouse_press(position):
|
||||
if $WorldEditor.get_current_mode() != 2:
|
||||
return
|
||||
if $WorldEditor.get_camera_mode() != 3:
|
||||
return
|
||||
# breakpoint
|
||||
# dragging = true
|
||||
var camera = get_viewport().get_camera()
|
||||
var start = camera.project_ray_origin(position)
|
||||
var normal = camera.project_ray_normal(position)
|
||||
var end = start + normal * camera.get_zfar()
|
||||
var space_state = get_world().direct_space_state
|
||||
var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
||||
if result.has("collider"):
|
||||
var proj = result.position
|
||||
drag_start = proj
|
||||
var mode = $"%buildings_edit_mode".selected
|
||||
if mode == 0:
|
||||
print("get closest building")
|
||||
$WorldEditor.editor_command("get_closest_building", [Transform(Basis(), proj)])
|
||||
elif mode == 1:
|
||||
$WorldEditor.editor_command("checkpoint", [])
|
||||
elif mode == 2:
|
||||
$WorldEditor.editor_command("checkpoint", [])
|
||||
var m = proj
|
||||
m.y = selected_building_xform.origin.y
|
||||
var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
||||
$WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
||||
$building_rot_cursor.global_transform = xform
|
||||
selected_building_xform = xform
|
||||
#func mouse_drag(position):
|
||||
# if $WorldEditor.get_current_mode() != 2:
|
||||
# return
|
||||
# if $WorldEditor.get_camera_mode() != 3:
|
||||
# return
|
||||
## breakpoint
|
||||
# var camera = get_viewport().get_camera()
|
||||
# var start = camera.project_ray_origin(position)
|
||||
# var normal = camera.project_ray_normal(position)
|
||||
# var end = start + normal * camera.get_zfar()
|
||||
# var space_state = get_world().direct_space_state
|
||||
# var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
||||
# if result.has("collider"):
|
||||
# var proj = result.position
|
||||
# var mode = $"%buildings_edit_mode".selected
|
||||
# if mode == 1:
|
||||
# # move
|
||||
# print(proj)
|
||||
# var newpos = proj
|
||||
# newpos.x = stepify(newpos.x, 2.0)
|
||||
# newpos.z = stepify(newpos.z, 2.0)
|
||||
# var gen: VoxelGeneratorImgMapper = $"%VoxelLodTerrain".generator
|
||||
# var hpos = gen.get_height_full(newpos)
|
||||
# newpos.y = hpos
|
||||
# $WorldEditor.editor_command("update_building_transform", [selected_building, Transform(selected_building_xform.basis, newpos)])
|
||||
# selected_building_xform = Transform(selected_building_xform.basis, newpos)
|
||||
# $"%building_cursor".global_transform.origin = newpos
|
||||
# elif mode == 2:
|
||||
# # rotate
|
||||
# var m = proj
|
||||
# m.y = selected_building_xform.origin.y
|
||||
# var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
||||
# $WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
||||
# $"%building_rot_cursor".global_transform = xform
|
||||
# selected_building_xform = xform
|
||||
#func mouse_press(position):
|
||||
# if $WorldEditor.get_current_mode() != 2:
|
||||
# return
|
||||
# if $WorldEditor.get_camera_mode() != 3:
|
||||
# return
|
||||
## breakpoint
|
||||
## dragging = true
|
||||
# var camera = get_viewport().get_camera()
|
||||
# var start = camera.project_ray_origin(position)
|
||||
# var normal = camera.project_ray_normal(position)
|
||||
# var end = start + normal * camera.get_zfar()
|
||||
# var space_state = get_world().direct_space_state
|
||||
# var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
||||
# if result.has("collider"):
|
||||
# var proj = result.position
|
||||
# drag_start = proj
|
||||
# var mode = $"%buildings_edit_mode".selected
|
||||
# if mode == 0:
|
||||
# print("get closest building")
|
||||
# $WorldEditor.editor_command("get_closest_building", [Transform(Basis(), proj)])
|
||||
# elif mode == 1:
|
||||
# $WorldEditor.editor_command("checkpoint", [])
|
||||
# elif mode == 2:
|
||||
# $WorldEditor.editor_command("checkpoint", [])
|
||||
# var m = proj
|
||||
# m.y = selected_building_xform.origin.y
|
||||
# var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
||||
# $WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
||||
# $"%building_rot_cursor".global_transform = xform
|
||||
# selected_building_xform = xform
|
||||
|
||||
var selected_building
|
||||
#var selected_building
|
||||
var selected_building_xform
|
||||
func select_building(xform, id, mid):
|
||||
selected_building = id
|
||||
selected_building_xform = xform
|
||||
print("selected id: ", id)
|
||||
$WorldEditor.select_building(xform, id, mid)
|
||||
#func select_building(xform, id, mid):
|
||||
# selected_building = id
|
||||
# selected_building_xform = xform
|
||||
# print("selected id: ", id)
|
||||
# $WorldEditor.select_building(xform, id, mid)
|
||||
# for h in range($"%building_type".get_item_count()):
|
||||
# var item = $"%building_type".get_item_text(h)
|
||||
# if item == mid:
|
||||
# $"%building_type".select(h)
|
||||
# break
|
||||
if !$building_cursor.visible:
|
||||
$building_cursor.show()
|
||||
$building_cursor.global_transform.origin = xform.origin
|
||||
# if !$"%building_cursor".visible:
|
||||
# $"%building_cursor".show()
|
||||
# $"%building_cursor".global_transform.origin = xform.origin
|
||||
func _process(delta):
|
||||
# if Input.is_action_just_pressed("editor_cam1"):
|
||||
# setup_cam1()
|
||||
@@ -163,13 +166,13 @@ func _process(delta):
|
||||
# if Input.is_action_just_pressed("editor_cam3"):
|
||||
# setup_cam3()
|
||||
var mode = $"%buildings_edit_mode".selected
|
||||
if mode == 2:
|
||||
$building_rot_cursor.global_transform = selected_building_xform
|
||||
if !$building_rot_cursor.visible:
|
||||
$building_rot_cursor.show()
|
||||
else:
|
||||
if $building_rot_cursor.visible:
|
||||
$building_rot_cursor.hide()
|
||||
# if mode == 2:
|
||||
# $"%building_rot_cursor".global_transform = selected_building_xform
|
||||
# if !$"%building_rot_cursor".visible:
|
||||
# $"%building_rot_cursor".show()
|
||||
# else:
|
||||
# if $"%building_rot_cursor".visible:
|
||||
# $"%building_rot_cursor".hide()
|
||||
# if dragging:
|
||||
# if !Input.is_action_pressed("mouse1"):
|
||||
# dragging = false
|
||||
|
||||
@@ -116,7 +116,7 @@ text = "NPC Mode"
|
||||
unique_name_in_owner = true
|
||||
margin_top = 154.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 298.0
|
||||
margin_bottom = 322.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_buildings"]
|
||||
margin_right = 232.0
|
||||
@@ -134,7 +134,7 @@ margin_top = 26.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 46.0
|
||||
text = "Select"
|
||||
items = [ "Select", null, false, 0, null, "Move", null, false, 1, null, "Rotate", null, false, 2, null ]
|
||||
items = [ "Select", null, false, 0, null, "Move", null, false, 1, null, "Rotate", null, false, 2, null, "Create", null, false, 3, null ]
|
||||
selected = 0
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/v_buildings"]
|
||||
@@ -162,18 +162,25 @@ margin_right = 232.0
|
||||
margin_bottom = 120.0
|
||||
text = "Delete building"
|
||||
|
||||
[node name="buildings_save" type="Button" parent="VBoxContainer/v_buildings"]
|
||||
[node name="buildings_create_building" type="Button" parent="VBoxContainer/v_buildings"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 124.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 144.0
|
||||
text = "Create building"
|
||||
|
||||
[node name="buildings_save" type="Button" parent="VBoxContainer/v_buildings"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 148.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 168.0
|
||||
text = "Save Buildings"
|
||||
|
||||
[node name="v_navigation" type="VBoxContainer" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 302.0
|
||||
margin_top = 326.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 324.0
|
||||
margin_bottom = 348.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_navigation"]
|
||||
margin_right = 232.0
|
||||
@@ -187,9 +194,9 @@ text = "Navigation mode"
|
||||
|
||||
[node name="v_poi" type="VBoxContainer" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 328.0
|
||||
margin_top = 352.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 350.0
|
||||
margin_bottom = 374.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_poi"]
|
||||
margin_right = 232.0
|
||||
@@ -203,9 +210,9 @@ text = "POI mode"
|
||||
|
||||
[node name="v_road_lines" type="VBoxContainer" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 354.0
|
||||
margin_top = 378.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 962.0
|
||||
margin_bottom = 986.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"]
|
||||
margin_right = 232.0
|
||||
@@ -462,9 +469,9 @@ text = "Cancel"
|
||||
|
||||
[node name="v_npc" type="VBoxContainer" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 966.0
|
||||
margin_top = 990.0
|
||||
margin_right = 232.0
|
||||
margin_bottom = 988.0
|
||||
margin_bottom = 1012.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"]
|
||||
margin_right = 232.0
|
||||
@@ -479,6 +486,7 @@ text = "NPC mode"
|
||||
[node name="StreamWorld" type="StreamWorld" parent="."]
|
||||
|
||||
[node name="VoxelLodTerrain" type="VoxelLodTerrain" parent="."]
|
||||
unique_name_in_owner = true
|
||||
generator = SubResource( 5 )
|
||||
mesher = SubResource( 6 )
|
||||
voxel_bounds = AABB( -5.36871e+08, -2048, -5.36871e+08, 1.07374e+09, 4096, 1.07374e+09 )
|
||||
@@ -505,6 +513,8 @@ transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, 0 )
|
||||
shape = SubResource( 9 )
|
||||
|
||||
[node name="building_cursor" type="MeshInstance" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
mesh = SubResource( 10 )
|
||||
material/0 = SubResource( 11 )
|
||||
|
||||
@@ -518,6 +528,8 @@ transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2, 0 )
|
||||
shape = SubResource( 12 )
|
||||
|
||||
[node name="building_rot_cursor" type="Spatial" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="building_rot_cursor" type="MeshInstance" parent="building_rot_cursor"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -60 )
|
||||
|
||||
450
src/modules/stream/buildings_editor.cpp
Normal file
450
src/modules/stream/buildings_editor.cpp
Normal file
@@ -0,0 +1,450 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <core/variant.h>
|
||||
#include <scene/gui/option_button.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include <scene/3d/camera.h>
|
||||
#include <modules/voxel/terrain/voxel_lod_terrain.h>
|
||||
#include <modules/imgmapper/voxel_generator_imgmapper.h>
|
||||
#include "world_editor.h"
|
||||
#include "buildings_editor.h"
|
||||
|
||||
class HandleChangeBuildingType : public Object {
|
||||
GDCLASS(HandleChangeBuildingType, Object)
|
||||
BuildingsEditor *editor;
|
||||
|
||||
void change_building_type(int index)
|
||||
{
|
||||
OptionButton *building_type =
|
||||
editor->get_as_node<OptionButton>("%building_type");
|
||||
const String &item = building_type->get_item_text(index);
|
||||
int bmode = editor->get_buildings_editor_mode();
|
||||
if (bmode == 0 || bmode == 1 ||
|
||||
bmode == 2) /* select, move, rotate */
|
||||
editor->change_building_type(item);
|
||||
/* do not change building types in create mode (3) */
|
||||
}
|
||||
|
||||
public:
|
||||
HandleChangeBuildingType(BuildingsEditor *editor)
|
||||
: Object()
|
||||
, editor(editor)
|
||||
{
|
||||
OptionButton *building_type =
|
||||
editor->get_as_node<OptionButton>("%building_type");
|
||||
building_type->connect("item_selected", this,
|
||||
"change_building_type");
|
||||
}
|
||||
virtual ~HandleChangeBuildingType()
|
||||
{
|
||||
OptionButton *building_type =
|
||||
editor->get_as_node<OptionButton>("%building_type");
|
||||
if (building_type->is_connected("item_selected", this,
|
||||
"change_building_type"))
|
||||
building_type->disconnect("item_selected", this,
|
||||
"change_building_type");
|
||||
}
|
||||
|
||||
protected:
|
||||
static void _bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(
|
||||
D_METHOD("change_building_type", "index"),
|
||||
&HandleChangeBuildingType::change_building_type);
|
||||
}
|
||||
};
|
||||
|
||||
class HandleDeleteButton : public Object {
|
||||
GDCLASS(HandleDeleteButton, Object)
|
||||
BuildingsEditor *editor;
|
||||
|
||||
public:
|
||||
HandleDeleteButton(BuildingsEditor *editor)
|
||||
: Object()
|
||||
, editor(editor)
|
||||
{
|
||||
Button *delete_button = editor->get_as_node<Button>(
|
||||
"%buildings_delete_building");
|
||||
assert(delete_button);
|
||||
/* FIXME */
|
||||
if (!delete_button->is_connected("pressed", this,
|
||||
"delete_building_handler"))
|
||||
delete_button->connect("pressed", this,
|
||||
"delete_building_handler");
|
||||
}
|
||||
~HandleDeleteButton()
|
||||
{
|
||||
Button *delete_button = editor->get_as_node<Button>(
|
||||
"%buildings_delete_building");
|
||||
if (delete_button->is_connected("pressed", this,
|
||||
"delete_building_handler"))
|
||||
delete_button->disconnect("pressed", this,
|
||||
"delete_building_handler");
|
||||
}
|
||||
void delete_building_handler()
|
||||
{
|
||||
editor->delete_building_handler();
|
||||
}
|
||||
static void _bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(
|
||||
D_METHOD("delete_building_handler"),
|
||||
&HandleDeleteButton::delete_building_handler);
|
||||
}
|
||||
};
|
||||
static HandleChangeBuildingType *change_building_type_handler = nullptr;
|
||||
static HandleDeleteButton *delete_button_handler = nullptr;
|
||||
|
||||
BuildingsEditor::BuildingsEditor(WorldEditor *editor)
|
||||
: editor(editor)
|
||||
, selected_building(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void BuildingsEditor::exit()
|
||||
{
|
||||
if (active)
|
||||
deactivate();
|
||||
}
|
||||
|
||||
void BuildingsEditor::activate()
|
||||
{
|
||||
assert(!active);
|
||||
editor->event.add_listener(this, &BuildingsEditor::event_handler);
|
||||
if (!change_building_type_handler)
|
||||
change_building_type_handler =
|
||||
memnew(HandleChangeBuildingType(this));
|
||||
if (!delete_button_handler)
|
||||
delete_button_handler = memnew(HandleDeleteButton(this));
|
||||
assert(change_building_type_handler && delete_button_handler);
|
||||
active = true;
|
||||
}
|
||||
|
||||
void BuildingsEditor::deactivate()
|
||||
{
|
||||
assert(active);
|
||||
if (change_building_type_handler) {
|
||||
memdelete(change_building_type_handler);
|
||||
change_building_type_handler = nullptr;
|
||||
}
|
||||
if (delete_button_handler) {
|
||||
memdelete(delete_button_handler);
|
||||
delete_button_handler = nullptr;
|
||||
}
|
||||
editor->event.remove_listener(this, &BuildingsEditor::event_handler);
|
||||
active = false;
|
||||
}
|
||||
|
||||
void BuildingsEditor::event_handler(const String &event, const Array &args)
|
||||
{
|
||||
if (event == "mouse_drag")
|
||||
mouse_drag(args[0]);
|
||||
else if (event == "mouse_press")
|
||||
mouse_press(args[0]);
|
||||
else if (event == "result:get_closest_building") {
|
||||
select_building(args[0], args[3], args[4]);
|
||||
if (get_buildings_editor_mode() == 2 /* rotate */) {
|
||||
/* move rot cursor too */
|
||||
get_as_node<Spatial>("%building_rot_cursor")
|
||||
->set_global_transform(selected_building_xform);
|
||||
}
|
||||
}
|
||||
print_line("buildings::" + event);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void BuildingsEditor::mode_visibility(int mode, const String &path)
|
||||
{
|
||||
T *obj = get_as_node<T>(path);
|
||||
if (get_buildings_editor_mode() == mode) {
|
||||
if (!obj->is_visible())
|
||||
obj->show();
|
||||
} else {
|
||||
if (obj->is_visible())
|
||||
obj->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingsEditor::update(float delta)
|
||||
{
|
||||
if (!active)
|
||||
activate();
|
||||
int mode = get_buildings_editor_mode();
|
||||
if (mode == 2) {
|
||||
Spatial *rot_cursor =
|
||||
get_as_node<Spatial>("%building_rot_cursor");
|
||||
if (!rot_cursor->is_visible())
|
||||
rot_cursor->set_global_transform(
|
||||
selected_building_xform);
|
||||
}
|
||||
mode_visibility<Button>(0, "%buildings_delete_building");
|
||||
mode_visibility<Spatial>(2, "%building_rot_cursor");
|
||||
mode_visibility<Button>(3, "%buildings_create_building");
|
||||
}
|
||||
|
||||
void BuildingsEditor::mouse_drag(const Vector2 &position)
|
||||
{
|
||||
if (editor->get_current_mode() != WorldEditor::MODE_BUILDINGS)
|
||||
return;
|
||||
if (editor->get_camera_mode() != 3)
|
||||
return;
|
||||
print_line("in mouse_drag");
|
||||
Camera *camera = editor->get_viewport()->get_camera();
|
||||
Vector3 start = camera->project_ray_origin(position);
|
||||
Vector3 normal = camera->project_ray_normal(position);
|
||||
Vector3 end = start + normal * camera->get_zfar();
|
||||
PhysicsDirectSpaceState *space_state =
|
||||
editor->get_world()->get_direct_space_state();
|
||||
PhysicsDirectSpaceState::RayResult result;
|
||||
Set<RID> excludes;
|
||||
bool r = space_state->intersect_ray(start, end, result, excludes,
|
||||
1 << 15, false, true, false);
|
||||
if (r && result.rid != RID()) {
|
||||
Vector3 proj = result.position;
|
||||
int mode = get_buildings_editor_mode();
|
||||
switch (mode) {
|
||||
case 1: {
|
||||
/* move */
|
||||
print_verbose("move: " + (proj.operator String()));
|
||||
Vector3 newpos(Math::stepify(proj.x, 2.0f), proj.y,
|
||||
Math::stepify(proj.z, 2.0f));
|
||||
Ref<VoxelGeneratorImgMapper> gen =
|
||||
get_as_node<VoxelLodTerrain>("%VoxelLodTerrain")
|
||||
->get_generator();
|
||||
float h = gen->get_height_full(newpos);
|
||||
newpos.y = h;
|
||||
Array args;
|
||||
args.push_back(selected_building);
|
||||
args.push_back(Transform(selected_building_xform.basis,
|
||||
newpos));
|
||||
editor->editor_command("update_building_transform",
|
||||
args);
|
||||
Spatial *cursor =
|
||||
get_as_node<Spatial>("%building_cursor");
|
||||
Transform orig_pos = cursor->get_global_transform();
|
||||
orig_pos.origin = newpos;
|
||||
cursor->set_global_transform(orig_pos);
|
||||
selected_building_xform = Transform(
|
||||
selected_building_xform.basis, newpos);
|
||||
} break;
|
||||
case 2: {
|
||||
/* rotate */
|
||||
print_verbose("rotate: " + (proj.operator String()));
|
||||
Vector3 m = proj;
|
||||
m.y = selected_building_xform.origin.y;
|
||||
Transform xform = selected_building_xform.looking_at(
|
||||
m, Vector3(0.0f, 1.0f, 0.0f));
|
||||
Array args;
|
||||
args.push_back(selected_building);
|
||||
args.push_back(xform);
|
||||
editor->editor_command("update_building_transform",
|
||||
args);
|
||||
selected_building_xform = xform;
|
||||
get_as_node<Spatial>("%building_rot_cursor")
|
||||
->set_global_transform(xform);
|
||||
} break;
|
||||
case 3: { /* create */
|
||||
print_verbose("create: " + (proj.operator String()));
|
||||
Vector3 newpos(Math::stepify(proj.x, 2.0f), proj.y,
|
||||
Math::stepify(proj.z, 2.0f));
|
||||
Ref<VoxelGeneratorImgMapper> gen =
|
||||
get_as_node<VoxelLodTerrain>("%VoxelLodTerrain")
|
||||
->get_generator();
|
||||
float h = gen->get_height_full(newpos);
|
||||
newpos.y = h;
|
||||
Transform xform(Basis(), newpos);
|
||||
get_as_node<Spatial>("%building_cursor")
|
||||
->set_global_transform(xform);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingsEditor::mouse_press(const Vector2 &position)
|
||||
{
|
||||
if (editor->get_current_mode() != WorldEditor::MODE_BUILDINGS)
|
||||
return;
|
||||
if (editor->get_camera_mode() != 3)
|
||||
return;
|
||||
print_line("in mouse_press");
|
||||
Camera *camera = editor->get_viewport()->get_camera();
|
||||
Vector3 start = camera->project_ray_origin(position);
|
||||
Vector3 normal = camera->project_ray_normal(position);
|
||||
Vector3 end = start + normal * camera->get_zfar();
|
||||
PhysicsDirectSpaceState *space_state =
|
||||
editor->get_world()->get_direct_space_state();
|
||||
PhysicsDirectSpaceState::RayResult result;
|
||||
Set<RID> excludes;
|
||||
bool r = space_state->intersect_ray(start, end, result, excludes,
|
||||
1 << 15, false, true, false);
|
||||
if (r && result.rid != RID()) {
|
||||
Vector3 proj = result.position;
|
||||
int mode = get_buildings_editor_mode();
|
||||
switch (mode) {
|
||||
case 0: {
|
||||
/* select */
|
||||
Array args;
|
||||
Transform xform(Basis(), proj);
|
||||
args.push_back(xform);
|
||||
editor->editor_command("get_closest_building", args);
|
||||
} break;
|
||||
case 1: {
|
||||
/* move */
|
||||
editor->editor_command("checkpoint", Array());
|
||||
} break;
|
||||
case 2: {
|
||||
/* TODO: deduplicate */
|
||||
/* rotate */
|
||||
editor->editor_command("checkpoint", Array());
|
||||
print_verbose("rotate: " + (proj.operator String()));
|
||||
Vector3 m = proj;
|
||||
m.y = selected_building_xform.origin.y;
|
||||
Transform xform = selected_building_xform.looking_at(
|
||||
m, Vector3(0.0f, 1.0f, 0.0f));
|
||||
Array args;
|
||||
args.push_back(selected_building);
|
||||
args.push_back(xform);
|
||||
editor->editor_command("update_building_transform",
|
||||
args);
|
||||
selected_building_xform = xform;
|
||||
get_as_node<Spatial>("%building_rot_cursor")
|
||||
->set_global_transform(xform);
|
||||
} break;
|
||||
/* TODO: deduplicate */
|
||||
case 3: { /* create */
|
||||
print_verbose("create: " + (proj.operator String()));
|
||||
Vector3 newpos(Math::stepify(proj.x, 2.0f), proj.y,
|
||||
Math::stepify(proj.z, 2.0f));
|
||||
Ref<VoxelGeneratorImgMapper> gen =
|
||||
get_as_node<VoxelLodTerrain>("%VoxelLodTerrain")
|
||||
->get_generator();
|
||||
float h = gen->get_height_full(newpos);
|
||||
newpos.y = h;
|
||||
Transform xform(Basis(), newpos);
|
||||
get_as_node<Spatial>("%building_cursor")
|
||||
->set_global_transform(xform);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BuildingsEditor::get_buildings_editor_mode() const
|
||||
{
|
||||
const OptionButton *buildings_edit_mode =
|
||||
get_as_node<OptionButton>("%buildings_edit_mode");
|
||||
int selected = buildings_edit_mode->get_selected();
|
||||
return selected;
|
||||
}
|
||||
|
||||
BuildingsEditor::~BuildingsEditor()
|
||||
{
|
||||
if (active)
|
||||
deactivate();
|
||||
}
|
||||
|
||||
int BuildingsEditor::get_selected_building() const
|
||||
{
|
||||
return selected_building;
|
||||
}
|
||||
|
||||
Transform BuildingsEditor::get_selected_building_xform() const
|
||||
{
|
||||
return selected_building_xform;
|
||||
}
|
||||
|
||||
void BuildingsEditor::delete_building_handler()
|
||||
{
|
||||
Array args, args2;
|
||||
args.push_back(selected_building);
|
||||
editor->editor_command("remove_building", args);
|
||||
args2.push_back(selected_building_xform);
|
||||
editor->editor_command("get_closest_building", args2);
|
||||
}
|
||||
|
||||
void BuildingsEditor::change_building_type(const String &type_name)
|
||||
{
|
||||
Array args;
|
||||
int bmode = get_buildings_editor_mode();
|
||||
assert(bmode == 0 || bmode == 1 ||
|
||||
bmode == 2); /* select, move, rotate */
|
||||
args.push_back(selected_building);
|
||||
args.push_back(type_name);
|
||||
editor->editor_command("change_building_type", args);
|
||||
}
|
||||
|
||||
void BuildingsEditor::remove_buildings_by_prefix(const String &prefix)
|
||||
{
|
||||
Array args;
|
||||
args.push_back(prefix);
|
||||
editor->editor_command("remove_buildings_by_prefix", args);
|
||||
}
|
||||
|
||||
void BuildingsEditor::select_building(const Transform &xform, int id,
|
||||
const String &mid)
|
||||
{
|
||||
int i;
|
||||
selected_building_xform = xform;
|
||||
selected_building = id;
|
||||
print_line("selected id: " + itos(id));
|
||||
OptionButton *building_type = Object::cast_to<OptionButton>(
|
||||
editor->get_node(NodePath("%building_type")));
|
||||
assert(building_type);
|
||||
bool ok = false;
|
||||
for (i = 0; i < building_type->get_item_count(); i++) {
|
||||
const String &item = building_type->get_item_text(i);
|
||||
if (item == mid) {
|
||||
building_type->select(i);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
Button *delete_button =
|
||||
get_as_node<Button>("%buildings_delete_building");
|
||||
delete_button->show();
|
||||
}
|
||||
Spatial *cursor = get_as_node<Spatial>("%building_cursor");
|
||||
/* Show cursor and change cursor position */
|
||||
if (!cursor->is_visible())
|
||||
cursor->show();
|
||||
Transform orig_xform = cursor->get_global_transform();
|
||||
orig_xform.origin = xform.origin;
|
||||
cursor->set_global_transform(orig_xform);
|
||||
}
|
||||
|
||||
void BuildingsEditor::editor_command(const String &command, const Array &args)
|
||||
{
|
||||
if (command == "select_building") {
|
||||
select_building(args[0], args[1], args[2]);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> T *BuildingsEditor::get_as_node(const String &path)
|
||||
{
|
||||
Node *node = scene()->get_node(NodePath(path));
|
||||
assert(node);
|
||||
T *ret = Object::cast_to<T>(node);
|
||||
assert(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T *BuildingsEditor::get_as_node(const String &path) const
|
||||
{
|
||||
const Node *node = scene()->get_node(NodePath(path));
|
||||
assert(node);
|
||||
const T *ret = Object::cast_to<T>(node);
|
||||
assert(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Node *BuildingsEditor::scene()
|
||||
{
|
||||
return editor->get_tree()->get_current_scene();
|
||||
}
|
||||
|
||||
const Node *BuildingsEditor::scene() const
|
||||
{
|
||||
const Node *ret = editor->get_tree()->get_current_scene();
|
||||
return ret;
|
||||
}
|
||||
35
src/modules/stream/buildings_editor.h
Normal file
35
src/modules/stream/buildings_editor.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef BUILDINGS_EDITOR_H
|
||||
#define BUILDINGS_EDITOR_H
|
||||
#include <core/math/transform.h>
|
||||
class WorldEditor;
|
||||
class BuildingsEditor {
|
||||
WorldEditor *editor;
|
||||
int selected_building;
|
||||
Transform selected_building_xform;
|
||||
bool active;
|
||||
void activate();
|
||||
void deactivate();
|
||||
void event_handler(const String &event, const Array &args);
|
||||
template <class T> void mode_visibility(int mode, const String &path);
|
||||
|
||||
public:
|
||||
BuildingsEditor(WorldEditor *editor);
|
||||
void exit();
|
||||
void update(float delta);
|
||||
void mouse_drag(const Vector2 &position);
|
||||
void mouse_press(const Vector2 &position);
|
||||
int get_buildings_editor_mode() const;
|
||||
virtual ~BuildingsEditor();
|
||||
int get_selected_building() const;
|
||||
Transform get_selected_building_xform() const;
|
||||
void select_building(const Transform &xform, int id, const String &mid);
|
||||
void remove_buildings_by_prefix(const String &prefix);
|
||||
void editor_command(const String &command, const Array &args);
|
||||
void delete_building_handler();
|
||||
void change_building_type(const String &type_name);
|
||||
template <class T> T *get_as_node(const String &path);
|
||||
template <class T> const T *get_as_node(const String &path) const;
|
||||
Node *scene();
|
||||
const Node *scene() const;
|
||||
};
|
||||
#endif
|
||||
@@ -8,8 +8,13 @@
|
||||
#include <core/os/dir_access.h>
|
||||
#include <core/os/time.h>
|
||||
#include <core/math/geometry.h>
|
||||
#include <scene/3d/immediate_geometry.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include "from_string.h"
|
||||
#include "road_lines_data.h"
|
||||
|
||||
static ImmediateGeometry *debug_im;
|
||||
static Ref<Material> debug_material;
|
||||
RoadLinesData::RoadLinesData()
|
||||
{
|
||||
int i;
|
||||
@@ -66,6 +71,14 @@ RoadLinesData *RoadLinesData::get_singleton()
|
||||
return singleton;
|
||||
}
|
||||
|
||||
RoadLinesData::~RoadLinesData()
|
||||
{
|
||||
if (debug_im) {
|
||||
memdelete(debug_im);
|
||||
debug_im = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RoadLinesData::cleanup()
|
||||
{
|
||||
memdelete(singleton);
|
||||
@@ -211,54 +224,72 @@ void RoadLinesData::index_lines(
|
||||
e = e->next();
|
||||
}
|
||||
}
|
||||
static inline int get_segment_index(const String &road, int pos)
|
||||
{
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
int idx = rld->lines[road].indices[pos];
|
||||
return idx;
|
||||
}
|
||||
void RoadLinesData::create_segments(const String &road,
|
||||
std::vector<int> &segments)
|
||||
{
|
||||
int i;
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
for (i = 0; i < (int)rld->lines[road].indices.size() - 1; i++) {
|
||||
int idx1 = rld->lines[road].indices[i];
|
||||
int idx2 = rld->lines[road].indices[i + 1];
|
||||
segments.push_back(idx1);
|
||||
segments.push_back(idx2);
|
||||
segments.push_back(i);
|
||||
segments.push_back(i + 1);
|
||||
}
|
||||
}
|
||||
/* add close points on each line to the line */
|
||||
void RoadLinesData::insert_close_points(std::vector<Vector3> &road_lines_nodes)
|
||||
void RoadLinesData::insert_close_points(std::vector<Vector3> &road_lines_nodes,
|
||||
float distance_squared)
|
||||
{
|
||||
int i;
|
||||
List<String> keys;
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
rld->get_road_lines_key_list(&keys);
|
||||
get_road_lines_key_list(&keys);
|
||||
List<String>::Element *e = keys.front();
|
||||
for (i = 0; i < (int)road_lines_nodes.size(); i++) {
|
||||
int idx3 = i;
|
||||
Vector3 p3 = road_lines_nodes[idx3];
|
||||
/* Checking each road point against
|
||||
all line segments */
|
||||
while (e) {
|
||||
int j;
|
||||
std::vector<int> segments;
|
||||
String rkey = e->get();
|
||||
create_segments(rkey, segments);
|
||||
for (j = 0; j < (int)segments.size(); j += 3) {
|
||||
int idx1 = segments[j];
|
||||
int idx2 = segments[j + 1];
|
||||
int idx = segments[j + 2];
|
||||
for (j = 0; j < (int)segments.size(); j += 2) {
|
||||
/* indices in road_lines_nodes */
|
||||
int idx1 = get_segment_index(rkey, segments[j]);
|
||||
int idx2 = get_segment_index(rkey,
|
||||
segments[j + 1]);
|
||||
/* insertion point in line indices
|
||||
array to split segment and add point */
|
||||
int idx = segments[j + 1];
|
||||
/* Skip segment point */
|
||||
if (idx3 == idx1 || idx3 == idx2)
|
||||
continue;
|
||||
Vector3 p1 = road_lines_nodes[idx1];
|
||||
Vector3 p2 = road_lines_nodes[idx2];
|
||||
Vector3 p3 = road_lines_nodes[idx3];
|
||||
std::vector<Vector3> seg = { p1, p2 };
|
||||
Vector3 closest =
|
||||
Geometry::get_closest_point_to_segment(
|
||||
p3, seg.data());
|
||||
if (p3.distance_squared_to(closest) < 160) {
|
||||
road_lines_nodes[idx3] = closest;
|
||||
rld->lines[rkey].indices.insert(
|
||||
rld->lines[rkey].indices.begin() +
|
||||
/* should be no duplicate points
|
||||
in road_lines_nodes */
|
||||
if (closest.is_equal_approx(p1))
|
||||
continue;
|
||||
if (closest.is_equal_approx(p2))
|
||||
continue;
|
||||
if (p3.distance_squared_to(closest) <
|
||||
distance_squared) {
|
||||
/* split segment and replace road
|
||||
point with a point on segment */
|
||||
lines[rkey].indices.insert(
|
||||
lines[rkey].indices.begin() +
|
||||
idx,
|
||||
idx3);
|
||||
road_lines_nodes[idx3] = closest;
|
||||
}
|
||||
}
|
||||
e = e->next();
|
||||
@@ -423,13 +454,42 @@ void RoadLinesData::dump_road_lines(const std::vector<Vector3> &road_lines_nodes
|
||||
}
|
||||
}
|
||||
|
||||
static inline ImmediateGeometry *get_debug_node()
|
||||
{
|
||||
debug_im = memnew(ImmediateGeometry);
|
||||
Ref<SpatialMaterial> tmpmat;
|
||||
tmpmat.instance();
|
||||
tmpmat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
|
||||
tmpmat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true);
|
||||
tmpmat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
|
||||
debug_material = tmpmat;
|
||||
debug_im->set_material_override(debug_material);
|
||||
SceneTree::get_singleton()
|
||||
->get_current_scene()
|
||||
->get_viewport()
|
||||
->add_child(debug_im);
|
||||
return debug_im;
|
||||
}
|
||||
|
||||
void RoadLinesData::process_lines(
|
||||
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||
&road_lines_nodes_hash,
|
||||
std::vector<Vector3> &road_lines_nodes)
|
||||
{
|
||||
int i;
|
||||
get_debug_node();
|
||||
debug_im->clear();
|
||||
index_lines(road_lines_nodes_hash, road_lines_nodes);
|
||||
insert_close_points(road_lines_nodes);
|
||||
debug_im->begin(Mesh::PRIMITIVE_LINES);
|
||||
for (i = 0; i < (int)road_lines_nodes.size(); i++) {
|
||||
debug_im->set_color(Color(0.1f, 0.6f, 0.6f, 1.0f));
|
||||
debug_im->add_vertex(road_lines_nodes[i]);
|
||||
debug_im->set_color(Color(0.1f, 0.6f, 0.6f, 1.0f));
|
||||
debug_im->add_vertex(road_lines_nodes[i] +
|
||||
Vector3(0.0f, 200.0f, 0.0f));
|
||||
}
|
||||
debug_im->end();
|
||||
insert_close_points(road_lines_nodes, 160.0f);
|
||||
update_road_lines_nodes(road_lines_nodes);
|
||||
dump_road_lines(road_lines_nodes);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
};
|
||||
HashMap<String, struct road_line> lines;
|
||||
static RoadLinesData *get_singleton();
|
||||
virtual ~RoadLinesData();
|
||||
static void cleanup();
|
||||
String get_road_lines_path();
|
||||
void get_road_lines_key_list(List<String> *keys);
|
||||
@@ -36,8 +37,8 @@ private:
|
||||
std::vector<Vector3> &road_lines_nodes);
|
||||
|
||||
void create_segments(const String &road, std::vector<int> &segments);
|
||||
|
||||
void insert_close_points(std::vector<Vector3> &road_lines_nodes);
|
||||
void insert_close_points(std::vector<Vector3> &road_lines_nodes,
|
||||
float distance_squared);
|
||||
|
||||
void update_road_lines_nodes(std::vector<Vector3> &road_lines_nodes);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "road_lines_editor.h"
|
||||
|
||||
static ImmediateGeometry *line_im = nullptr;
|
||||
// static ImmediateGeometry *debug_im = nullptr;
|
||||
static Ref<Material> debug_material;
|
||||
|
||||
#define __evhandler(vname, mtype) \
|
||||
@@ -946,7 +947,9 @@ void RoadLinesEditor::handle_input()
|
||||
}
|
||||
void RoadLinesEditor::place_zebras()
|
||||
{
|
||||
editor->remove_buildings_by_prefix("zebra");
|
||||
Array args;
|
||||
args.push_back("zebra");
|
||||
editor->editor_command("remove_buildings_by_prefix", args);
|
||||
/*
|
||||
func place_zebras():
|
||||
var road_nodes = SceneComps.get_component("road_nodes2")
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <core/os/file_access.h>
|
||||
#include <scene/resources/mesh.h>
|
||||
#include <scene/3d/mesh_instance.h>
|
||||
#include <scene/3d/immediate_geometry.h>
|
||||
#include <core/math/transform.h>
|
||||
#include <core/math/geometry.h>
|
||||
#include <core/math/vector2.h>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef ROAD_LINES_PROCESSING_H_
|
||||
#define ROAD_LINES_PROCESSSING_H_
|
||||
class Node;
|
||||
class ImmediateGeometry;
|
||||
class RoadProcessing {
|
||||
public:
|
||||
static void road_setup(Node *target);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <scene/scene_string_names.h>
|
||||
#include "road_lines_editor.h"
|
||||
#include "world_editor.h"
|
||||
#include "buildings_editor.h"
|
||||
|
||||
WorldEditor::WorldEditor()
|
||||
: Spatial()
|
||||
@@ -25,7 +26,7 @@ WorldEditor::WorldEditor()
|
||||
, dragging(false)
|
||||
, drag_delay(0.2f)
|
||||
, road_lines_editor(memnew(RoadLinesEditor(this)))
|
||||
, selected_building(-1)
|
||||
, buildings_editor(memnew(BuildingsEditor(this)))
|
||||
{
|
||||
if (!InputMap::get_singleton()->has_action("left"))
|
||||
InputMap::get_singleton()->add_action("left");
|
||||
@@ -47,11 +48,20 @@ WorldEditor::WorldEditor()
|
||||
InputMap::get_singleton()->add_action("editor_cam3");
|
||||
if (!InputMap::get_singleton()->has_action("mouse1"))
|
||||
InputMap::get_singleton()->add_action("mouse1");
|
||||
event.add_listener(this, &WorldEditor::event_signal_handler);
|
||||
}
|
||||
|
||||
WorldEditor::~WorldEditor()
|
||||
{
|
||||
event.remove_listener(this, &WorldEditor::event_signal_handler);
|
||||
if (road_lines_editor) {
|
||||
memdelete(road_lines_editor);
|
||||
road_lines_editor = nullptr;
|
||||
}
|
||||
if (buildings_editor) {
|
||||
memdelete(buildings_editor);
|
||||
buildings_editor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldEditor::set_camera_mode(int mode)
|
||||
@@ -100,16 +110,6 @@ int WorldEditor::get_camera_mode() const
|
||||
return current_camera_mode;
|
||||
}
|
||||
|
||||
int WorldEditor::get_selected_building() const
|
||||
{
|
||||
return selected_building;
|
||||
}
|
||||
|
||||
Transform WorldEditor::get_selected_building_xform() const
|
||||
{
|
||||
return selected_building_xform;
|
||||
}
|
||||
|
||||
void WorldEditor::disable_all()
|
||||
{
|
||||
}
|
||||
@@ -143,13 +143,6 @@ void WorldEditor::mode_npc()
|
||||
disable_all();
|
||||
print_line("NPC");
|
||||
}
|
||||
enum {
|
||||
MODE_BUILDINGS = 2,
|
||||
MODE_NAVIGATION = 3,
|
||||
MODE_POI = 5,
|
||||
MODE_ROAD_LINES = 6,
|
||||
MODE_NPC = 7,
|
||||
};
|
||||
struct StringHasher {
|
||||
std::size_t operator()(const String &s) const
|
||||
{
|
||||
@@ -157,11 +150,11 @@ struct StringHasher {
|
||||
}
|
||||
};
|
||||
static std::unordered_map<String, int, StringHasher> modes = {
|
||||
{ "select_buildings", MODE_BUILDINGS },
|
||||
{ "select_navigation", MODE_NAVIGATION },
|
||||
{ "select_poi", MODE_POI },
|
||||
{ "select_road_lines", MODE_ROAD_LINES },
|
||||
{ "select_npc", MODE_NPC }
|
||||
{ "select_buildings", WorldEditor::MODE_BUILDINGS },
|
||||
{ "select_navigation", WorldEditor::MODE_NAVIGATION },
|
||||
{ "select_poi", WorldEditor::MODE_POI },
|
||||
{ "select_road_lines", WorldEditor::MODE_ROAD_LINES },
|
||||
{ "select_npc", WorldEditor::MODE_NPC }
|
||||
};
|
||||
void WorldEditor::tools_button(const String &button)
|
||||
{
|
||||
@@ -174,7 +167,7 @@ void WorldEditor::tools_button(const String &button)
|
||||
goto end;
|
||||
change[0] = current_mode;
|
||||
change[1] = modes[button];
|
||||
emit_signal("editor_event", "mode_change_pre", change);
|
||||
event.emit("mode_change_pre", change);
|
||||
switch (current_mode) {
|
||||
case MODE_ROAD_LINES:
|
||||
road_lines_editor->exit();
|
||||
@@ -197,7 +190,7 @@ void WorldEditor::tools_button(const String &button)
|
||||
mode_npc();
|
||||
break;
|
||||
}
|
||||
emit_signal("editor_event", "mode_change_post", change);
|
||||
event.emit("mode_change_post", change);
|
||||
current_mode = modes[button];
|
||||
end:;
|
||||
}
|
||||
@@ -237,8 +230,6 @@ void WorldEditor::editor_command(const String &command, const Array &args)
|
||||
if (stream_world) {
|
||||
stream_world->run_command(command, args);
|
||||
}
|
||||
} else if (command == "select_building") {
|
||||
select_building(args[0], args[1], args[2]);
|
||||
} else if (command == "remove_generated_stuff") {
|
||||
if (stream_world)
|
||||
stream_world->run_command(command, args);
|
||||
@@ -248,37 +239,17 @@ void WorldEditor::editor_command(const String &command, const Array &args)
|
||||
} else if (command == "remove_road_meshes") {
|
||||
if (stream_world)
|
||||
stream_world->run_command(command, args);
|
||||
} else if (road_lines_editor) {
|
||||
} else if (command == "remove_building") {
|
||||
if (stream_world)
|
||||
stream_world->run_command(command, args);
|
||||
} else if (command == "remove_buildings_by_prefix") {
|
||||
if (stream_world)
|
||||
stream_world->run_command(command, args);
|
||||
} else {
|
||||
if (road_lines_editor)
|
||||
road_lines_editor->editor_command(command, args);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldEditor::select_building(const Transform &xform, int id,
|
||||
const String &mid)
|
||||
{
|
||||
int i;
|
||||
selected_building_xform = xform;
|
||||
selected_building = id;
|
||||
print_line("selected id: " + itos(id));
|
||||
OptionButton *building_type = Object::cast_to<OptionButton>(
|
||||
get_node(NodePath("%building_type")));
|
||||
assert(building_type);
|
||||
for (i = 0; i < building_type->get_item_count(); i++) {
|
||||
const String &item = building_type->get_item_text(i);
|
||||
if (item == mid) {
|
||||
building_type->select(i);
|
||||
break;
|
||||
}
|
||||
/* TODO: set building cursor position to xform */
|
||||
Button *delete_button = Object::cast_to<Button>(
|
||||
get_node(NodePath("%buildings_delete_building")));
|
||||
assert(delete_button);
|
||||
delete_button->show();
|
||||
/* FIXME */
|
||||
if (!delete_button->is_connected("pressed", this,
|
||||
"delete_building_handler"))
|
||||
delete_button->connect("pressed", this,
|
||||
"delete_building_handler");
|
||||
if (buildings_editor)
|
||||
buildings_editor->editor_command(command, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +258,11 @@ int WorldEditor::get_current_mode() const
|
||||
return current_mode;
|
||||
}
|
||||
|
||||
void WorldEditor::event_signal_handler(const String &event, const Array &args)
|
||||
{
|
||||
emit_signal("editor_event", event, args);
|
||||
}
|
||||
|
||||
StreamWorld *WorldEditor::get_stream_world()
|
||||
{
|
||||
return stream_world;
|
||||
@@ -295,7 +271,7 @@ StreamWorld *WorldEditor::get_stream_world()
|
||||
void WorldEditor::world_command_result(const String &what, const Array &data)
|
||||
{
|
||||
print_line("what: " + what);
|
||||
emit_signal("editor_event", "result:" + what, data);
|
||||
event.emit("result:" + what, data);
|
||||
}
|
||||
|
||||
void WorldEditor::_notification(int which)
|
||||
@@ -320,6 +296,14 @@ void WorldEditor::_notification(int which)
|
||||
}
|
||||
set_process_unhandled_input(true);
|
||||
set_physics_process(true);
|
||||
Spatial *cursor = Object::cast_to<Spatial>(
|
||||
get_node(NodePath("%building_cursor")));
|
||||
assert(cursor);
|
||||
cursor->hide();
|
||||
Spatial *rot_cursor = Object::cast_to<Spatial>(
|
||||
get_node(NodePath("%building_rot_cursor")));
|
||||
assert(rot_cursor);
|
||||
rot_cursor->hide();
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE:
|
||||
set_physics_process(false);
|
||||
@@ -342,8 +326,7 @@ void WorldEditor::_notification(int which)
|
||||
Vector2 position =
|
||||
get_viewport()->get_mouse_position();
|
||||
args.push_back(position);
|
||||
emit_signal("editor_event", "mouse_drag_off",
|
||||
args);
|
||||
event.emit("mouse_drag_off", args);
|
||||
}
|
||||
}
|
||||
Transform cam_xform = cam->get_global_transform();
|
||||
@@ -382,13 +365,15 @@ void WorldEditor::_notification(int which)
|
||||
cam->set_global_transform(cam_xform);
|
||||
Array move_args;
|
||||
move_args.push_back(cam_xform);
|
||||
emit_signal("editor_event",
|
||||
"editor_camera_moved", move_args);
|
||||
event.emit("editor_camera_moved", move_args);
|
||||
}
|
||||
}
|
||||
if (!dragging && drag_delay >= 0.0f)
|
||||
drag_delay -= delta;
|
||||
switch (current_mode) {
|
||||
case MODE_BUILDINGS:
|
||||
buildings_editor->update(delta);
|
||||
break;
|
||||
case MODE_ROAD_LINES:
|
||||
// print_line("current_mode: " + itos(current_mode));
|
||||
road_lines_editor->update(delta);
|
||||
@@ -415,13 +400,13 @@ void WorldEditor::_unhandled_input(const Ref<InputEvent> &event)
|
||||
Array args;
|
||||
Vector2 position = get_viewport()->get_mouse_position();
|
||||
args.push_back(position);
|
||||
emit_signal("editor_event", "mouse_press", args);
|
||||
this->event.emit("mouse_press", args);
|
||||
} else if (Input::get_singleton()->is_action_pressed("mouse1")) {
|
||||
if (dragging) {
|
||||
Array args;
|
||||
Vector2 position = get_viewport()->get_mouse_position();
|
||||
args.push_back(position);
|
||||
emit_signal("editor_event", "mouse_drag", args);
|
||||
this->event.emit("mouse_drag", args);
|
||||
} else {
|
||||
if (drag_delay < 0.0f && !dragging) {
|
||||
dragging = true;
|
||||
@@ -429,8 +414,7 @@ void WorldEditor::_unhandled_input(const Ref<InputEvent> &event)
|
||||
Vector2 position =
|
||||
get_viewport()->get_mouse_position();
|
||||
args.push_back(position);
|
||||
emit_signal("editor_event", "mouse_drag_on",
|
||||
args);
|
||||
this->event.emit("mouse_drag_on", args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,22 +427,6 @@ void WorldEditor::world_exited()
|
||||
stream_world = nullptr;
|
||||
}
|
||||
|
||||
void WorldEditor::delete_building_handler()
|
||||
{
|
||||
Array args, args2;
|
||||
args.push_back(selected_building);
|
||||
stream_world->run_command("remove_building", args);
|
||||
args2.push_back(selected_building_xform);
|
||||
stream_world->run_command("get_closest_building", args2);
|
||||
}
|
||||
|
||||
void WorldEditor::remove_buildings_by_prefix(const String &prefix)
|
||||
{
|
||||
Array args;
|
||||
args.push_back(prefix);
|
||||
stream_world->run_command("remove_buildings_by_prefix", args);
|
||||
}
|
||||
|
||||
void WorldEditor::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("editor_command", "command", "args"),
|
||||
@@ -475,16 +443,8 @@ void WorldEditor::_bind_methods()
|
||||
&WorldEditor::set_camera_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_camera_mode"),
|
||||
&WorldEditor::get_camera_mode);
|
||||
ClassDB::bind_method(D_METHOD("select_building", "xform", "id", "mid"),
|
||||
&WorldEditor::select_building);
|
||||
ClassDB::bind_method(D_METHOD("get_selected_building"),
|
||||
&WorldEditor::get_selected_building);
|
||||
ClassDB::bind_method(D_METHOD("get_selected_building_xform"),
|
||||
&WorldEditor::get_selected_building_xform);
|
||||
ClassDB::bind_method(D_METHOD("_unhandled_input", "event"),
|
||||
&WorldEditor::_unhandled_input);
|
||||
ClassDB::bind_method(D_METHOD("delete_building_handler"),
|
||||
&WorldEditor::delete_building_handler);
|
||||
ADD_SIGNAL(MethodInfo("editor_event",
|
||||
PropertyInfo(Variant::STRING, "event_name"),
|
||||
PropertyInfo(Variant::ARRAY, "args")));
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#ifndef WORLD_EDITOR_H
|
||||
#define WORLD_EDITOR_H
|
||||
#include <list>
|
||||
#include <scene/3d/spatial.h>
|
||||
#include "stream.h"
|
||||
class RoadLinesEditor;
|
||||
class BuildingsEditor;
|
||||
class WorldEditor : public Spatial {
|
||||
GDCLASS(WorldEditor, Spatial)
|
||||
protected:
|
||||
@@ -16,7 +18,6 @@ protected:
|
||||
void mode_road_lines();
|
||||
void mode_npc();
|
||||
void tools_button(const String &button);
|
||||
int get_current_mode() const;
|
||||
StreamWorld *get_stream_world();
|
||||
void world_command_result(const String &what, const Array &data);
|
||||
void _notification(int which);
|
||||
@@ -32,18 +33,87 @@ private:
|
||||
bool dragging;
|
||||
float drag_delay;
|
||||
RoadLinesEditor *road_lines_editor;
|
||||
int selected_building;
|
||||
Transform selected_building_xform;
|
||||
void delete_building_handler();
|
||||
BuildingsEditor *buildings_editor;
|
||||
|
||||
public:
|
||||
enum {
|
||||
MODE_BUILDINGS = 2,
|
||||
MODE_NAVIGATION = 3,
|
||||
MODE_POI = 5,
|
||||
MODE_ROAD_LINES = 6,
|
||||
MODE_NPC = 7,
|
||||
};
|
||||
WorldEditor();
|
||||
virtual ~WorldEditor();
|
||||
void editor_command(const String &command, const Array &args);
|
||||
int get_camera_mode() const;
|
||||
int get_selected_building() const;
|
||||
Transform get_selected_building_xform() const;
|
||||
void select_building(const Transform &xform, int id, const String &mid);
|
||||
void remove_buildings_by_prefix(const String &prefix);
|
||||
int get_current_mode() const;
|
||||
class EventHelper {
|
||||
class event_listener_ptrs {
|
||||
public:
|
||||
class H {};
|
||||
H *obj;
|
||||
void (H::*method)(const String &event,
|
||||
const Array &args);
|
||||
void execute(const String &event,
|
||||
const Array &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 Array &args);
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
void add_listener(T *obj, void (T::*method)(const String &event,
|
||||
const Array &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);
|
||||
}
|
||||
template <class T>
|
||||
void remove_listener(T *obj,
|
||||
void (T::*method)(const String &event,
|
||||
const Array &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);
|
||||
});
|
||||
}
|
||||
void emit(const String &event, const Array &args)
|
||||
{
|
||||
auto evl = listeners.begin();
|
||||
while (evl != listeners.end()) {
|
||||
const event_listener_ptrs &xev = *evl;
|
||||
xev.execute(event, args);
|
||||
evl++;
|
||||
}
|
||||
}
|
||||
};
|
||||
EventHelper event;
|
||||
void event_signal_handler(const String &event, const Array &args);
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user