Almost separated the buildings editor
This commit is contained in:
@@ -10,9 +10,9 @@ onready var vmode = {
|
|||||||
7: $"%v_npc",
|
7: $"%v_npc",
|
||||||
}
|
}
|
||||||
|
|
||||||
func change_building_type(index):
|
#func change_building_type(index):
|
||||||
var item = $"%building_type".get_item_text(index)
|
# var item = $"%building_type".get_item_text(index)
|
||||||
$WorldEditor.editor_command("change_building_type", [selected_building, item])
|
# $WorldEditor.editor_command("change_building_type", [selected_building, item])
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
for b in [
|
for b in [
|
||||||
@@ -27,9 +27,9 @@ func _ready():
|
|||||||
$WorldEditor.connect("editor_event", self, "editor_event")
|
$WorldEditor.connect("editor_event", self, "editor_event")
|
||||||
for k in vmode.keys():
|
for k in vmode.keys():
|
||||||
vmode[k].hide()
|
vmode[k].hide()
|
||||||
$building_cursor.hide()
|
$"%building_cursor".hide()
|
||||||
$"%line_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):
|
func editor_event(evname: String, args: Array):
|
||||||
print(evname, args)
|
print(evname, args)
|
||||||
@@ -49,8 +49,9 @@ func editor_event(evname: String, args: Array):
|
|||||||
elif mode_next == 6:
|
elif mode_next == 6:
|
||||||
$WorldEditor.editor_command("get_lines_list", [])
|
$WorldEditor.editor_command("get_lines_list", [])
|
||||||
elif evname == "result:get_closest_building":
|
elif evname == "result:get_closest_building":
|
||||||
print(evname, args)
|
pass
|
||||||
select_building(args[0], args[3], args[4])
|
# print(evname, args)
|
||||||
|
# select_building(args[0], args[3], args[4])
|
||||||
elif evname == "result:get_building_types":
|
elif evname == "result:get_building_types":
|
||||||
print(evname, args)
|
print(evname, args)
|
||||||
var btypes = args[0]
|
var btypes = args[0]
|
||||||
@@ -63,9 +64,11 @@ func editor_event(evname: String, args: Array):
|
|||||||
# elif evname == "edit_update_building":
|
# elif evname == "edit_update_building":
|
||||||
# check_edit_building()
|
# check_edit_building()
|
||||||
elif evname == "mouse_press":
|
elif evname == "mouse_press":
|
||||||
mouse_press(args[0])
|
pass
|
||||||
|
# mouse_press(args[0])
|
||||||
elif evname == "mouse_drag":
|
elif evname == "mouse_drag":
|
||||||
mouse_drag(args[0])
|
pass
|
||||||
|
# mouse_drag(args[0])
|
||||||
elif evname == "mouse_drag_on":
|
elif evname == "mouse_drag_on":
|
||||||
pass
|
pass
|
||||||
elif evname == "mouse_drag_off":
|
elif evname == "mouse_drag_off":
|
||||||
@@ -74,87 +77,87 @@ func editor_event(evname: String, args: Array):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
breakpoint
|
breakpoint
|
||||||
func mouse_drag(position):
|
#func mouse_drag(position):
|
||||||
if $WorldEditor.get_current_mode() != 2:
|
# if $WorldEditor.get_current_mode() != 2:
|
||||||
return
|
# return
|
||||||
if $WorldEditor.get_camera_mode() != 3:
|
# if $WorldEditor.get_camera_mode() != 3:
|
||||||
return
|
# return
|
||||||
# breakpoint
|
## breakpoint
|
||||||
var camera = get_viewport().get_camera()
|
# var camera = get_viewport().get_camera()
|
||||||
var start = camera.project_ray_origin(position)
|
# var start = camera.project_ray_origin(position)
|
||||||
var normal = camera.project_ray_normal(position)
|
# var normal = camera.project_ray_normal(position)
|
||||||
var end = start + normal * camera.get_zfar()
|
# var end = start + normal * camera.get_zfar()
|
||||||
var space_state = get_world().direct_space_state
|
# var space_state = get_world().direct_space_state
|
||||||
var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
# var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
||||||
if result.has("collider"):
|
# if result.has("collider"):
|
||||||
var proj = result.position
|
# var proj = result.position
|
||||||
var mode = $"%buildings_edit_mode".selected
|
# var mode = $"%buildings_edit_mode".selected
|
||||||
if mode == 1:
|
# if mode == 1:
|
||||||
# move
|
# # move
|
||||||
print(proj)
|
# print(proj)
|
||||||
var newpos = proj
|
# var newpos = proj
|
||||||
newpos.x = stepify(newpos.x, 2.0)
|
# newpos.x = stepify(newpos.x, 2.0)
|
||||||
newpos.z = stepify(newpos.z, 2.0)
|
# newpos.z = stepify(newpos.z, 2.0)
|
||||||
var gen: VoxelGeneratorImgMapper = $VoxelLodTerrain.generator
|
# var gen: VoxelGeneratorImgMapper = $"%VoxelLodTerrain".generator
|
||||||
var hpos = gen.get_height_full(newpos)
|
# var hpos = gen.get_height_full(newpos)
|
||||||
newpos.y = hpos
|
# newpos.y = hpos
|
||||||
$WorldEditor.editor_command("update_building_transform", [selected_building, Transform(selected_building_xform.basis, newpos)])
|
# $WorldEditor.editor_command("update_building_transform", [selected_building, Transform(selected_building_xform.basis, newpos)])
|
||||||
selected_building_xform = Transform(selected_building_xform.basis, newpos)
|
# selected_building_xform = Transform(selected_building_xform.basis, newpos)
|
||||||
$building_cursor.global_transform.origin = newpos
|
# $"%building_cursor".global_transform.origin = newpos
|
||||||
elif mode == 2:
|
# elif mode == 2:
|
||||||
# rotate
|
# # rotate
|
||||||
var m = proj
|
# var m = proj
|
||||||
m.y = selected_building_xform.origin.y
|
# m.y = selected_building_xform.origin.y
|
||||||
var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
# var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
||||||
$WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
# $WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
||||||
$building_rot_cursor.global_transform = xform
|
# $"%building_rot_cursor".global_transform = xform
|
||||||
selected_building_xform = xform
|
# selected_building_xform = xform
|
||||||
func mouse_press(position):
|
#func mouse_press(position):
|
||||||
if $WorldEditor.get_current_mode() != 2:
|
# if $WorldEditor.get_current_mode() != 2:
|
||||||
return
|
# return
|
||||||
if $WorldEditor.get_camera_mode() != 3:
|
# if $WorldEditor.get_camera_mode() != 3:
|
||||||
return
|
# return
|
||||||
# breakpoint
|
## breakpoint
|
||||||
# dragging = true
|
## dragging = true
|
||||||
var camera = get_viewport().get_camera()
|
# var camera = get_viewport().get_camera()
|
||||||
var start = camera.project_ray_origin(position)
|
# var start = camera.project_ray_origin(position)
|
||||||
var normal = camera.project_ray_normal(position)
|
# var normal = camera.project_ray_normal(position)
|
||||||
var end = start + normal * camera.get_zfar()
|
# var end = start + normal * camera.get_zfar()
|
||||||
var space_state = get_world().direct_space_state
|
# var space_state = get_world().direct_space_state
|
||||||
var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
# var result = space_state.intersect_ray(start, end, [], 1 << 15, false, true)
|
||||||
if result.has("collider"):
|
# if result.has("collider"):
|
||||||
var proj = result.position
|
# var proj = result.position
|
||||||
drag_start = proj
|
# drag_start = proj
|
||||||
var mode = $"%buildings_edit_mode".selected
|
# var mode = $"%buildings_edit_mode".selected
|
||||||
if mode == 0:
|
# if mode == 0:
|
||||||
print("get closest building")
|
# print("get closest building")
|
||||||
$WorldEditor.editor_command("get_closest_building", [Transform(Basis(), proj)])
|
# $WorldEditor.editor_command("get_closest_building", [Transform(Basis(), proj)])
|
||||||
elif mode == 1:
|
# elif mode == 1:
|
||||||
$WorldEditor.editor_command("checkpoint", [])
|
# $WorldEditor.editor_command("checkpoint", [])
|
||||||
elif mode == 2:
|
# elif mode == 2:
|
||||||
$WorldEditor.editor_command("checkpoint", [])
|
# $WorldEditor.editor_command("checkpoint", [])
|
||||||
var m = proj
|
# var m = proj
|
||||||
m.y = selected_building_xform.origin.y
|
# m.y = selected_building_xform.origin.y
|
||||||
var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
# var xform = selected_building_xform.looking_at(m, Vector3.UP)
|
||||||
$WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
# $WorldEditor.editor_command("update_building_transform", [selected_building, xform])
|
||||||
$building_rot_cursor.global_transform = xform
|
# $"%building_rot_cursor".global_transform = xform
|
||||||
selected_building_xform = xform
|
# selected_building_xform = xform
|
||||||
|
|
||||||
var selected_building
|
#var selected_building
|
||||||
var selected_building_xform
|
var selected_building_xform
|
||||||
func select_building(xform, id, mid):
|
#func select_building(xform, id, mid):
|
||||||
selected_building = id
|
# selected_building = id
|
||||||
selected_building_xform = xform
|
# selected_building_xform = xform
|
||||||
print("selected id: ", id)
|
# print("selected id: ", id)
|
||||||
$WorldEditor.select_building(xform, id, mid)
|
# $WorldEditor.select_building(xform, id, mid)
|
||||||
# for h in range($"%building_type".get_item_count()):
|
# for h in range($"%building_type".get_item_count()):
|
||||||
# var item = $"%building_type".get_item_text(h)
|
# var item = $"%building_type".get_item_text(h)
|
||||||
# if item == mid:
|
# if item == mid:
|
||||||
# $"%building_type".select(h)
|
# $"%building_type".select(h)
|
||||||
# break
|
# break
|
||||||
if !$building_cursor.visible:
|
# if !$"%building_cursor".visible:
|
||||||
$building_cursor.show()
|
# $"%building_cursor".show()
|
||||||
$building_cursor.global_transform.origin = xform.origin
|
# $"%building_cursor".global_transform.origin = xform.origin
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
# if Input.is_action_just_pressed("editor_cam1"):
|
# if Input.is_action_just_pressed("editor_cam1"):
|
||||||
# setup_cam1()
|
# setup_cam1()
|
||||||
@@ -163,13 +166,13 @@ func _process(delta):
|
|||||||
# if Input.is_action_just_pressed("editor_cam3"):
|
# if Input.is_action_just_pressed("editor_cam3"):
|
||||||
# setup_cam3()
|
# setup_cam3()
|
||||||
var mode = $"%buildings_edit_mode".selected
|
var mode = $"%buildings_edit_mode".selected
|
||||||
if mode == 2:
|
# if mode == 2:
|
||||||
$building_rot_cursor.global_transform = selected_building_xform
|
# $"%building_rot_cursor".global_transform = selected_building_xform
|
||||||
if !$building_rot_cursor.visible:
|
# if !$"%building_rot_cursor".visible:
|
||||||
$building_rot_cursor.show()
|
# $"%building_rot_cursor".show()
|
||||||
else:
|
# else:
|
||||||
if $building_rot_cursor.visible:
|
# if $"%building_rot_cursor".visible:
|
||||||
$building_rot_cursor.hide()
|
# $"%building_rot_cursor".hide()
|
||||||
# if dragging:
|
# if dragging:
|
||||||
# if !Input.is_action_pressed("mouse1"):
|
# if !Input.is_action_pressed("mouse1"):
|
||||||
# dragging = false
|
# dragging = false
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ text = "NPC Mode"
|
|||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 154.0
|
margin_top = 154.0
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 298.0
|
margin_bottom = 322.0
|
||||||
|
|
||||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_buildings"]
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_buildings"]
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
@@ -134,7 +134,7 @@ margin_top = 26.0
|
|||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 46.0
|
margin_bottom = 46.0
|
||||||
text = "Select"
|
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
|
selected = 0
|
||||||
|
|
||||||
[node name="Label2" type="Label" parent="VBoxContainer/v_buildings"]
|
[node name="Label2" type="Label" parent="VBoxContainer/v_buildings"]
|
||||||
@@ -162,18 +162,25 @@ margin_right = 232.0
|
|||||||
margin_bottom = 120.0
|
margin_bottom = 120.0
|
||||||
text = "Delete building"
|
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
|
unique_name_in_owner = true
|
||||||
margin_top = 124.0
|
margin_top = 124.0
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 144.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"
|
text = "Save Buildings"
|
||||||
|
|
||||||
[node name="v_navigation" type="VBoxContainer" parent="VBoxContainer"]
|
[node name="v_navigation" type="VBoxContainer" parent="VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 302.0
|
margin_top = 326.0
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 324.0
|
margin_bottom = 348.0
|
||||||
|
|
||||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_navigation"]
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_navigation"]
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
@@ -187,9 +194,9 @@ text = "Navigation mode"
|
|||||||
|
|
||||||
[node name="v_poi" type="VBoxContainer" parent="VBoxContainer"]
|
[node name="v_poi" type="VBoxContainer" parent="VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 328.0
|
margin_top = 352.0
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 350.0
|
margin_bottom = 374.0
|
||||||
|
|
||||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_poi"]
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_poi"]
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
@@ -203,9 +210,9 @@ text = "POI mode"
|
|||||||
|
|
||||||
[node name="v_road_lines" type="VBoxContainer" parent="VBoxContainer"]
|
[node name="v_road_lines" type="VBoxContainer" parent="VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 354.0
|
margin_top = 378.0
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 962.0
|
margin_bottom = 986.0
|
||||||
|
|
||||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"]
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"]
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
@@ -462,9 +469,9 @@ text = "Cancel"
|
|||||||
|
|
||||||
[node name="v_npc" type="VBoxContainer" parent="VBoxContainer"]
|
[node name="v_npc" type="VBoxContainer" parent="VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 966.0
|
margin_top = 990.0
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
margin_bottom = 988.0
|
margin_bottom = 1012.0
|
||||||
|
|
||||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"]
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"]
|
||||||
margin_right = 232.0
|
margin_right = 232.0
|
||||||
@@ -479,6 +486,7 @@ text = "NPC mode"
|
|||||||
[node name="StreamWorld" type="StreamWorld" parent="."]
|
[node name="StreamWorld" type="StreamWorld" parent="."]
|
||||||
|
|
||||||
[node name="VoxelLodTerrain" type="VoxelLodTerrain" parent="."]
|
[node name="VoxelLodTerrain" type="VoxelLodTerrain" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
generator = SubResource( 5 )
|
generator = SubResource( 5 )
|
||||||
mesher = SubResource( 6 )
|
mesher = SubResource( 6 )
|
||||||
voxel_bounds = AABB( -5.36871e+08, -2048, -5.36871e+08, 1.07374e+09, 4096, 1.07374e+09 )
|
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 )
|
shape = SubResource( 9 )
|
||||||
|
|
||||||
[node name="building_cursor" type="MeshInstance" parent="."]
|
[node name="building_cursor" type="MeshInstance" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
mesh = SubResource( 10 )
|
mesh = SubResource( 10 )
|
||||||
material/0 = SubResource( 11 )
|
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 )
|
shape = SubResource( 12 )
|
||||||
|
|
||||||
[node name="building_rot_cursor" type="Spatial" parent="."]
|
[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"]
|
[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 )
|
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/dir_access.h>
|
||||||
#include <core/os/time.h>
|
#include <core/os/time.h>
|
||||||
#include <core/math/geometry.h>
|
#include <core/math/geometry.h>
|
||||||
|
#include <scene/3d/immediate_geometry.h>
|
||||||
|
#include <scene/main/viewport.h>
|
||||||
#include "from_string.h"
|
#include "from_string.h"
|
||||||
#include "road_lines_data.h"
|
#include "road_lines_data.h"
|
||||||
|
|
||||||
|
static ImmediateGeometry *debug_im;
|
||||||
|
static Ref<Material> debug_material;
|
||||||
RoadLinesData::RoadLinesData()
|
RoadLinesData::RoadLinesData()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -66,6 +71,14 @@ RoadLinesData *RoadLinesData::get_singleton()
|
|||||||
return singleton;
|
return singleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoadLinesData::~RoadLinesData()
|
||||||
|
{
|
||||||
|
if (debug_im) {
|
||||||
|
memdelete(debug_im);
|
||||||
|
debug_im = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RoadLinesData::cleanup()
|
void RoadLinesData::cleanup()
|
||||||
{
|
{
|
||||||
memdelete(singleton);
|
memdelete(singleton);
|
||||||
@@ -211,54 +224,72 @@ void RoadLinesData::index_lines(
|
|||||||
e = e->next();
|
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,
|
void RoadLinesData::create_segments(const String &road,
|
||||||
std::vector<int> &segments)
|
std::vector<int> &segments)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
for (i = 0; i < (int)rld->lines[road].indices.size() - 1; i++) {
|
for (i = 0; i < (int)rld->lines[road].indices.size() - 1; i++) {
|
||||||
int idx1 = rld->lines[road].indices[i];
|
segments.push_back(i);
|
||||||
int idx2 = rld->lines[road].indices[i + 1];
|
|
||||||
segments.push_back(idx1);
|
|
||||||
segments.push_back(idx2);
|
|
||||||
segments.push_back(i + 1);
|
segments.push_back(i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* add close points on each line to the line */
|
/* 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;
|
int i;
|
||||||
List<String> keys;
|
List<String> keys;
|
||||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
get_road_lines_key_list(&keys);
|
||||||
rld->get_road_lines_key_list(&keys);
|
|
||||||
List<String>::Element *e = keys.front();
|
List<String>::Element *e = keys.front();
|
||||||
for (i = 0; i < (int)road_lines_nodes.size(); i++) {
|
for (i = 0; i < (int)road_lines_nodes.size(); i++) {
|
||||||
int idx3 = i;
|
int idx3 = i;
|
||||||
|
Vector3 p3 = road_lines_nodes[idx3];
|
||||||
|
/* Checking each road point against
|
||||||
|
all line segments */
|
||||||
while (e) {
|
while (e) {
|
||||||
int j;
|
int j;
|
||||||
std::vector<int> segments;
|
std::vector<int> segments;
|
||||||
String rkey = e->get();
|
String rkey = e->get();
|
||||||
create_segments(rkey, segments);
|
create_segments(rkey, segments);
|
||||||
for (j = 0; j < (int)segments.size(); j += 3) {
|
for (j = 0; j < (int)segments.size(); j += 2) {
|
||||||
int idx1 = segments[j];
|
/* indices in road_lines_nodes */
|
||||||
int idx2 = segments[j + 1];
|
int idx1 = get_segment_index(rkey, segments[j]);
|
||||||
int idx = segments[j + 2];
|
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 */
|
/* Skip segment point */
|
||||||
if (idx3 == idx1 || idx3 == idx2)
|
if (idx3 == idx1 || idx3 == idx2)
|
||||||
continue;
|
continue;
|
||||||
Vector3 p1 = road_lines_nodes[idx1];
|
Vector3 p1 = road_lines_nodes[idx1];
|
||||||
Vector3 p2 = road_lines_nodes[idx2];
|
Vector3 p2 = road_lines_nodes[idx2];
|
||||||
Vector3 p3 = road_lines_nodes[idx3];
|
|
||||||
std::vector<Vector3> seg = { p1, p2 };
|
std::vector<Vector3> seg = { p1, p2 };
|
||||||
Vector3 closest =
|
Vector3 closest =
|
||||||
Geometry::get_closest_point_to_segment(
|
Geometry::get_closest_point_to_segment(
|
||||||
p3, seg.data());
|
p3, seg.data());
|
||||||
if (p3.distance_squared_to(closest) < 160) {
|
/* should be no duplicate points
|
||||||
road_lines_nodes[idx3] = closest;
|
in road_lines_nodes */
|
||||||
rld->lines[rkey].indices.insert(
|
if (closest.is_equal_approx(p1))
|
||||||
rld->lines[rkey].indices.begin() +
|
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,
|
idx,
|
||||||
idx3);
|
idx3);
|
||||||
|
road_lines_nodes[idx3] = closest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e = e->next();
|
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(
|
void RoadLinesData::process_lines(
|
||||||
std::unordered_map<uint32_t, std::vector<Vector3> >
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
&road_lines_nodes_hash,
|
&road_lines_nodes_hash,
|
||||||
std::vector<Vector3> &road_lines_nodes)
|
std::vector<Vector3> &road_lines_nodes)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
get_debug_node();
|
||||||
|
debug_im->clear();
|
||||||
index_lines(road_lines_nodes_hash, road_lines_nodes);
|
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);
|
update_road_lines_nodes(road_lines_nodes);
|
||||||
dump_road_lines(road_lines_nodes);
|
dump_road_lines(road_lines_nodes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
};
|
};
|
||||||
HashMap<String, struct road_line> lines;
|
HashMap<String, struct road_line> lines;
|
||||||
static RoadLinesData *get_singleton();
|
static RoadLinesData *get_singleton();
|
||||||
|
virtual ~RoadLinesData();
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
String get_road_lines_path();
|
String get_road_lines_path();
|
||||||
void get_road_lines_key_list(List<String> *keys);
|
void get_road_lines_key_list(List<String> *keys);
|
||||||
@@ -36,8 +37,8 @@ private:
|
|||||||
std::vector<Vector3> &road_lines_nodes);
|
std::vector<Vector3> &road_lines_nodes);
|
||||||
|
|
||||||
void create_segments(const String &road, std::vector<int> &segments);
|
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);
|
void update_road_lines_nodes(std::vector<Vector3> &road_lines_nodes);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "road_lines_editor.h"
|
#include "road_lines_editor.h"
|
||||||
|
|
||||||
static ImmediateGeometry *line_im = nullptr;
|
static ImmediateGeometry *line_im = nullptr;
|
||||||
|
// static ImmediateGeometry *debug_im = nullptr;
|
||||||
static Ref<Material> debug_material;
|
static Ref<Material> debug_material;
|
||||||
|
|
||||||
#define __evhandler(vname, mtype) \
|
#define __evhandler(vname, mtype) \
|
||||||
@@ -946,7 +947,9 @@ void RoadLinesEditor::handle_input()
|
|||||||
}
|
}
|
||||||
void RoadLinesEditor::place_zebras()
|
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():
|
func place_zebras():
|
||||||
var road_nodes = SceneComps.get_component("road_nodes2")
|
var road_nodes = SceneComps.get_component("road_nodes2")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <core/os/file_access.h>
|
#include <core/os/file_access.h>
|
||||||
#include <scene/resources/mesh.h>
|
#include <scene/resources/mesh.h>
|
||||||
#include <scene/3d/mesh_instance.h>
|
#include <scene/3d/mesh_instance.h>
|
||||||
|
#include <scene/3d/immediate_geometry.h>
|
||||||
#include <core/math/transform.h>
|
#include <core/math/transform.h>
|
||||||
#include <core/math/geometry.h>
|
#include <core/math/geometry.h>
|
||||||
#include <core/math/vector2.h>
|
#include <core/math/vector2.h>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ROAD_LINES_PROCESSING_H_
|
#ifndef ROAD_LINES_PROCESSING_H_
|
||||||
#define ROAD_LINES_PROCESSSING_H_
|
#define ROAD_LINES_PROCESSSING_H_
|
||||||
class Node;
|
class Node;
|
||||||
|
class ImmediateGeometry;
|
||||||
class RoadProcessing {
|
class RoadProcessing {
|
||||||
public:
|
public:
|
||||||
static void road_setup(Node *target);
|
static void road_setup(Node *target);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <scene/scene_string_names.h>
|
#include <scene/scene_string_names.h>
|
||||||
#include "road_lines_editor.h"
|
#include "road_lines_editor.h"
|
||||||
#include "world_editor.h"
|
#include "world_editor.h"
|
||||||
|
#include "buildings_editor.h"
|
||||||
|
|
||||||
WorldEditor::WorldEditor()
|
WorldEditor::WorldEditor()
|
||||||
: Spatial()
|
: Spatial()
|
||||||
@@ -25,7 +26,7 @@ WorldEditor::WorldEditor()
|
|||||||
, dragging(false)
|
, dragging(false)
|
||||||
, drag_delay(0.2f)
|
, drag_delay(0.2f)
|
||||||
, road_lines_editor(memnew(RoadLinesEditor(this)))
|
, road_lines_editor(memnew(RoadLinesEditor(this)))
|
||||||
, selected_building(-1)
|
, buildings_editor(memnew(BuildingsEditor(this)))
|
||||||
{
|
{
|
||||||
if (!InputMap::get_singleton()->has_action("left"))
|
if (!InputMap::get_singleton()->has_action("left"))
|
||||||
InputMap::get_singleton()->add_action("left");
|
InputMap::get_singleton()->add_action("left");
|
||||||
@@ -47,11 +48,20 @@ WorldEditor::WorldEditor()
|
|||||||
InputMap::get_singleton()->add_action("editor_cam3");
|
InputMap::get_singleton()->add_action("editor_cam3");
|
||||||
if (!InputMap::get_singleton()->has_action("mouse1"))
|
if (!InputMap::get_singleton()->has_action("mouse1"))
|
||||||
InputMap::get_singleton()->add_action("mouse1");
|
InputMap::get_singleton()->add_action("mouse1");
|
||||||
|
event.add_listener(this, &WorldEditor::event_signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldEditor::~WorldEditor()
|
WorldEditor::~WorldEditor()
|
||||||
{
|
{
|
||||||
|
event.remove_listener(this, &WorldEditor::event_signal_handler);
|
||||||
|
if (road_lines_editor) {
|
||||||
memdelete(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)
|
void WorldEditor::set_camera_mode(int mode)
|
||||||
@@ -100,16 +110,6 @@ int WorldEditor::get_camera_mode() const
|
|||||||
return current_camera_mode;
|
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()
|
void WorldEditor::disable_all()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -143,13 +143,6 @@ void WorldEditor::mode_npc()
|
|||||||
disable_all();
|
disable_all();
|
||||||
print_line("NPC");
|
print_line("NPC");
|
||||||
}
|
}
|
||||||
enum {
|
|
||||||
MODE_BUILDINGS = 2,
|
|
||||||
MODE_NAVIGATION = 3,
|
|
||||||
MODE_POI = 5,
|
|
||||||
MODE_ROAD_LINES = 6,
|
|
||||||
MODE_NPC = 7,
|
|
||||||
};
|
|
||||||
struct StringHasher {
|
struct StringHasher {
|
||||||
std::size_t operator()(const String &s) const
|
std::size_t operator()(const String &s) const
|
||||||
{
|
{
|
||||||
@@ -157,11 +150,11 @@ struct StringHasher {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
static std::unordered_map<String, int, StringHasher> modes = {
|
static std::unordered_map<String, int, StringHasher> modes = {
|
||||||
{ "select_buildings", MODE_BUILDINGS },
|
{ "select_buildings", WorldEditor::MODE_BUILDINGS },
|
||||||
{ "select_navigation", MODE_NAVIGATION },
|
{ "select_navigation", WorldEditor::MODE_NAVIGATION },
|
||||||
{ "select_poi", MODE_POI },
|
{ "select_poi", WorldEditor::MODE_POI },
|
||||||
{ "select_road_lines", MODE_ROAD_LINES },
|
{ "select_road_lines", WorldEditor::MODE_ROAD_LINES },
|
||||||
{ "select_npc", MODE_NPC }
|
{ "select_npc", WorldEditor::MODE_NPC }
|
||||||
};
|
};
|
||||||
void WorldEditor::tools_button(const String &button)
|
void WorldEditor::tools_button(const String &button)
|
||||||
{
|
{
|
||||||
@@ -174,7 +167,7 @@ void WorldEditor::tools_button(const String &button)
|
|||||||
goto end;
|
goto end;
|
||||||
change[0] = current_mode;
|
change[0] = current_mode;
|
||||||
change[1] = modes[button];
|
change[1] = modes[button];
|
||||||
emit_signal("editor_event", "mode_change_pre", change);
|
event.emit("mode_change_pre", change);
|
||||||
switch (current_mode) {
|
switch (current_mode) {
|
||||||
case MODE_ROAD_LINES:
|
case MODE_ROAD_LINES:
|
||||||
road_lines_editor->exit();
|
road_lines_editor->exit();
|
||||||
@@ -197,7 +190,7 @@ void WorldEditor::tools_button(const String &button)
|
|||||||
mode_npc();
|
mode_npc();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
emit_signal("editor_event", "mode_change_post", change);
|
event.emit("mode_change_post", change);
|
||||||
current_mode = modes[button];
|
current_mode = modes[button];
|
||||||
end:;
|
end:;
|
||||||
}
|
}
|
||||||
@@ -237,8 +230,6 @@ void WorldEditor::editor_command(const String &command, const Array &args)
|
|||||||
if (stream_world) {
|
if (stream_world) {
|
||||||
stream_world->run_command(command, args);
|
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") {
|
} else if (command == "remove_generated_stuff") {
|
||||||
if (stream_world)
|
if (stream_world)
|
||||||
stream_world->run_command(command, args);
|
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") {
|
} else if (command == "remove_road_meshes") {
|
||||||
if (stream_world)
|
if (stream_world)
|
||||||
stream_world->run_command(command, args);
|
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);
|
road_lines_editor->editor_command(command, args);
|
||||||
}
|
if (buildings_editor)
|
||||||
}
|
buildings_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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +258,11 @@ int WorldEditor::get_current_mode() const
|
|||||||
return current_mode;
|
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()
|
StreamWorld *WorldEditor::get_stream_world()
|
||||||
{
|
{
|
||||||
return 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)
|
void WorldEditor::world_command_result(const String &what, const Array &data)
|
||||||
{
|
{
|
||||||
print_line("what: " + what);
|
print_line("what: " + what);
|
||||||
emit_signal("editor_event", "result:" + what, data);
|
event.emit("result:" + what, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldEditor::_notification(int which)
|
void WorldEditor::_notification(int which)
|
||||||
@@ -320,6 +296,14 @@ void WorldEditor::_notification(int which)
|
|||||||
}
|
}
|
||||||
set_process_unhandled_input(true);
|
set_process_unhandled_input(true);
|
||||||
set_physics_process(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;
|
} break;
|
||||||
case NOTIFICATION_EXIT_TREE:
|
case NOTIFICATION_EXIT_TREE:
|
||||||
set_physics_process(false);
|
set_physics_process(false);
|
||||||
@@ -342,8 +326,7 @@ void WorldEditor::_notification(int which)
|
|||||||
Vector2 position =
|
Vector2 position =
|
||||||
get_viewport()->get_mouse_position();
|
get_viewport()->get_mouse_position();
|
||||||
args.push_back(position);
|
args.push_back(position);
|
||||||
emit_signal("editor_event", "mouse_drag_off",
|
event.emit("mouse_drag_off", args);
|
||||||
args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Transform cam_xform = cam->get_global_transform();
|
Transform cam_xform = cam->get_global_transform();
|
||||||
@@ -382,13 +365,15 @@ void WorldEditor::_notification(int which)
|
|||||||
cam->set_global_transform(cam_xform);
|
cam->set_global_transform(cam_xform);
|
||||||
Array move_args;
|
Array move_args;
|
||||||
move_args.push_back(cam_xform);
|
move_args.push_back(cam_xform);
|
||||||
emit_signal("editor_event",
|
event.emit("editor_camera_moved", move_args);
|
||||||
"editor_camera_moved", move_args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!dragging && drag_delay >= 0.0f)
|
if (!dragging && drag_delay >= 0.0f)
|
||||||
drag_delay -= delta;
|
drag_delay -= delta;
|
||||||
switch (current_mode) {
|
switch (current_mode) {
|
||||||
|
case MODE_BUILDINGS:
|
||||||
|
buildings_editor->update(delta);
|
||||||
|
break;
|
||||||
case MODE_ROAD_LINES:
|
case MODE_ROAD_LINES:
|
||||||
// print_line("current_mode: " + itos(current_mode));
|
// print_line("current_mode: " + itos(current_mode));
|
||||||
road_lines_editor->update(delta);
|
road_lines_editor->update(delta);
|
||||||
@@ -415,13 +400,13 @@ void WorldEditor::_unhandled_input(const Ref<InputEvent> &event)
|
|||||||
Array args;
|
Array args;
|
||||||
Vector2 position = get_viewport()->get_mouse_position();
|
Vector2 position = get_viewport()->get_mouse_position();
|
||||||
args.push_back(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")) {
|
} else if (Input::get_singleton()->is_action_pressed("mouse1")) {
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
Array args;
|
Array args;
|
||||||
Vector2 position = get_viewport()->get_mouse_position();
|
Vector2 position = get_viewport()->get_mouse_position();
|
||||||
args.push_back(position);
|
args.push_back(position);
|
||||||
emit_signal("editor_event", "mouse_drag", args);
|
this->event.emit("mouse_drag", args);
|
||||||
} else {
|
} else {
|
||||||
if (drag_delay < 0.0f && !dragging) {
|
if (drag_delay < 0.0f && !dragging) {
|
||||||
dragging = true;
|
dragging = true;
|
||||||
@@ -429,8 +414,7 @@ void WorldEditor::_unhandled_input(const Ref<InputEvent> &event)
|
|||||||
Vector2 position =
|
Vector2 position =
|
||||||
get_viewport()->get_mouse_position();
|
get_viewport()->get_mouse_position();
|
||||||
args.push_back(position);
|
args.push_back(position);
|
||||||
emit_signal("editor_event", "mouse_drag_on",
|
this->event.emit("mouse_drag_on", args);
|
||||||
args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,22 +427,6 @@ void WorldEditor::world_exited()
|
|||||||
stream_world = nullptr;
|
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()
|
void WorldEditor::_bind_methods()
|
||||||
{
|
{
|
||||||
ClassDB::bind_method(D_METHOD("editor_command", "command", "args"),
|
ClassDB::bind_method(D_METHOD("editor_command", "command", "args"),
|
||||||
@@ -475,16 +443,8 @@ void WorldEditor::_bind_methods()
|
|||||||
&WorldEditor::set_camera_mode);
|
&WorldEditor::set_camera_mode);
|
||||||
ClassDB::bind_method(D_METHOD("get_camera_mode"),
|
ClassDB::bind_method(D_METHOD("get_camera_mode"),
|
||||||
&WorldEditor::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"),
|
ClassDB::bind_method(D_METHOD("_unhandled_input", "event"),
|
||||||
&WorldEditor::_unhandled_input);
|
&WorldEditor::_unhandled_input);
|
||||||
ClassDB::bind_method(D_METHOD("delete_building_handler"),
|
|
||||||
&WorldEditor::delete_building_handler);
|
|
||||||
ADD_SIGNAL(MethodInfo("editor_event",
|
ADD_SIGNAL(MethodInfo("editor_event",
|
||||||
PropertyInfo(Variant::STRING, "event_name"),
|
PropertyInfo(Variant::STRING, "event_name"),
|
||||||
PropertyInfo(Variant::ARRAY, "args")));
|
PropertyInfo(Variant::ARRAY, "args")));
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#ifndef WORLD_EDITOR_H
|
#ifndef WORLD_EDITOR_H
|
||||||
#define WORLD_EDITOR_H
|
#define WORLD_EDITOR_H
|
||||||
|
#include <list>
|
||||||
#include <scene/3d/spatial.h>
|
#include <scene/3d/spatial.h>
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
class RoadLinesEditor;
|
class RoadLinesEditor;
|
||||||
|
class BuildingsEditor;
|
||||||
class WorldEditor : public Spatial {
|
class WorldEditor : public Spatial {
|
||||||
GDCLASS(WorldEditor, Spatial)
|
GDCLASS(WorldEditor, Spatial)
|
||||||
protected:
|
protected:
|
||||||
@@ -16,7 +18,6 @@ protected:
|
|||||||
void mode_road_lines();
|
void mode_road_lines();
|
||||||
void mode_npc();
|
void mode_npc();
|
||||||
void tools_button(const String &button);
|
void tools_button(const String &button);
|
||||||
int get_current_mode() const;
|
|
||||||
StreamWorld *get_stream_world();
|
StreamWorld *get_stream_world();
|
||||||
void world_command_result(const String &what, const Array &data);
|
void world_command_result(const String &what, const Array &data);
|
||||||
void _notification(int which);
|
void _notification(int which);
|
||||||
@@ -32,18 +33,87 @@ private:
|
|||||||
bool dragging;
|
bool dragging;
|
||||||
float drag_delay;
|
float drag_delay;
|
||||||
RoadLinesEditor *road_lines_editor;
|
RoadLinesEditor *road_lines_editor;
|
||||||
int selected_building;
|
BuildingsEditor *buildings_editor;
|
||||||
Transform selected_building_xform;
|
|
||||||
void delete_building_handler();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum {
|
||||||
|
MODE_BUILDINGS = 2,
|
||||||
|
MODE_NAVIGATION = 3,
|
||||||
|
MODE_POI = 5,
|
||||||
|
MODE_ROAD_LINES = 6,
|
||||||
|
MODE_NPC = 7,
|
||||||
|
};
|
||||||
WorldEditor();
|
WorldEditor();
|
||||||
virtual ~WorldEditor();
|
virtual ~WorldEditor();
|
||||||
void editor_command(const String &command, const Array &args);
|
void editor_command(const String &command, const Array &args);
|
||||||
int get_camera_mode() const;
|
int get_camera_mode() const;
|
||||||
int get_selected_building() const;
|
int get_current_mode() const;
|
||||||
Transform get_selected_building_xform() const;
|
class EventHelper {
|
||||||
void select_building(const Transform &xform, int id, const String &mid);
|
class event_listener_ptrs {
|
||||||
void remove_buildings_by_prefix(const String &prefix);
|
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
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user