godot/tools/editor/plugins/spatial_editor_plugin.cpp
Rémi Verschelde c4d6e54e93 Remove Quick Filter Files and fix FS search hotkey
The new Quick Filter Files behaviour since 8b47e26 had not been implemented,
so this implements it and makes it an editor hotkey instead of a menu entry.
Fixes #7582.
2017-01-21 13:07:32 +01:00

4188 lines
123 KiB
C++

/*************************************************************************/
/* spatial_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "spatial_editor_plugin.h"
#include "print_string.h"
#include "os/keyboard.h"
#include "scene/3d/visual_instance.h"
#include "scene/3d/camera.h"
#include "camera_matrix.h"
#include "sort.h"
#include "tools/editor/editor_node.h"
#include "tools/editor/editor_settings.h"
#include "scene/resources/surface_tool.h"
#include "tools/editor/spatial_editor_gizmos.h"
#include "globals.h"
#include "tools/editor/plugins/animation_player_editor_plugin.h"
#include "tools/editor/animation_editor.h"
#define DISTANCE_DEFAULT 4
#define GIZMO_ARROW_SIZE 0.3
#define GIZMO_RING_HALF_WIDTH 0.1
//#define GIZMO_SCALE_DEFAULT 0.28
#define GIZMO_SCALE_DEFAULT 0.15
void SpatialEditorViewport::_update_camera() {
if (orthogonal) {
//camera->set_orthogonal(size.width*cursor.distance,get_znear(),get_zfar());
camera->set_orthogonal(2 * cursor.distance, 0.1, 8192);
}
else
camera->set_perspective(get_fov(), get_znear(), get_zfar());
Transform camera_transform;
camera_transform.translate(cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
if (orthogonal)
camera_transform.translate(0, 0, 4096);
else
camera_transform.translate(0, 0, cursor.distance);
if (camera->get_global_transform() != camera_transform) {
camera->set_global_transform(camera_transform);
update_transform_gizmo_view();
}
}
String SpatialEditorGizmo::get_handle_name(int p_idx) const {
if (get_script_instance() && get_script_instance()->has_method("get_handle_name"))
return get_script_instance()->call("get_handle_name", p_idx);
return "";
}
Variant SpatialEditorGizmo::get_handle_value(int p_idx) const{
if (get_script_instance() && get_script_instance()->has_method("get_handle_value"))
return get_script_instance()->call("get_handle_value", p_idx);
return Variant();
}
void SpatialEditorGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point) {
if (get_script_instance() && get_script_instance()->has_method("set_handle"))
get_script_instance()->call("set_handle", p_idx, p_camera, p_point);
}
void SpatialEditorGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
if (get_script_instance() && get_script_instance()->has_method("commit_handle"))
get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel);
}
bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum) {
return false;
}
bool SpatialEditorGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3& r_pos, Vector3& r_normal,int *r_gizmo_handle,bool p_sec_first) {
return false;
}
SpatialEditorGizmo::SpatialEditorGizmo(){
selected=false;
}
int SpatialEditorViewport::get_selected_count() const {
Map<Node*,Object*> &selection = editor_selection->get_selection();
int count=0;
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->key()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
count++;
}
return count;
}
float SpatialEditorViewport::get_znear() const {
float val = spatial_editor->get_znear();
if (val<0.001)
val=0.001;
return val;
}
float SpatialEditorViewport::get_zfar() const{
float val = spatial_editor->get_zfar();
if (val<0.001)
val=0.001;
return val;
}
float SpatialEditorViewport::get_fov() const{
float val = spatial_editor->get_fov();
if (val<0.001)
val=0.001;
if (val>89)
val=89;
return val;
}
Transform SpatialEditorViewport::_get_camera_transform() const {
return camera->get_global_transform();
}
Vector3 SpatialEditorViewport::_get_camera_pos() const {
return _get_camera_transform().origin;
}
Point2 SpatialEditorViewport::_point_to_screen(const Vector3& p_point) {
return camera->unproject_position(p_point);
}
Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2& p_pos) const {
return camera->project_ray_origin(p_pos);
}
Vector3 SpatialEditorViewport::_get_camera_normal() const {
return -_get_camera_transform().basis.get_axis(2);
}
Vector3 SpatialEditorViewport::_get_ray(const Vector2& p_pos) {
return camera->project_ray_normal(p_pos);
}
/*
void SpatialEditorViewport::_clear_id(Spatial *p_node) {
editor_selection->remove_node(p_node);
}
*/
void SpatialEditorViewport::_clear_selected() {
editor_selection->clear();
}
void SpatialEditorViewport::_select_clicked(bool p_append,bool p_single) {
if (!clicked)
return;
Object *obj = ObjectDB::get_instance(clicked);
if (!obj)
return;
Spatial *sp = obj->cast_to<Spatial>();
if (!sp)
return;
_select(sp, clicked_wants_append,true);
}
void SpatialEditorViewport::_select(Spatial *p_node, bool p_append,bool p_single) {
if (!p_append) {
// should not modify the selection..
editor_selection->clear();
editor_selection->add_node(p_node);
} else {
if (editor_selection->is_selected(p_node) && p_single) {
//erase
editor_selection->remove_node(p_node);
} else {
editor_selection->add_node(p_node);
}
}
}
ObjectID SpatialEditorViewport::_select_ray(const Point2& p_pos, bool p_append,bool &r_includes_current,int *r_gizmo_handle,bool p_alt_select) {
if (r_gizmo_handle)
*r_gizmo_handle=-1;
Vector3 ray=_get_ray(p_pos);
Vector3 pos=_get_ray_pos(p_pos);
Vector<ObjectID> instances=VisualServer::get_singleton()->instances_cull_ray(pos,ray,get_tree()->get_root()->get_world()->get_scenario() );
Set<Ref<SpatialEditorGizmo> > found_gizmos;
//uint32_t closest=0;
//float closest_dist=0;
r_includes_current=false;
List<_RayResult> results;
for (int i=0;i<instances.size();i++) {
Object *obj=ObjectDB::get_instance(instances[i]);
if (!obj)
continue;
Spatial *spat=obj->cast_to<Spatial>();
if (!spat)
continue;
Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
if (!seg.is_valid())
continue;
if (found_gizmos.has(seg))
continue;
found_gizmos.insert(seg);
Vector3 point;
Vector3 normal;
int handle=-1;
bool inters = seg->intersect_ray(camera,p_pos,point,normal,NULL,p_alt_select);
if (!inters)
continue;
float dist = pos.distance_to(point);
if (dist<0)
continue;
if (editor_selection->is_selected(spat))
r_includes_current=true;
_RayResult res;
res.item=spat;
res.depth=dist;
res.handle=handle;
results.push_back(res);
}
if (results.empty())
return 0;
results.sort();
Spatial *s=NULL;
if (!r_includes_current || results.size()==1 || (r_gizmo_handle && results.front()->get().handle>=0)) {
//return the nearest one
s = results.front()->get().item;
if (r_gizmo_handle)
*r_gizmo_handle=results.front()->get().handle;
} else {
//returns the next one from a curent selection
List<_RayResult>::Element *E=results.front();
List<_RayResult>::Element *S=NULL;
while(true) {
//very strange loop algorithm that complies with object selection standards (tm).
if (S==E) {
//went all around and anothing was found
//since can't rotate the selection
//just return the first one
s=results.front()->get().item;
break;
}
if (!S && editor_selection->is_selected(E->get().item)) {
//found an item currently in the selection,
//so start from this one
S=E;
}
if (S && !editor_selection->is_selected(E->get().item)) {
// free item after a selected item, this one is desired.
s=E->get().item;
break;
}
E=E->next();
if (!E) {
if (!S) {
//did a loop but nothing was selected, select first
s=results.front()->get().item;
break;
}
E=results.front();
}
}
}
if (!s)
return 0;
return s->get_instance_ID();
}
void SpatialEditorViewport::_find_items_at_pos(const Point2& p_pos,bool &r_includes_current,Vector<_RayResult> &results,bool p_alt_select) {
Vector3 ray=_get_ray(p_pos);
Vector3 pos=_get_ray_pos(p_pos);
Vector<ObjectID> instances=VisualServer::get_singleton()->instances_cull_ray(pos,ray,get_tree()->get_root()->get_world()->get_scenario() );
Set<Ref<SpatialEditorGizmo> > found_gizmos;
r_includes_current=false;
for (int i=0;i<instances.size();i++) {
Object *obj=ObjectDB::get_instance(instances[i]);
if (!obj)
continue;
Spatial *spat=obj->cast_to<Spatial>();
if (!spat)
continue;
Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
if (!seg.is_valid())
continue;
if (found_gizmos.has(seg))
continue;
found_gizmos.insert(seg);
Vector3 point;
Vector3 normal;
int handle=-1;
bool inters = seg->intersect_ray(camera,p_pos,point,normal,NULL,p_alt_select);
if (!inters)
continue;
float dist = pos.distance_to(point);
if (dist<0)
continue;
if (editor_selection->is_selected(spat))
r_includes_current=true;
_RayResult res;
res.item=spat;
res.depth=dist;
res.handle=handle;
results.push_back(res);
}
if (results.empty())
return;
results.sort();
}
Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3& p_pos) {
CameraMatrix cm;
cm.set_perspective(get_fov(),get_size().aspect(),get_znear(),get_zfar());
float screen_w,screen_h;
cm.get_viewport_size(screen_w,screen_h);
Transform camera_transform;
camera_transform.translate( cursor.pos );
camera_transform.basis.rotate(Vector3(1,0,0),-cursor.x_rot);
camera_transform.basis.rotate(Vector3(0,1,0),-cursor.y_rot);
camera_transform.translate(0,0,cursor.distance);
return camera_transform.xform(Vector3( ((p_pos.x/get_size().width)*2.0-1.0)*screen_w, ((1.0-(p_pos.y/get_size().height))*2.0-1.0)*screen_h,-get_znear()));
}
void SpatialEditorViewport::_select_region() {
if (cursor.region_begin==cursor.region_end)
return; //nothing really
Vector3 box[4]={
Vector3(
MIN( cursor.region_begin.x, cursor.region_end.x),
MIN( cursor.region_begin.y, cursor.region_end.y),
0
),
Vector3(
MAX( cursor.region_begin.x, cursor.region_end.x),
MIN( cursor.region_begin.y, cursor.region_end.y),
0
),
Vector3(
MAX( cursor.region_begin.x, cursor.region_end.x),
MAX( cursor.region_begin.y, cursor.region_end.y),
0
),
Vector3(
MIN( cursor.region_begin.x, cursor.region_end.x),
MAX( cursor.region_begin.y, cursor.region_end.y),
0
)
};
Vector<Plane> frustum;
Vector3 cam_pos=_get_camera_pos();
Set<Ref<SpatialEditorGizmo> > found_gizmos;
for(int i=0;i<4;i++) {
Vector3 a=_get_screen_to_space(box[i]);
Vector3 b=_get_screen_to_space(box[(i+1)%4]);
frustum.push_back( Plane(a,b,cam_pos) );
}
Plane near( cam_pos, -_get_camera_normal() );
near.d-=get_znear();
frustum.push_back( near );
Plane far=-near;
far.d+=500.0;
frustum.push_back( far );
Vector<ObjectID> instances=VisualServer::get_singleton()->instances_cull_convex(frustum,get_tree()->get_root()->get_world()->get_scenario());
for (int i=0;i<instances.size();i++) {
Object *obj=ObjectDB::get_instance(instances[i]);
if (!obj)
continue;
Spatial *sp = obj->cast_to<Spatial>();
if (!sp)
continue;
Ref<SpatialEditorGizmo> seg = sp->get_gizmo();
if (!seg.is_valid())
continue;
if (found_gizmos.has(seg))
continue;
if (seg->intersect_frustum(camera,frustum))
_select(sp,true,false);
}
}
void SpatialEditorViewport::_update_name() {
String ortho = orthogonal?TTR("Orthogonal"):TTR("Perspective");
if (name!="")
view_menu->set_text("[ "+name+" "+ortho+" ]");
else
view_menu->set_text("[ "+ortho+" ]");
}
void SpatialEditorViewport::_compute_edit(const Point2& p_point) {
_edit.click_ray=_get_ray( Vector2( p_point.x, p_point.y ) );
_edit.click_ray_pos=_get_ray_pos( Vector2( p_point.x, p_point.y ) );
_edit.plane=TRANSFORM_VIEW;
spatial_editor->update_transform_gizmo();
_edit.center=spatial_editor->get_gizmo_transform().origin;
List<Node*> &selection = editor_selection->get_selected_node_list();
//Vector3 center;
//int nc=0;
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
se->original=se->sp->get_global_transform();
//center+=se->original.origin;
//nc++;
}
/*
if (nc)
_edit.center=center/float(nc);
*/
}
static int _get_key_modifier(const String& p_property) {
switch(EditorSettings::get_singleton()->get(p_property).operator int()) {
case 0: return 0;
case 1: return KEY_SHIFT;
case 2: return KEY_ALT;
case 3: return KEY_META;
case 4: return KEY_CONTROL;
}
return 0;
}
bool SpatialEditorViewport::_gizmo_select(const Vector2& p_screenpos,bool p_hilite_only) {
if (!spatial_editor->is_gizmo_visible())
return false;
if (get_selected_count()==0) {
if (p_hilite_only)
spatial_editor->select_gizmo_hilight_axis(-1);
return false;
}
Vector3 ray_pos=_get_ray_pos( Vector2( p_screenpos.x, p_screenpos.y ) );
Vector3 ray=_get_ray( Vector2( p_screenpos.x, p_screenpos.y ) );
Transform gt = spatial_editor->get_gizmo_transform();
float gs=gizmo_scale;
if (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_MOVE) {
int col_axis=-1;
float col_d=1e20;
for(int i=0;i<3;i++) {
Vector3 grabber_pos = gt.origin+gt.basis.get_axis(i)*gs;
float grabber_radius = gs*GIZMO_ARROW_SIZE;
Vector3 r;
if (Geometry::segment_intersects_sphere(ray_pos,ray_pos+ray*10000.0,grabber_pos,grabber_radius,&r)) {
float d = r.distance_to(ray_pos);
if (d<col_d) {
col_d=d;
col_axis=i;
}
}
}
if (col_axis!=-1) {
if (p_hilite_only) {
spatial_editor->select_gizmo_hilight_axis(col_axis);
} else {
//handle rotate
_edit.mode=TRANSFORM_TRANSLATE;
_compute_edit(Point2(p_screenpos.x,p_screenpos.y));
_edit.plane=TransformPlane(TRANSFORM_X_AXIS+col_axis);
}
return true;
}
}
if (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_ROTATE) {
int col_axis=-1;
float col_d=1e20;
for(int i=0;i<3;i++) {
Plane plane(gt.origin,gt.basis.get_axis(i).normalized());
Vector3 r;
if (!plane.intersects_ray(ray_pos,ray,&r))
continue;
float dist = r.distance_to(gt.origin);
if (dist > gs*(1-GIZMO_RING_HALF_WIDTH) && dist < gs *(1+GIZMO_RING_HALF_WIDTH)) {
float d = ray_pos.distance_to(r);
if (d<col_d) {
col_d=d;
col_axis=i;
}
}
}
if (col_axis!=-1) {
if (p_hilite_only) {
spatial_editor->select_gizmo_hilight_axis(col_axis+3);
} else {
//handle rotate
_edit.mode=TRANSFORM_ROTATE;
_compute_edit(Point2(p_screenpos.x,p_screenpos.y));
_edit.plane=TransformPlane(TRANSFORM_X_AXIS+col_axis);
}
return true;
}
}
if (p_hilite_only)
spatial_editor->select_gizmo_hilight_axis(-1);
return false;
}
void SpatialEditorViewport::_smouseenter() {
if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
surface->grab_focus();
}
void SpatialEditorViewport::_list_select(InputEventMouseButton b) {
_find_items_at_pos(Vector2( b.x, b.y ),clicked_includes_current,selection_results,b.mod.shift);
Node *scene=editor->get_edited_scene();
for(int i=0;i<selection_results.size();i++) {
Spatial *item=selection_results[i].item;
if (item!=scene && item->get_owner()!=scene && !scene->is_editable_instance(item->get_owner())) {
//invalid result
selection_results.remove(i);
i--;
}
}
clicked_wants_append=b.mod.shift;
if (selection_results.size() == 1) {
clicked=selection_results[0].item->get_instance_ID();
selection_results.clear();
if (clicked) {
_select_clicked(clicked_wants_append,true);
clicked=0;
}
} else if (!selection_results.empty()) {
NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
StringName root_name = root_path.get_name(root_path.get_name_count()-1);
for (int i = 0; i < selection_results.size(); i++) {
Spatial *spat=selection_results[i].item;
Ref<Texture> icon;
if (spat->has_meta("_editor_icon"))
icon=spat->get_meta("_editor_icon");
else
icon=get_icon( has_icon(spat->get_class(),"EditorIcons")?spat->get_class():String("Object"),"EditorIcons");
String node_path="/"+root_name+"/"+root_path.rel_path_to(spat->get_path());
selection_menu->add_item(spat->get_name());
selection_menu->set_item_icon(i, icon );
selection_menu->set_item_metadata(i, node_path);
selection_menu->set_item_tooltip(i,String(spat->get_name())+
"\nType: "+spat->get_class()+"\nPath: "+node_path);
}
selection_menu->set_global_pos(Vector2( b.global_x, b.global_y ));
selection_menu->popup();
selection_menu->call_deferred("grab_click_focus");
selection_menu->set_invalidate_click_until_motion();
}
}
void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (previewing)
return; //do NONE
{
EditorNode *en = editor;
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
if (!over_plugin_list->empty()) {
bool discard = over_plugin_list->forward_spatial_gui_input(camera,p_event);
if (discard)
return;
}
}
switch(p_event.type) {
case InputEvent::MOUSE_BUTTON: {
const InputEventMouseButton &b=p_event.mouse_button;
switch(b.button_index) {
case BUTTON_WHEEL_UP: {
cursor.distance/=1.08;
if (cursor.distance<0.001)
cursor.distance=0.001;
} break;
case BUTTON_WHEEL_DOWN: {
if (cursor.distance<0.001)
cursor.distance=0.001;
cursor.distance*=1.08;
} break;
case BUTTON_RIGHT: {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation_scheme").operator int();
if (b.pressed && _edit.gizmo.is_valid()) {
//restore
_edit.gizmo->commit_handle(_edit.gizmo_handle,_edit.gizmo_initial_value,true);
_edit.gizmo=Ref<SpatialEditorGizmo>();
}
if (_edit.mode==TRANSFORM_NONE && b.pressed) {
Plane cursor_plane(cursor.cursor_pos,_get_camera_normal());
Vector3 ray_origin = _get_ray_pos(Vector2(b.x,b.y));
Vector3 ray_dir = _get_ray(Vector2(b.x,b.y));
//gizmo modify
if (b.mod.control) {
Vector<ObjectID> instances=VisualServer::get_singleton()->instances_cull_ray(ray_origin,ray_dir,get_tree()->get_root()->get_world()->get_scenario() );
Plane p(ray_origin,_get_camera_normal());
float min_d=1e10;
bool found=false;
for (int i=0;i<instances.size();i++) {
Object *obj=ObjectDB::get_instance(instances[i]);
if (!obj)
continue;
VisualInstance *vi=obj->cast_to<VisualInstance>();
if (!vi)
continue;
//optimize by checking AABB (although should pre sort by distance)
Rect3 aabb = vi->get_global_transform().xform(vi->get_aabb());
if (p.distance_to(aabb.get_support(-ray_dir))>min_d)
continue;
PoolVector<Face3> faces = vi->get_faces(VisualInstance::FACES_SOLID);
int c = faces.size();
if (c>0) {
PoolVector<Face3>::Read r = faces.read();
for(int j=0;j<c;j++) {
Vector3 inters;
if (r[j].intersects_ray(ray_origin,ray_dir,&inters)) {
float d = p.distance_to(inters);
if (d<0)
continue;
if (d<min_d) {
min_d=d;
found=true;
}
}
}
}
}
if (found) {
//cursor.cursor_pos=ray_origin+ray_dir*min_d;
//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
}
} else {
Vector3 new_pos;
if (cursor_plane.intersects_ray(ray_origin,ray_dir,&new_pos)) {
//cursor.cursor_pos=new_pos;
//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
}
}
if (b.mod.alt) {
if (nav_scheme == NAVIGATION_MAYA)
break;
_list_select(b);
return;
}
}
if (_edit.mode!=TRANSFORM_NONE && b.pressed) {
//cancel motion
_edit.mode=TRANSFORM_NONE;
//_validate_selection();
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
sp->set_global_transform( se->original );
}
surface->update();
//VisualServer::get_singleton()->poly_clear(indicators);
set_message(TTR("Transform Aborted."),3);
}
} break;
case BUTTON_MIDDLE: {
if (b.pressed && _edit.mode!=TRANSFORM_NONE) {
switch(_edit.plane ) {
case TRANSFORM_VIEW: {
_edit.plane=TRANSFORM_X_AXIS;
set_message(TTR("X-Axis Transform."),2);
name="";
_update_name();
} break;
case TRANSFORM_X_AXIS: {
_edit.plane=TRANSFORM_Y_AXIS;
set_message(TTR("Y-Axis Transform."),2);
} break;
case TRANSFORM_Y_AXIS: {
_edit.plane=TRANSFORM_Z_AXIS;
set_message(TTR("Z-Axis Transform."),2);
} break;
case TRANSFORM_Z_AXIS: {
_edit.plane=TRANSFORM_VIEW;
set_message(TTR("View Plane Transform."),2);
} break;
}
}
} break;
case BUTTON_LEFT: {
if (b.pressed) {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation_scheme").operator int();
if ( (nav_scheme==NAVIGATION_MAYA || nav_scheme==NAVIGATION_MODO) && b.mod.alt) {
break;
}
if (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_LIST_SELECT) {
_list_select(b);
break;
}
_edit.mouse_pos=Point2(b.x,b.y);
_edit.snap=false;
_edit.mode=TRANSFORM_NONE;
//gizmo has priority over everything
bool can_select_gizmos=true;
{
int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
can_select_gizmos = view_menu->get_popup()->is_item_checked( idx );
}
if (can_select_gizmos && spatial_editor->get_selected()) {
Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
if (seg.is_valid()) {
int handle=-1;
Vector3 point;
Vector3 normal;
bool inters = seg->intersect_ray(camera,_edit.mouse_pos,point,normal,&handle,b.mod.shift);
if (inters && handle!=-1) {
_edit.gizmo=seg;
_edit.gizmo_handle=handle;
//_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle);
_edit.gizmo_initial_value=seg->get_handle_value(handle);
break;
}
}
}
if (_gizmo_select(_edit.mouse_pos))
break;
clicked=0;
clicked_includes_current=false;
if ((spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_SELECT && b.mod.control) || spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_ROTATE) {
/* HANDLE ROTATION */
if (get_selected_count()==0)
break; //bye
//handle rotate
_edit.mode=TRANSFORM_ROTATE;
_compute_edit(Point2(b.x,b.y));
break;
}
if (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_MOVE) {
if (get_selected_count()==0)
break; //bye
//handle rotate
_edit.mode=TRANSFORM_TRANSLATE;
_compute_edit(Point2(b.x,b.y));
break;
}
if (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_SCALE) {
if (get_selected_count()==0)
break; //bye
//handle rotate
_edit.mode=TRANSFORM_SCALE;
_compute_edit(Point2(b.x,b.y));
break;
}
// todo scale
int gizmo_handle=-1;
clicked=_select_ray(Vector2( b.x, b.y ),b.mod.shift,clicked_includes_current,&gizmo_handle,b.mod.shift);
//clicking is always deferred to either move or release
clicked_wants_append=b.mod.shift;
if (!clicked) {
if (!clicked_wants_append)
_clear_selected();
//default to regionselect
cursor.region_select=true;
cursor.region_begin=Point2(b.x,b.y);
cursor.region_end=Point2(b.x,b.y);
}
if (clicked && gizmo_handle>=0) {
Object *obj=ObjectDB::get_instance(clicked);
if (obj) {
Spatial *spa = obj->cast_to<Spatial>();
if (spa) {
Ref<SpatialEditorGizmo> seg=spa->get_gizmo();
if (seg.is_valid()) {
_edit.gizmo=seg;
_edit.gizmo_handle=gizmo_handle;
//_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle);
_edit.gizmo_initial_value=seg->get_handle_value(gizmo_handle);
//print_line("GIZMO: "+itos(gizmo_handle)+" FROMPOS: "+_edit.orig_gizmo_pos);
break;
}
}
}
//_compute_edit(Point2(b.x,b.y)); //in case a motion happens..
}
surface->update();
} else {
if (_edit.gizmo.is_valid()) {
_edit.gizmo->commit_handle(_edit.gizmo_handle,_edit.gizmo_initial_value,false);
_edit.gizmo=Ref<SpatialEditorGizmo>();
break;
}
if (clicked) {
_select_clicked(clicked_wants_append,true);
//clickd processing was deferred
clicked=0;
}
if (cursor.region_select) {
_select_region();
cursor.region_select=false;
surface->update();
}
if (_edit.mode!=TRANSFORM_NONE) {
static const char* _transform_name[4]={"None","Rotate","Translate","Scale"};
undo_redo->create_action(_transform_name[_edit.mode]);
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
undo_redo->add_do_method(sp,"set_global_transform",sp->get_global_transform());
undo_redo->add_undo_method(sp,"set_global_transform",se->original);
}
undo_redo->commit_action();
_edit.mode=TRANSFORM_NONE;
//VisualServer::get_singleton()->poly_clear(indicators);
set_message("");
}
surface->update();
}
} break;
}
} break;
case InputEvent::MOUSE_MOTION: {
const InputEventMouseMotion &m=p_event.mouse_motion;
_edit.mouse_pos=Point2(p_event.mouse_motion.x,p_event.mouse_motion.y);
if (spatial_editor->get_selected()) {
Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
if (seg.is_valid()) {
int selected_handle=-1;
int handle=-1;
Vector3 point;
Vector3 normal;
bool inters = seg->intersect_ray(camera,_edit.mouse_pos,point,normal,&handle,false);
if (inters && handle!=-1) {
selected_handle=handle;
}
if (selected_handle!=spatial_editor->get_over_gizmo_handle()) {
spatial_editor->set_over_gizmo_handle(selected_handle);
spatial_editor->get_selected()->update_gizmo();
if (selected_handle!=-1)
spatial_editor->select_gizmo_hilight_axis(-1);
}
}
}
if (spatial_editor->get_over_gizmo_handle()==-1 && !(m.button_mask&1) && !_edit.gizmo.is_valid()) {
_gizmo_select(_edit.mouse_pos,true);
}
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation_scheme").operator int();
NavigationMode nav_mode = NAVIGATION_NONE;
if (_edit.gizmo.is_valid()) {
_edit.gizmo->set_handle(_edit.gizmo_handle,camera,Vector2(m.x,m.y));
Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle);
String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
set_message(n+": "+String(v));
} else if (m.button_mask&1) {
if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) {
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MODO && m.mod.alt && m.mod.shift) {
nav_mode = NAVIGATION_PAN;
} else if (nav_scheme == NAVIGATION_MODO && m.mod.alt && m.mod.control) {
nav_mode = NAVIGATION_ZOOM;
} else if (nav_scheme == NAVIGATION_MODO && m.mod.alt) {
nav_mode = NAVIGATION_ORBIT;
} else {
if (clicked) {
if (!clicked_includes_current) {
_select_clicked(clicked_wants_append,true);
//clickd processing was deferred
}
_compute_edit(_edit.mouse_pos);
clicked=0;
_edit.mode=TRANSFORM_TRANSLATE;
}
if (cursor.region_select && nav_mode == NAVIGATION_NONE) {
cursor.region_end=Point2(m.x,m.y);
surface->update();
return;
}
if (_edit.mode==TRANSFORM_NONE && nav_mode == NAVIGATION_NONE)
break;
Vector3 ray_pos=_get_ray_pos( Vector2( m.x, m.y ) );
Vector3 ray=_get_ray( Vector2( m.x, m.y ) );
switch(_edit.mode) {
case TRANSFORM_SCALE: {
Plane plane=Plane(_edit.center,_get_camera_normal());
Vector3 intersection;
if (!plane.intersects_ray(ray_pos,ray,&intersection))
break;
Vector3 click;
if (!plane.intersects_ray(_edit.click_ray_pos,_edit.click_ray,&click))
break;
float center_click_dist = click.distance_to(_edit.center);
float center_inters_dist = intersection.distance_to(_edit.center);
if (center_click_dist==0)
break;
float scale = (center_inters_dist / center_click_dist)*100.0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
scale = Math::stepify(scale,spatial_editor->get_scale_snap());
}
set_message(vformat(TTR("Scaling to %s%%."),String::num(scale,1)));
scale/=100.0;
Transform r;
r.basis.scale(Vector3(scale,scale,scale));
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
Transform original=se->original;
Transform base=Transform( Basis(), _edit.center);
Transform t=base * (r * (base.inverse() * original));
sp->set_global_transform(t);
}
surface->update();
} break;
case TRANSFORM_TRANSLATE: {
Vector3 motion_mask;
Plane plane;
switch( _edit.plane ) {
case TRANSFORM_VIEW:
motion_mask=Vector3(0,0,0);
plane=Plane(_edit.center,_get_camera_normal());
break;
case TRANSFORM_X_AXIS:
motion_mask=spatial_editor->get_gizmo_transform().basis.get_axis(0);
plane=Plane(_edit.center,motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
break;
case TRANSFORM_Y_AXIS:
motion_mask=spatial_editor->get_gizmo_transform().basis.get_axis(1);
plane=Plane(_edit.center,motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
break;
case TRANSFORM_Z_AXIS:
motion_mask=spatial_editor->get_gizmo_transform().basis.get_axis(2);
plane=Plane(_edit.center,motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
break;
}
Vector3 intersection;
if (!plane.intersects_ray(ray_pos,ray,&intersection))
break;
Vector3 click;
if (!plane.intersects_ray(_edit.click_ray_pos,_edit.click_ray,&click))
break;
//_validate_selection();
Vector3 motion = intersection-click;
if (motion_mask!=Vector3()) {
motion=motion_mask.dot(motion)*motion_mask;
}
float snap=0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_translate_snap();
motion.snap(snap);
}
//set_message("Translating: "+motion);
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp) {
continue;
}
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se) {
continue;
}
Transform t=se->original;
t.origin+=motion;
sp->set_global_transform(t);
}
} break;
case TRANSFORM_ROTATE: {
Plane plane;
switch( _edit.plane ) {
case TRANSFORM_VIEW:
plane=Plane(_edit.center,_get_camera_normal());
break;
case TRANSFORM_X_AXIS:
plane=Plane(_edit.center,spatial_editor->get_gizmo_transform().basis.get_axis(0));
break;
case TRANSFORM_Y_AXIS:
plane=Plane(_edit.center,spatial_editor->get_gizmo_transform().basis.get_axis(1));
break;
case TRANSFORM_Z_AXIS:
plane=Plane(_edit.center,spatial_editor->get_gizmo_transform().basis.get_axis(2));
break;
}
Vector3 intersection;
if (!plane.intersects_ray(ray_pos,ray,&intersection))
break;
Vector3 click;
if (!plane.intersects_ray(_edit.click_ray_pos,_edit.click_ray,&click))
break;
Vector3 y_axis=(click-_edit.center).normalized();
Vector3 x_axis=plane.normal.cross(y_axis).normalized();
float angle=Math::atan2( x_axis.dot(intersection-_edit.center), y_axis.dot(intersection-_edit.center) );
if (_edit.snap || spatial_editor->is_snap_enabled()) {
float snap = spatial_editor->get_rotate_snap();
if (snap) {
angle=Math::rad2deg(angle)+snap*0.5; //else it wont reach +180
angle-=Math::fmod(angle,snap);
set_message(vformat(TTR("Rotating %s degrees."),rtos(angle)));
angle=Math::deg2rad(angle);
} else
set_message(vformat(TTR("Rotating %s degrees."),rtos(Math::rad2deg(angle))));
} else {
set_message(vformat(TTR("Rotating %s degrees."),rtos(Math::rad2deg(angle))));
}
Transform r;
r.basis.rotate(plane.normal,angle);
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
Transform original=se->original;
Transform base=Transform( Basis(), _edit.center);
Transform t=base * r * base.inverse() * original;
sp->set_global_transform(t);
}
surface->update();
/*
VisualServer::get_singleton()->poly_clear(indicators);
Vector<Vector3> points;
Vector<Vector3> empty;
Vector<Color> colors;
points.push_back(intersection);
points.push_back(_edit.original.origin);
colors.push_back( Color(255,155,100) );
colors.push_back( Color(255,155,100) );
VisualServer::get_singleton()->poly_add_primitive(indicators,points,empty,colors,empty);
*/
} break;
default:{}
}
}
} else if (m.button_mask&2) {
if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) {
nav_mode = NAVIGATION_ZOOM;
}
} else if (m.button_mask&4) {
if (nav_scheme == NAVIGATION_GODOT) {
int mod = 0;
if (m.mod.shift)
mod=KEY_SHIFT;
if (m.mod.alt)
mod=KEY_ALT;
if (m.mod.control)
mod=KEY_CONTROL;
if (m.mod.meta)
mod=KEY_META;
if (mod == _get_key_modifier("editors/3d/pan_modifier"))
nav_mode = NAVIGATION_PAN;
else if (mod == _get_key_modifier("editors/3d/zoom_modifier"))
nav_mode = NAVIGATION_ZOOM;
else if (mod == _get_key_modifier("editors/3d/orbit_modifier"))
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MAYA) {
if (m.mod.alt)
nav_mode = NAVIGATION_PAN;
}
} else if (EditorSettings::get_singleton()->get("editors/3d/emulate_3_button_mouse")) {
// Handle trackpad (no external mouse) use case
int mod = 0;
if (m.mod.shift)
mod=KEY_SHIFT;
if (m.mod.alt)
mod=KEY_ALT;
if (m.mod.control)
mod=KEY_CONTROL;
if (m.mod.meta)
mod=KEY_META;
if(mod){
if (mod == _get_key_modifier("editors/3d/pan_modifier"))
nav_mode = NAVIGATION_PAN;
else if (mod == _get_key_modifier("editors/3d/zoom_modifier"))
nav_mode = NAVIGATION_ZOOM;
else if (mod == _get_key_modifier("editors/3d/orbit_modifier"))
nav_mode = NAVIGATION_ORBIT;
}
}
switch(nav_mode) {
case NAVIGATION_PAN:{
real_t pan_speed = 1/150.0;
int pan_speed_modifier = 10;
if (nav_scheme==NAVIGATION_MAYA && m.mod.shift)
pan_speed *= pan_speed_modifier;
Transform camera_transform;
camera_transform.translate(cursor.pos);
camera_transform.basis.rotate(Vector3(1,0,0),-cursor.x_rot);
camera_transform.basis.rotate(Vector3(0,1,0),-cursor.y_rot);
Vector3 translation(-m.relative_x*pan_speed,m.relative_y*pan_speed,0);
translation*=cursor.distance/DISTANCE_DEFAULT;
camera_transform.translate(translation);
cursor.pos=camera_transform.origin;
} break;
case NAVIGATION_ZOOM: {
real_t zoom_speed = 1/80.0;
int zoom_speed_modifier = 10;
if (nav_scheme==NAVIGATION_MAYA && m.mod.shift)
zoom_speed *= zoom_speed_modifier;
NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/zoom_style").operator int();
if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
if ( m.relative_x > 0)
cursor.distance*=1-m.relative_x*zoom_speed;
else if (m.relative_x < 0)
cursor.distance/=1+m.relative_x*zoom_speed;
}
else {
if ( m.relative_y > 0)
cursor.distance*=1+m.relative_y*zoom_speed;
else if (m.relative_y < 0)
cursor.distance/=1-m.relative_y*zoom_speed;
}
} break;
case NAVIGATION_ORBIT: {
cursor.x_rot+=m.relative_y/80.0;
cursor.y_rot+=m.relative_x/80.0;
if (cursor.x_rot>Math_PI/2.0)
cursor.x_rot=Math_PI/2.0;
if (cursor.x_rot<-Math_PI/2.0)
cursor.x_rot=-Math_PI/2.0;
name="";
_update_name();
} break;
default: {}
}
} break;
case InputEvent::KEY: {
const InputEventKey &k = p_event.key;
if (!k.pressed)
break;
if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
if (_edit.mode != TRANSFORM_NONE) {
_edit.snap=true;
}
}
if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
cursor.y_rot = 0;
cursor.x_rot = -Math_PI/2.0;
set_message(TTR("Bottom View."),2);
name = TTR("Bottom");
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) {
cursor.y_rot = 0;
cursor.x_rot = Math_PI/2.0;
set_message(TTR("Top View."),2);
name = TTR("Top");
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) {
cursor.x_rot = 0;
cursor.y_rot = Math_PI;
set_message(TTR("Rear View."),2);
name = TTR("Rear");
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) {
cursor.x_rot = 0;
cursor.y_rot=0;
set_message(TTR("Front View."),2);
name=TTR("Front");
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) {
cursor.x_rot=0;
cursor.y_rot = Math_PI/2.0;
set_message(TTR("Left View."),2);
name = TTR("Left");
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) {
cursor.x_rot=0;
cursor.y_rot = -Math_PI/2.0;
set_message(TTR("Right View."),2);
name = TTR("Right");
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
_menu_option(orthogonal?VIEW_PERSPECTIVE:VIEW_ORTHOGONAL);
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) {
if (!get_selected_count() || _edit.mode!=TRANSFORM_NONE)
break;
if (!AnimationPlayerEditor::singleton->get_key_editor()->has_keying()) {
set_message(TTR("Keying is disabled (no key inserted)."));
break;
}
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
emit_signal("transform_key_request",sp,"",sp->get_transform());
}
set_message(TTR("Animation Key Inserted."));
}
if (k.scancode == KEY_SPACE) {
if (!k.pressed) emit_signal("toggle_maximize_view", this);
}
} break;
}
}
void SpatialEditorViewport::set_message(String p_message,float p_time) {
message=p_message;
message_time=p_time;
}
void SpatialEditorViewport::_notification(int p_what) {
if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
bool visible=is_visible_in_tree();
set_process(visible);
if (visible)
_update_camera();
call_deferred("update_transform_gizmo_view");
}
if (p_what==NOTIFICATION_RESIZED) {
call_deferred("update_transform_gizmo_view");
}
if (p_what==NOTIFICATION_PROCESS) {
//force editr camera
/*
current_camera=get_root_node()->get_current_camera();
if (current_camera!=camera) {
}
*/
_update_camera();
Map<Node*,Object*> &selection = editor_selection->get_selection();
bool changed=false;
bool exist=false;
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->key()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
VisualInstance *vi=sp->cast_to<VisualInstance>();
if (se->aabb.has_no_surface()) {
se->aabb=vi?vi->get_aabb():Rect3( Vector3(-0.2,-0.2,-0.2),Vector3(0.4,0.4,0.4));
}
Transform t=sp->get_global_transform();
t.translate(se->aabb.pos);
t.basis.scale( se->aabb.size );
exist=true;
if (se->last_xform==t)
continue;
changed=true;
se->last_xform=t;
VisualServer::get_singleton()->instance_set_transform(se->sbox_instance,t);
}
if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
spatial_editor->update_transform_gizmo();
}
if (message_time>0) {
if (message!=last_message) {
surface->update();
last_message=message;
}
message_time-=get_fixed_process_delta_time();
if (message_time<0)
surface->update();
}
//update shadow atlas if changed
int shadowmap_size = GlobalConfig::get_singleton()->get("rendering/shadow_atlas/size");
int atlas_q0 = GlobalConfig::get_singleton()->get("rendering/shadow_atlas/quadrant_0_subdiv");
int atlas_q1 = GlobalConfig::get_singleton()->get("rendering/shadow_atlas/quadrant_1_subdiv");
int atlas_q2 = GlobalConfig::get_singleton()->get("rendering/shadow_atlas/quadrant_2_subdiv");
int atlas_q3 = GlobalConfig::get_singleton()->get("rendering/shadow_atlas/quadrant_3_subdiv");
viewport->set_shadow_atlas_size(shadowmap_size);
viewport->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
viewport->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
viewport->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
viewport->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
//update msaa if changed
int msaa_mode = GlobalConfig::get_singleton()->get("rendering/quality/msaa");
viewport->set_msaa(Viewport::MSAA(msaa_mode));
bool hdr = GlobalConfig::get_singleton()->get("rendering/quality/hdr");
viewport->set_hdr(hdr);
}
if (p_what==NOTIFICATION_ENTER_TREE) {
surface->connect("draw",this,"_draw");
surface->connect("gui_input",this,"_sinput");
surface->connect("mouse_entered",this,"_smouseenter");
preview_camera->set_icon(get_icon("Camera","EditorIcons"));
_init_gizmo_instance(index);
}
if (p_what==NOTIFICATION_EXIT_TREE) {
_finish_gizmo_instances();
}
if (p_what==NOTIFICATION_MOUSE_ENTER) {
}
if (p_what==NOTIFICATION_DRAW) {
}
}
void SpatialEditorViewport::_draw() {
if (surface->has_focus()) {
Size2 size = surface->get_size();
Rect2 r =Rect2(Point2(),size);
get_stylebox("EditorFocus","EditorStyles")->draw(surface->get_canvas_item(),r);
}
RID ci=surface->get_canvas_item();
if (cursor.region_select) {
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor.region_begin,cursor.region_end-cursor.region_begin),Color(0.7,0.7,1.0,0.3));
}
if (message_time>0) {
Ref<Font> font = get_font("font","Label");
Point2 msgpos=Point2(5,get_size().y-20);
font->draw(ci,msgpos+Point2(1,1),message,Color(0,0,0,0.8));
font->draw(ci,msgpos+Point2(-1,-1),message,Color(0,0,0,0.8));
font->draw(ci,msgpos,message,Color(1,1,1,1));
}
if (_edit.mode==TRANSFORM_ROTATE) {
Point2 center = _point_to_screen(_edit.center);
VisualServer::get_singleton()->canvas_item_add_line(ci,_edit.mouse_pos, center, Color(0.4,0.7,1.0,0.8));
}
if (previewing) {
Size2 ss = Size2( GlobalConfig::get_singleton()->get("display/width"), GlobalConfig::get_singleton()->get("display/height") );
float aspect = ss.aspect();
Size2 s = get_size();
Rect2 draw_rect;
switch(previewing->get_keep_aspect_mode()) {
case Camera::KEEP_WIDTH: {
draw_rect.size = Size2(s.width,s.width/aspect);
draw_rect.pos.x=0;
draw_rect.pos.y=(s.height-draw_rect.size.y)*0.5;
} break;
case Camera::KEEP_HEIGHT: {
draw_rect.size = Size2(s.height*aspect,s.height);
draw_rect.pos.y=0;
draw_rect.pos.x=(s.width-draw_rect.size.x)*0.5;
} break;
}
draw_rect = Rect2(Vector2(),s).clip(draw_rect);
surface->draw_line(draw_rect.pos,draw_rect.pos+Vector2(draw_rect.size.x,0),Color(0.6,0.6,0.1,0.5),2.0);
surface->draw_line(draw_rect.pos+Vector2(draw_rect.size.x,0),draw_rect.pos+draw_rect.size,Color(0.6,0.6,0.1,0.5),2.0);
surface->draw_line(draw_rect.pos+draw_rect.size,draw_rect.pos+Vector2(0,draw_rect.size.y),Color(0.6,0.6,0.1,0.5),2.0);
surface->draw_line(draw_rect.pos,draw_rect.pos+Vector2(0,draw_rect.size.y),Color(0.6,0.6,0.1,0.5),2.0);
}
}
void SpatialEditorViewport::_menu_option(int p_option) {
switch(p_option) {
case VIEW_TOP: {
cursor.x_rot=Math_PI/2.0;
cursor.y_rot=0;
name=TTR("Top");
_update_name();
} break;
case VIEW_BOTTOM: {
cursor.x_rot=-Math_PI/2.0;
cursor.y_rot=0;
name=TTR("Bottom");
_update_name();
} break;
case VIEW_LEFT: {
cursor.y_rot=Math_PI/2.0;
cursor.x_rot=0;
name=TTR("Left");
_update_name();
} break;
case VIEW_RIGHT: {
cursor.y_rot=-Math_PI/2.0;
cursor.x_rot=0;
name=TTR("Right");
_update_name();
} break;
case VIEW_FRONT: {
cursor.y_rot=0;
cursor.x_rot=0;
name=TTR("Front");
_update_name();
} break;
case VIEW_REAR: {
cursor.y_rot=Math_PI;
cursor.x_rot=0;
name=TTR("Rear");
_update_name();
} break;
case VIEW_CENTER_TO_ORIGIN: {
cursor.pos = Vector3(0,0,0);
} break;
case VIEW_CENTER_TO_SELECTION: {
focus_selection();
} break;
case VIEW_ALIGN_SELECTION_WITH_VIEW: {
if (!get_selected_count())
break;
Transform camera_transform = camera->get_global_transform();
List<Node*> &selection = editor_selection->get_selected_node_list();
undo_redo->create_action(TTR("Align with view"));
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
Transform xform = camera_transform;
xform.scale_basis(sp->get_scale());
undo_redo->add_do_method(sp,"set_global_transform",xform);
undo_redo->add_undo_method(sp,"set_global_transform",sp->get_global_transform());
}
undo_redo->commit_action();
} break;
case VIEW_ENVIRONMENT: {
int idx = view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT);
bool current = view_menu->get_popup()->is_item_checked( idx );
current=!current;
if (current) {
camera->set_environment(RES());
} else {
camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
}
view_menu->get_popup()->set_item_checked( idx, current );
} break;
case VIEW_PERSPECTIVE: {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false );
orthogonal=false;
call_deferred("update_transform_gizmo_view");
_update_name();
} break;
case VIEW_ORTHOGONAL: {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true );
orthogonal=true;
call_deferred("update_transform_gizmo_view");
_update_name();
} break;
case VIEW_AUDIO_LISTENER: {
int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
bool current = view_menu->get_popup()->is_item_checked( idx );
current=!current;
viewport->set_as_audio_listener(current);
view_menu->get_popup()->set_item_checked( idx, current );
} break;
case VIEW_GIZMOS: {
int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
bool current = view_menu->get_popup()->is_item_checked( idx );
current=!current;
if (current)
camera->set_cull_mask( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+index))|(1<<GIZMO_EDIT_LAYER)|(1<<GIZMO_GRID_LAYER) );
else
camera->set_cull_mask( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+index))|(1<<GIZMO_GRID_LAYER) );
view_menu->get_popup()->set_item_checked( idx, current );
} break;
}
}
void SpatialEditorViewport::_preview_exited_scene() {
preview_camera->set_pressed(false);
_toggle_camera_preview(false);
view_menu->show();
}
void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
uint32_t layer=1<<(GIZMO_BASE_LAYER+p_idx);//|(1<<GIZMO_GRID_LAYER);
for(int i=0;i<3;i++) {
move_gizmo_instance[i]=VS::get_singleton()->instance_create();
VS::get_singleton()->instance_set_base(move_gizmo_instance[i],spatial_editor->get_move_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i],get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(move_gizmo_instance[i],false);
//VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i],layer);
rotate_gizmo_instance[i]=VS::get_singleton()->instance_create();
VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i],spatial_editor->get_rotate_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i],get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i],false);
//VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i],layer);
}
}
void SpatialEditorViewport::_finish_gizmo_instances() {
for(int i=0;i<3;i++) {
VS::get_singleton()->free(move_gizmo_instance[i]);
VS::get_singleton()->free(rotate_gizmo_instance[i]);
}
}
void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
ERR_FAIL_COND(p_activate && !preview);
ERR_FAIL_COND(!p_activate && !previewing);
if (!p_activate) {
previewing->disconnect("tree_exited",this,"_preview_exited_scene");
previewing=NULL;
VS::get_singleton()->viewport_attach_camera( viewport->get_viewport_rid(), camera->get_camera() ); //restore
if (!preview)
preview_camera->hide();
view_menu->show();
surface->update();
} else {
previewing=preview;
previewing->connect("tree_exited",this,"_preview_exited_scene");
VS::get_singleton()->viewport_attach_camera( viewport->get_viewport_rid(), preview->get_camera() ); //replace
view_menu->hide();
surface->update();
}
}
void SpatialEditorViewport::_selection_result_pressed(int p_result) {
if (selection_results.size() <= p_result)
return;
clicked=selection_results[p_result].item->get_instance_ID();
if (clicked) {
_select_clicked(clicked_wants_append,true);
clicked=0;
}
}
void SpatialEditorViewport::_selection_menu_hide() {
selection_results.clear();
selection_menu->clear();
selection_menu->set_size(Vector2(0, 0));
}
void SpatialEditorViewport::set_can_preview(Camera* p_preview) {
preview=p_preview;
if (!preview_camera->is_pressed()) {
if (p_preview) {
preview_camera->show();
} else {
preview_camera->hide();
}
}
}
void SpatialEditorViewport::update_transform_gizmo_view() {
if (!is_visible_in_tree())
return;
Transform xform = spatial_editor->get_gizmo_transform();
Transform camera_xform = camera->get_transform();
Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
Plane p(camera_xform.origin,camz);
float gizmo_d = Math::abs( p.distance_to(xform.origin ));
float d0 = camera->unproject_position(camera_xform.origin+camz*gizmo_d).y;
float d1 = camera->unproject_position(camera_xform.origin+camz*gizmo_d+camy).y;
float dd = Math::abs(d0-d1);
if (dd==0)
dd=0.0001;
float gsize = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
gizmo_scale=(gsize/Math::abs(dd));
Vector3 scale = Vector3(1,1,1) * gizmo_scale;
xform.basis.scale(scale);
//xform.basis.scale(GIZMO_SCALE_DEFAULT*Vector3(1,1,1));
for(int i=0;i<3;i++) {
VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform );
VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i],spatial_editor->is_gizmo_visible()&& (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_MOVE) );
VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform );
VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i],spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_ROTATE) );
}
}
void SpatialEditorViewport::set_state(const Dictionary& p_state) {
cursor.pos=p_state["pos"];
cursor.x_rot=p_state["x_rot"];
cursor.y_rot=p_state["y_rot"];
cursor.distance=p_state["distance"];
bool env = p_state["use_environment"];
bool orth = p_state["use_orthogonal"];
if (orth)
_menu_option(VIEW_ORTHOGONAL);
else
_menu_option(VIEW_PERSPECTIVE);
if (env != camera->get_environment().is_valid())
_menu_option(VIEW_ENVIRONMENT);
if (p_state.has("listener")) {
bool listener = p_state["listener"];
int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
viewport->set_as_audio_listener(listener);
view_menu->get_popup()->set_item_checked( idx, listener );
}
if (p_state.has("previewing")) {
Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
if (pv && pv->cast_to<Camera>()) {
previewing=pv->cast_to<Camera>();
previewing->connect("tree_exited",this,"_preview_exited_scene");
VS::get_singleton()->viewport_attach_camera( viewport->get_viewport_rid(), previewing->get_camera() ); //replace
view_menu->hide();
surface->update();
preview_camera->set_pressed(true);
preview_camera->show();
}
}
}
Dictionary SpatialEditorViewport::get_state() const {
Dictionary d;
d["pos"]=cursor.pos;
d["x_rot"]=cursor.x_rot;
d["y_rot"]=cursor.y_rot;
d["distance"]=cursor.distance;
d["use_environment"]=camera->get_environment().is_valid();
d["use_orthogonal"]=camera->get_projection()==Camera::PROJECTION_ORTHOGONAL;
d["listener"]=viewport->is_audio_listener();
if (previewing) {
d["previewing"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
}
return d;
}
void SpatialEditorViewport::_bind_methods(){
ClassDB::bind_method(_MD("_draw"),&SpatialEditorViewport::_draw);
ClassDB::bind_method(_MD("_smouseenter"),&SpatialEditorViewport::_smouseenter);
ClassDB::bind_method(_MD("_sinput"),&SpatialEditorViewport::_sinput);
ClassDB::bind_method(_MD("_menu_option"),&SpatialEditorViewport::_menu_option);
ClassDB::bind_method(_MD("_toggle_camera_preview"),&SpatialEditorViewport::_toggle_camera_preview);
ClassDB::bind_method(_MD("_preview_exited_scene"),&SpatialEditorViewport::_preview_exited_scene);
ClassDB::bind_method(_MD("update_transform_gizmo_view"),&SpatialEditorViewport::update_transform_gizmo_view);
ClassDB::bind_method(_MD("_selection_result_pressed"),&SpatialEditorViewport::_selection_result_pressed);
ClassDB::bind_method(_MD("_selection_menu_hide"),&SpatialEditorViewport::_selection_menu_hide);
ADD_SIGNAL( MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")) );
}
void SpatialEditorViewport::reset() {
orthogonal=false;
message_time=0;
message="";
last_message="";
name="";
cursor.x_rot=0.5;
cursor.y_rot=0.5;
cursor.distance=4;
cursor.region_select=false;
_update_name();
}
void SpatialEditorViewport::focus_selection() {
if (!get_selected_count())
return;
Vector3 center;
int count=0;
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
center+=sp->get_global_transform().origin;
count++;
}
if( count != 0 ) {
center/=float(count);
}
cursor.pos=center;
}
SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
_edit.mode=TRANSFORM_NONE;
_edit.plane=TRANSFORM_VIEW;
_edit.edited_gizmo=0;
_edit.snap=1;
_edit.gizmo_handle=0;
index=p_index;
editor=p_editor;
editor_selection=editor->get_editor_selection();
undo_redo=editor->get_undo_redo();
clicked=0;
clicked_includes_current=false;
orthogonal=false;
message_time=0;
spatial_editor=p_spatial_editor;
ViewportContainer *c=memnew(ViewportContainer);
c->set_stretch(true);
add_child(c);
c->set_area_as_parent_rect();
viewport = memnew( Viewport );
viewport->set_disable_input(true);
c->add_child(viewport);
surface = memnew( Control );
add_child(surface);
surface->set_area_as_parent_rect();
camera = memnew(Camera);
camera->set_disable_gizmo(true);
camera->set_cull_mask( ((1<<20)-1)|(1<<(GIZMO_BASE_LAYER+p_index))|(1<<GIZMO_EDIT_LAYER)|(1<<GIZMO_GRID_LAYER) );
//camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
viewport->add_child(camera);
camera->make_current();
surface->set_focus_mode(FOCUS_ALL);
view_menu = memnew( MenuButton );
surface->add_child(view_menu);
view_menu->set_pos( Point2(4,4));
view_menu->set_self_modulate(Color(1,1,1,0.5));
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/right_view"), VIEW_RIGHT);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
view_menu->get_popup()->add_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE),true);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("Environment")), VIEW_ENVIRONMENT);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT),true);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("Gizmos")),VIEW_GIZMOS);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(VIEW_GIZMOS),true);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_origin"), VIEW_CENTER_TO_ORIGIN);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_selection_with_view"), VIEW_ALIGN_SELECTION_WITH_VIEW);
view_menu->get_popup()->connect("id_pressed",this,"_menu_option");
preview_camera = memnew( Button );
preview_camera->set_toggle_mode(true);
preview_camera->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,90);
preview_camera->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,10);
preview_camera->set_text("preview");
surface->add_child(preview_camera);
preview_camera->hide();
preview_camera->connect("toggled",this,"_toggle_camera_preview");
previewing=NULL;
preview=NULL;
gizmo_scale=1.0;
selection_menu = memnew( PopupMenu );
add_child(selection_menu);
selection_menu->set_custom_minimum_size(Vector2(100, 0));
selection_menu->connect("id_pressed", this, "_selection_result_pressed");
selection_menu->connect("popup_hide", this, "_selection_menu_hide");
if (p_index==0) {
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER),true);
viewport->set_as_audio_listener(true);
}
name=TTR("Top");
_update_name();
EditorSettings::get_singleton()->connect("settings_changed",this,"update_transform_gizmo_view");
}
SpatialEditor *SpatialEditor::singleton=NULL;
SpatialEditorSelectedItem::~SpatialEditorSelectedItem() {
if (sbox_instance.is_valid())
VisualServer::get_singleton()->free(sbox_instance);
}
void SpatialEditor::select_gizmo_hilight_axis(int p_axis) {
for(int i=0;i<3;i++) {
move_gizmo[i]->surface_set_material(0,i==p_axis?gizmo_hl:gizmo_color[i]);
rotate_gizmo[i]->surface_set_material(0,(i+3)==p_axis?gizmo_hl:gizmo_color[i]);
}
}
void SpatialEditor::update_transform_gizmo() {
List<Node*> &selection = editor_selection->get_selected_node_list();
Rect3 center;
bool first=true;
Basis gizmo_basis;
bool local_gizmo_coords = transform_menu->get_popup()->is_item_checked( transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS) );
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
Transform xf = se->sp->get_global_transform();
if (first) {
center.pos=xf.origin;
first=false;
if (local_gizmo_coords) {
gizmo_basis=xf.basis;
gizmo_basis.orthonormalize();
}
} else {
center.expand_to(xf.origin);
gizmo_basis=Basis();
}
//count++;
}
Vector3 pcenter = center.pos+center.size*0.5;
gizmo.visible=!first;
gizmo.transform.origin=pcenter;
gizmo.transform.basis=gizmo_basis;
for(int i=0;i<4;i++) {
viewports[i]->update_transform_gizmo_view();
}
}
Object *SpatialEditor::_get_editor_data(Object *p_what) {
Spatial *sp = p_what->cast_to<Spatial>();
if (!sp)
return NULL;
SpatialEditorSelectedItem *si = memnew( SpatialEditorSelectedItem );
si->sp=sp;
si->sbox_instance=VisualServer::get_singleton()->instance_create2(selection_box->get_rid(),sp->get_world()->get_scenario());
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, VS::SHADOW_CASTING_SETTING_OFF);
if (get_tree()->is_editor_hint())
editor->call("edit_node",sp);
return si;
}
void SpatialEditor::_generate_selection_box() {
Rect3 aabb( Vector3(), Vector3(1,1,1) );
aabb.grow_by( aabb.get_longest_axis_size()/20.0 );
Ref<SurfaceTool> st = memnew( SurfaceTool );
st->begin(Mesh::PRIMITIVE_LINES);
for (int i=0;i<12;i++) {
Vector3 a,b;
aabb.get_edge(i,a,b);
/*Vector<Vector3> points;
Vector<Color> colors;
points.push_back(a);
points.push_back(b);*/
st->add_color( Color(1.0,1.0,0.8,0.8) );
st->add_vertex(a);
st->add_color( Color(1.0,1.0,0.8,0.4) );
st->add_vertex(a.linear_interpolate(b,0.2));
st->add_color( Color(1.0,1.0,0.8,0.4) );
st->add_vertex(a.linear_interpolate(b,0.8));
st->add_color( Color(1.0,1.0,0.8,0.8) );
st->add_vertex(b);
}
Ref<FixedSpatialMaterial> mat = memnew( FixedSpatialMaterial );
mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
mat->set_albedo(Color(1,1,1));
mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true);
mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
st->set_material(mat);
selection_box = st->commit();
}
Dictionary SpatialEditor::get_state() const {
Dictionary d;
d["snap_enabled"]=snap_enabled;
d["translate_snap"]=get_translate_snap();
d["rotate_snap"]=get_rotate_snap();
d["scale_snap"]=get_scale_snap();
int local_coords_index=transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS);
d["local_coords"]=transform_menu->get_popup()->is_item_checked( local_coords_index );
int vc=0;
if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT) ))
vc=1;
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS) ))
vc=2;
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS) ))
vc=3;
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS) ))
vc=4;
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT) ))
vc=5;
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT) ))
vc=6;
d["viewport_mode"]=vc;
Array vpdata;
for(int i=0;i<4;i++) {
vpdata.push_back( viewports[i]->get_state() );
}
d["viewports"]=vpdata;
d["default_light"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT) );
d["ambient_light_color"]=settings_ambient_color->get_pick_color();
d["default_srgb"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB) );
d["show_grid"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID) );
d["show_origin"]=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN) );
d["fov"]=get_fov();
d["znear"]=get_znear();
d["zfar"]=get_zfar();
d["deflight_rot_x"]=settings_default_light_rot_x;
d["deflight_rot_y"]=settings_default_light_rot_y;
return d;
}
void SpatialEditor::set_state(const Dictionary& p_state) {
Dictionary d = p_state;
if (d.has("snap_enabled")) {
snap_enabled=d["snap_enabled"];
int snap_enabled_idx=transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_USE_SNAP);
transform_menu->get_popup()->set_item_checked( snap_enabled_idx, snap_enabled );
}
if (d.has("translate_snap"))
snap_translate->set_text(d["translate_snap"]);
if (d.has("rotate_snap"))
snap_rotate->set_text(d["rotate_snap"]);
if (d.has("scale_snap"))
snap_scale->set_text(d["scale_snap"]);
if (d.has("local_coords")) {
int local_coords_idx=transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS);
transform_menu->get_popup()->set_item_checked( local_coords_idx, d["local_coords"] );
update_transform_gizmo();
}
if (d.has("viewport_mode")) {
int vc = d["viewport_mode"];
if (vc==1)
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
else if (vc==2)
_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
else if (vc==3)
_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
else if (vc==4)
_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
else if (vc==5)
_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
else if (vc==6)
_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
}
if (d.has("viewports")) {
Array vp = d["viewports"];
ERR_FAIL_COND(vp.size()>4);
for(int i=0;i<4;i++) {
viewports[i]->set_state(vp[i]);
}
}
if (d.has("zfar"))
settings_zfar->set_value(float(d["zfar"]));
if (d.has("znear"))
settings_znear->set_value(float(d["znear"]));
if (d.has("fov"))
settings_fov->set_value(float(d["fov"]));
if (d.has("default_light")) {
bool use = d["default_light"];
bool existing = light_instance.is_valid();
if (use!=existing) {
if (existing) {
VisualServer::get_singleton()->free(light_instance);
light_instance=RID();
} else {
light_instance=VisualServer::get_singleton()->instance_create2(light,get_tree()->get_root()->get_world()->get_scenario());
VisualServer::get_singleton()->instance_set_transform(light_instance,light_transform);
}
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), light_instance.is_valid() );
}
}
if (d.has("ambient_light_color")) {
settings_ambient_color->set_pick_color(d["ambient_light_color"]);
//viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,d["ambient_light_color"]);
}
if (d.has("default_srgb")) {
bool use = d["default_srgb"];
//viewport_environment->set_enable_fx(Environment::FX_SRGB,use);
//view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB), use );
}
if (d.has("show_grid")) {
bool use = d["show_grid"];
if (use!=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) {
_menu_item_pressed(MENU_VIEW_GRID);
}
}
if (d.has("show_origin")) {
bool use = d["show_origin"];
if (use!=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN))) {
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), use );
VisualServer::get_singleton()->instance_set_visible(origin_instance,use);
}
}
if (d.has("deflight_rot_x"))
settings_default_light_rot_x=d["deflight_rot_x"];
if (d.has("deflight_rot_y"))
settings_default_light_rot_y=d["deflight_rot_y"];
_update_default_light_angle();
}
void SpatialEditor::edit(Spatial *p_spatial) {
if (p_spatial!=selected) {
if (selected) {
Ref<SpatialEditorGizmo> seg = selected->get_gizmo();
if (seg.is_valid()) {
seg->set_selected(false);
selected->update_gizmo();
}
}
selected=p_spatial;
over_gizmo_handle=-1;
if (selected) {
Ref<SpatialEditorGizmo> seg = selected->get_gizmo();
if (seg.is_valid()) {
seg->set_selected(true);
selected->update_gizmo();
}
}
}
/*
if (p_spatial) {
_validate_selection();
if (selected.has(p_spatial->get_instance_ID()) && selected.size()==1)
return;
_select(p_spatial->get_instance_ID(),false,true);
// should become the selection
}
*/
}
void SpatialEditor::_xform_dialog_action() {
Transform t;
//translation
Vector3 scale;
Vector3 rotate;
Vector3 translate;
for(int i=0;i<3;i++) {
translate[i]=xform_translate[i]->get_text().to_double();
rotate[i]=Math::deg2rad(xform_rotate[i]->get_text().to_double());
scale[i]=xform_scale[i]->get_text().to_double();
}
t.basis.scale(scale);
t.basis.rotate(rotate);
t.origin=translate;
undo_redo->create_action(TTR("XForm Dialog"));
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
Spatial *sp = E->get()->cast_to<Spatial>();
if (!sp)
continue;
SpatialEditorSelectedItem *se=editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
if (!se)
continue;
bool post = xform_type->get_selected()>0;
Transform tr = sp->get_global_transform();
if (post)
tr = tr * t;
else {
tr.basis = t.basis * tr.basis;
tr.origin+=t.origin;
}
undo_redo->add_do_method(sp,"set_global_transform",tr);
undo_redo->add_undo_method(sp,"set_global_transform",sp->get_global_transform());
}
undo_redo->commit_action();
}
void SpatialEditor::_menu_item_pressed(int p_option) {
switch(p_option) {
case MENU_TOOL_SELECT:
case MENU_TOOL_MOVE:
case MENU_TOOL_ROTATE:
case MENU_TOOL_SCALE:
case MENU_TOOL_LIST_SELECT: {
for(int i=0;i<TOOL_MAX;i++)
tool_button[i]->set_pressed(i==p_option);
tool_mode=(ToolMode)p_option;
//static const char *_mode[]={"Selection Mode.","Translation Mode.","Rotation Mode.","Scale Mode.","List Selection Mode."};
//set_message(_mode[p_option],3);
update_transform_gizmo();
} break;
case MENU_TRANSFORM_USE_SNAP: {
bool is_checked = transform_menu->get_popup()->is_item_checked( transform_menu->get_popup()->get_item_index(p_option) );
snap_enabled=!is_checked;
transform_menu->get_popup()->set_item_checked( transform_menu->get_popup()->get_item_index(p_option), snap_enabled );
} break;
case MENU_TRANSFORM_CONFIGURE_SNAP: {
snap_dialog->popup_centered(Size2(200,180));
} break;
case MENU_TRANSFORM_LOCAL_COORDS: {
bool is_checked = transform_menu->get_popup()->is_item_checked( transform_menu->get_popup()->get_item_index(p_option) );
transform_menu->get_popup()->set_item_checked( transform_menu->get_popup()->get_item_index(p_option), !is_checked );
update_transform_gizmo();
} break;
case MENU_TRANSFORM_DIALOG: {
for(int i=0;i<3;i++) {
xform_translate[i]->set_text("0");
xform_rotate[i]->set_text("0");
xform_scale[i]->set_text("1");
}
xform_dialog->popup_centered(Size2(200,200));
} break;
case MENU_VIEW_USE_DEFAULT_LIGHT: {
bool is_checked = view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(p_option) );
if (is_checked) {
VisualServer::get_singleton()->free(light_instance);
light_instance=RID();
} else {
light_instance=VisualServer::get_singleton()->instance_create2(light,get_tree()->get_root()->get_world()->get_scenario());
VisualServer::get_singleton()->instance_set_transform(light_instance,light_transform);
_update_default_light_angle();
}
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), light_instance.is_valid() );
} break;
case MENU_VIEW_USE_DEFAULT_SRGB: {
bool is_checked = view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(p_option) );
if (is_checked) {
//viewport_environment->set_enable_fx(Environment::FX_SRGB,false);
} else {
//viewport_environment->set_enable_fx(Environment::FX_SRGB,true);
}
is_checked = ! is_checked;
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), is_checked );
} break;
case MENU_VIEW_USE_1_VIEWPORT: {
for(int i=1;i<4;i++) {
viewports[i]->hide();
}
viewports[0]->set_area_as_parent_rect();
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_USE_2_VIEWPORTS: {
for(int i=1;i<4;i++) {
if (i==1 || i==3)
viewports[i]->hide();
else
viewports[i]->show();
}
viewports[0]->set_area_as_parent_rect();
//viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_RATIO,0.5);
viewports[2]->set_area_as_parent_rect();
//viewports[2]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
for(int i=1;i<4;i++) {
if (i==1 || i==3)
viewports[i]->hide();
else
viewports[i]->show();
}
viewports[0]->set_area_as_parent_rect();
//viewports[0]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
viewports[2]->set_area_as_parent_rect();
//viewports[2]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_USE_3_VIEWPORTS: {
for(int i=1;i<4;i++) {
if (i==1)
viewports[i]->hide();
else
viewports[i]->show();
}
viewports[0]->set_area_as_parent_rect();
//viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_RATIO,0.5);
viewports[2]->set_area_as_parent_rect();
//viewports[2]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
//viewports[2]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
viewports[3]->set_area_as_parent_rect();
//viewports[3]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
//viewports[3]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
for(int i=1;i<4;i++) {
if (i==1)
viewports[i]->hide();
else
viewports[i]->show();
}
viewports[0]->set_area_as_parent_rect();
//viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_RATIO,0.5);
//viewports[0]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
viewports[2]->set_area_as_parent_rect();
//viewports[2]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
//viewports[2]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
viewports[3]->set_area_as_parent_rect();
//viewports[3]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), true );
} break;
case MENU_VIEW_USE_4_VIEWPORTS: {
for(int i=1;i<4;i++) {
viewports[i]->show();
}
viewports[0]->set_area_as_parent_rect();
//viewports[0]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
//viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_RATIO,0.5);
viewports[1]->set_area_as_parent_rect();
//viewports[1]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
//viewports[1]->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_RATIO,0.5);
viewports[2]->set_area_as_parent_rect();
//viewports[2]->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_RATIO,0.5);
//viewports[2]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
viewports[3]->set_area_as_parent_rect();
//viewports[3]->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_RATIO,0.5);
//viewports[3]->set_anchor_and_margin(MARGIN_TOP,ANCHOR_RATIO,0.5);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false );
} break;
case MENU_VIEW_DISPLAY_NORMAL: {
VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_DISABLED );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false );
} break;
case MENU_VIEW_DISPLAY_WIREFRAME: {
VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_WIREFRAME );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false );
} break;
case MENU_VIEW_DISPLAY_OVERDRAW: {
VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), true );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false );
} break;
case MENU_VIEW_DISPLAY_SHADELESS: {
VisualServer::get_singleton()->scenario_set_debug( get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_SHADELESS );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false );
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), true );
} break;
case MENU_VIEW_ORIGIN: {
bool is_checked = view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(p_option) );
is_checked=!is_checked;
VisualServer::get_singleton()->instance_set_visible(origin_instance,is_checked);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), is_checked);
} break;
case MENU_VIEW_GRID: {
bool is_checked = view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(p_option) );
grid_enabled=!is_checked;
for(int i=0;i<3;++i) {
if (grid_enable[i]) {
VisualServer::get_singleton()->instance_set_visible(grid_instance[i],grid_enabled);
grid_visible[i]=grid_enabled;
}
}
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), grid_enabled );
} break;
case MENU_VIEW_CAMERA_SETTINGS: {
settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size()+Size2(50,50));
} break;
}
}
void SpatialEditor::_init_indicators() {
//make sure that the camera indicator is not selectable
light=VisualServer::get_singleton()->light_create( VisualServer::LIGHT_DIRECTIONAL );
//VisualServer::get_singleton()->light_set_shadow( light, true );
light_instance=VisualServer::get_singleton()->instance_create2(light,get_tree()->get_root()->get_world()->get_scenario());
light_transform.rotate(Vector3(1,0,0),-Math_PI/5.0);
VisualServer::get_singleton()->instance_set_transform(light_instance,light_transform);
//RID mat = VisualServer::get_singleton()->fixed_material_create();
///VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
//VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
{
indicator_mat.instance();
indicator_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true);
indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
indicator_mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
indicator_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true);
PoolVector<Color> grid_colors[3];
PoolVector<Vector3> grid_points[3];
Vector<Color> origin_colors;
Vector<Vector3> origin_points;
Color grid_color = EditorSettings::get_singleton()->get("editors/3d/grid_color");
for(int i=0;i<3;i++) {
Vector3 axis;
axis[i]=1;
Vector3 axis_n1;
axis_n1[(i+1)%3]=1;
Vector3 axis_n2;
axis_n2[(i+2)%3]=1;
origin_colors.push_back(Color(axis.x,axis.y,axis.z));
origin_colors.push_back(Color(axis.x,axis.y,axis.z));
origin_points.push_back(axis*4096);
origin_points.push_back(axis*-4096);
#define ORIGIN_GRID_SIZE 25
for(int j=-ORIGIN_GRID_SIZE;j<=ORIGIN_GRID_SIZE;j++) {
grid_colors[i].push_back(grid_color);
grid_colors[i].push_back(grid_color);
grid_colors[i].push_back(grid_color);
grid_colors[i].push_back(grid_color);
grid_points[i].push_back(axis_n1*ORIGIN_GRID_SIZE+axis_n2*j);
grid_points[i].push_back(-axis_n1*ORIGIN_GRID_SIZE+axis_n2*j);
grid_points[i].push_back(axis_n2*ORIGIN_GRID_SIZE+axis_n1*j);
grid_points[i].push_back(-axis_n2*ORIGIN_GRID_SIZE+axis_n1*j);
}
grid[i] = VisualServer::get_singleton()->mesh_create();
Array d;
d.resize(VS::ARRAY_MAX);
d[VisualServer::ARRAY_VERTEX]=grid_points[i];
d[VisualServer::ARRAY_COLOR]=grid_colors[i];
VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i],VisualServer::PRIMITIVE_LINES,d);
VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat->get_rid());
grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i],get_tree()->get_root()->get_world()->get_scenario());
grid_visible[i]=false;
grid_enable[i]=false;
VisualServer::get_singleton()->instance_set_visible(grid_instance[i],false);
VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
}
origin = VisualServer::get_singleton()->mesh_create();
Array d;
d.resize(VS::ARRAY_MAX);
d[VisualServer::ARRAY_VERTEX]=origin_points;
d[VisualServer::ARRAY_COLOR]=origin_colors;
VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin,VisualServer::PRIMITIVE_LINES,d);
VisualServer::get_singleton()->mesh_surface_set_material(origin,0,indicator_mat->get_rid());
//origin = VisualServer::get_singleton()->poly_create();
//VisualServer::get_singleton()->poly_add_primitive(origin,origin_points,Vector<Vector3>(),origin_colors,Vector<Vector3>());
//VisualServer::get_singleton()->poly_set_material(origin,indicator_mat,true);
origin_instance = VisualServer::get_singleton()->instance_create2(origin,get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_layer_mask(origin_instance,1<<SpatialEditorViewport::GIZMO_GRID_LAYER);
VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, VS::SHADOW_CASTING_SETTING_OFF);
VisualServer::get_singleton()->instance_set_visible(grid_instance[1],true);
grid_enable[1]=true;
grid_visible[1]=true;
grid_enabled=true;
last_grid_snap=1;
}
{
cursor_mesh = VisualServer::get_singleton()->mesh_create();
PoolVector<Vector3> cursor_points;
float cs = 0.25;
cursor_points.push_back(Vector3(+cs,0,0));
cursor_points.push_back(Vector3(-cs,0,0));
cursor_points.push_back(Vector3(0,+cs,0));
cursor_points.push_back(Vector3(0,-cs,0));
cursor_points.push_back(Vector3(0,0,+cs));
cursor_points.push_back(Vector3(0,0,-cs));
cursor_material.instance();
cursor_material->set_albedo(Color(0,1,1));
cursor_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
Array d;
d.resize(VS::ARRAY_MAX);
d[VS::ARRAY_VERTEX]=cursor_points;
VisualServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh,VS::PRIMITIVE_LINES,d);
VisualServer::get_singleton()->mesh_surface_set_material(cursor_mesh,0,cursor_material->get_rid());
cursor_instance = VisualServer::get_singleton()->instance_create2(cursor_mesh,get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_layer_mask(cursor_instance,1<<SpatialEditorViewport::GIZMO_GRID_LAYER);
VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, VS::SHADOW_CASTING_SETTING_OFF);
}
{
//move gizmo
float gizmo_alph = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_opacity");
gizmo_hl = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ) );
gizmo_hl->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
gizmo_hl->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
gizmo_hl->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
gizmo_hl->set_albedo(Color(1,1,1,gizmo_alph+0.2f));
for(int i=0;i<3;i++) {
move_gizmo[i]=Ref<Mesh>( memnew( Mesh ) );
rotate_gizmo[i]=Ref<Mesh>( memnew( Mesh ) );
Ref<FixedSpatialMaterial> mat = memnew( FixedSpatialMaterial );
mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
Color col;
col[i]=1.0;
col.a= gizmo_alph;
mat->set_albedo(col);
gizmo_color[i]=mat;
Vector3 ivec;
ivec[i]=1;
Vector3 nivec;
nivec[(i+1)%3]=1;
nivec[(i+2)%3]=1;
Vector3 ivec2;
ivec2[(i+1)%3]=1;
Vector3 ivec3;
ivec3[(i+2)%3]=1;
{
Ref<SurfaceTool> surftool = memnew( SurfaceTool );
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
//translate
const int arrow_points=5;
Vector3 arrow[5]={
nivec*0.0+ivec*0.0,
nivec*0.01+ivec*0.0,
nivec*0.01+ivec*1.0,
nivec*0.1+ivec*1.0,
nivec*0.0+ivec*(1+GIZMO_ARROW_SIZE),
};
int arrow_sides=6;
for(int k = 0; k < 7 ; k++) {
Basis ma(ivec,Math_PI*2*float(k)/arrow_sides);
Basis mb(ivec,Math_PI*2*float(k+1)/arrow_sides);
for(int j=0;j<arrow_points-1;j++) {
Vector3 points[4]={
ma.xform(arrow[j]),
mb.xform(arrow[j]),
mb.xform(arrow[j+1]),
ma.xform(arrow[j+1]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
}
}
surftool->set_material(mat);
surftool->commit(move_gizmo[i]);
}
{
Ref<SurfaceTool> surftool = memnew( SurfaceTool );
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
Vector3 circle[5]={
ivec*0.02+ivec2*0.02+ivec2*1.0,
ivec*-0.02+ivec2*0.02+ivec2*1.0,
ivec*-0.02+ivec2*-0.02+ivec2*1.0,
ivec*0.02+ivec2*-0.02+ivec2*1.0,
ivec*0.02+ivec2*0.02+ivec2*1.0,
};
for(int k = 0; k < 33 ; k++) {
Basis ma(ivec,Math_PI*2*float(k)/32);
Basis mb(ivec,Math_PI*2*float(k+1)/32);
for(int j=0;j<4;j++) {
Vector3 points[4]={
ma.xform(circle[j]),
mb.xform(circle[j]),
mb.xform(circle[j+1]),
ma.xform(circle[j+1]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
}
}
surftool->set_material(mat);
surftool->commit(rotate_gizmo[i]);
}
}
}
/*for(int i=0;i<4;i++) {
viewports[i]->init_gizmo_instance(i);
}*/
_generate_selection_box();
//get_scene()->get_root_node()->cast_to<EditorNode>()->get_scene_root()->add_child(camera);
//current_camera=camera;
}
void SpatialEditor::_finish_indicators() {
VisualServer::get_singleton()->free(origin_instance);
VisualServer::get_singleton()->free(origin);
for(int i=0;i<3;i++) {
VisualServer::get_singleton()->free(grid_instance[i]);
VisualServer::get_singleton()->free(grid[i]);
}
VisualServer::get_singleton()->free(light_instance);
VisualServer::get_singleton()->free(light);
//VisualServer::get_singleton()->free(poly);
//VisualServer::get_singleton()->free(indicators_instance);
//VisualServer::get_singleton()->free(indicators);
VisualServer::get_singleton()->free(cursor_instance);
VisualServer::get_singleton()->free(cursor_mesh);
}
void SpatialEditor::_instance_scene() {
#if 0
EditorNode *en = get_scene()->get_root_node()->cast_to<EditorNode>();
ERR_FAIL_COND(!en);
String path = en->get_filesystem_dock()->get_selected_path();
if (path=="") {
set_message(TTR("No scene selected to instance!"));
return;
}
undo_redo->create_action(TTR("Instance at Cursor"));
Node* scene = en->request_instance_scene(path);
if (!scene) {
set_message(TTR("Could not instance scene!"));
undo_redo->commit_action(); //bleh
return;
}
Spatial *s = scene->cast_to<Spatial>();
if (s) {
undo_redo->add_do_method(s,"set_global_transform",Transform(Matrix3(),cursor.cursor_pos));
}
undo_redo->commit_action();
#endif
}
void SpatialEditor::_unhandled_key_input(InputEvent p_event) {
if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
return;
#if 0
//i don't remember this being used, why was it here?
{
EditorNode *en = editor;
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
if (!over_plugin_list->empty() && over_plugin_list->forward_gui_input(p_event)) {
return; //ate the over input event
}
}
#endif
switch(p_event.type) {
case InputEvent::KEY: {
const InputEventKey &k=p_event.key;
if (!k.pressed)
break;
switch(k.scancode) {
case KEY_Q: _menu_item_pressed(MENU_TOOL_SELECT); break;
case KEY_W: _menu_item_pressed(MENU_TOOL_MOVE); break;
case KEY_E: _menu_item_pressed(MENU_TOOL_ROTATE); break;
case KEY_R: _menu_item_pressed(MENU_TOOL_SCALE); break;
case KEY_Z: {
if (k.mod.shift || k.mod.control || k.mod.command)
break;
if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME))) {
_menu_item_pressed(MENU_VIEW_DISPLAY_NORMAL);
} else {
_menu_item_pressed(MENU_VIEW_DISPLAY_WIREFRAME);
}
} break;
#if 0
#endif
}
} break;
}
}
void SpatialEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_READY) {
tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon( get_icon("ToolSelect","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon( get_icon("ToolMove","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon( get_icon("ToolRotate","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon( get_icon("ToolScale","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon( get_icon("ListSelect","EditorIcons") );
instance_button->set_icon( get_icon("SpatialAdd","EditorIcons") );
instance_button->hide();
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT),get_icon("Panels1","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS),get_icon("Panels2","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT),get_icon("Panels2Alt","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS),get_icon("Panels3","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT),get_icon("Panels3Alt","EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS),get_icon("Panels4","EditorIcons"));
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
get_tree()->connect("node_removed",this,"_node_removed");
VS::get_singleton()->scenario_set_fallback_environment(get_viewport()->find_world()->get_scenario(),viewport_environment->get_rid());
}
if (p_what==NOTIFICATION_ENTER_TREE) {
gizmos = memnew( SpatialEditorGizmos );
_init_indicators();
_update_default_light_angle();
}
if (p_what==NOTIFICATION_EXIT_TREE) {
_finish_indicators();
memdelete( gizmos );
}
}
void SpatialEditor::add_control_to_menu_panel(Control *p_control) {
hbc_menu->add_child(p_control);
}
void SpatialEditor::set_can_preview(Camera* p_preview) {
for(int i=0;i<4;i++) {
viewports[i]->set_can_preview(p_preview);
}
}
VSplitContainer *SpatialEditor::get_shader_split() {
return shader_split;
}
HSplitContainer *SpatialEditor::get_palette_split() {
return palette_split;
}
void SpatialEditor::_request_gizmo(Object* p_obj) {
Spatial *sp=p_obj->cast_to<Spatial>();
if (!sp)
return;
if (editor->get_edited_scene() && (sp==editor->get_edited_scene() || sp->get_owner()==editor->get_edited_scene() || editor->get_edited_scene()->is_editable_instance(sp->get_owner()))) {
Ref<SpatialEditorGizmo> seg;
for(int i=0;i<EditorNode::get_singleton()->get_editor_data().get_editor_plugin_count();i++) {
seg = EditorNode::get_singleton()->get_editor_data().get_editor_plugin(i)->create_spatial_gizmo(sp);
if (seg.is_valid())
break;
}
if (!seg.is_valid()) {
seg = gizmos->get_gizmo(sp);
}
if (seg.is_valid()) {
sp->set_gizmo(seg);
}
if (seg.is_valid() && sp==selected) {
seg->set_selected(true);
selected->update_gizmo();
}
}
}
void SpatialEditor::_toggle_maximize_view(Object* p_viewport) {
if (!p_viewport) return;
SpatialEditorViewport *current_viewport = p_viewport->cast_to<SpatialEditorViewport>();
if (!current_viewport) return;
int index=-1;
bool maximized = false;
for(int i=0;i<4;i++) {
if (viewports[i]==current_viewport) {
index=i;
if ( current_viewport->get_global_rect() == viewport_base->get_global_rect() )
maximized=true;
break;
}
}
if (index==-1) return;
if (!maximized) {
for(int i=0;i<4;i++) {
if (i==index)
viewports[i]->set_area_as_parent_rect();
else
viewports[i]->hide();
}
} else {
for(int i=0;i<4;i++)
viewports[i]->show();
if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT) ))
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS) ))
_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT) ))
_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS) ))
_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT) ))
_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
else if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS) ))
_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
}
}
void SpatialEditor::_node_removed(Node* p_node) {
if (p_node==selected)
selected=NULL;
}
void SpatialEditor::_bind_methods() {
//ClassDB::bind_method("_gui_input",&SpatialEditor::_gui_input);
ClassDB::bind_method("_unhandled_key_input",&SpatialEditor::_unhandled_key_input);
ClassDB::bind_method("_node_removed",&SpatialEditor::_node_removed);
ClassDB::bind_method("_menu_item_pressed",&SpatialEditor::_menu_item_pressed);
ClassDB::bind_method("_xform_dialog_action",&SpatialEditor::_xform_dialog_action);
ClassDB::bind_method("_instance_scene",&SpatialEditor::_instance_scene);
ClassDB::bind_method("_get_editor_data",&SpatialEditor::_get_editor_data);
ClassDB::bind_method("_request_gizmo",&SpatialEditor::_request_gizmo);
ClassDB::bind_method("_default_light_angle_input",&SpatialEditor::_default_light_angle_input);
ClassDB::bind_method("_update_ambient_light_color",&SpatialEditor::_update_ambient_light_color);
ClassDB::bind_method("_toggle_maximize_view",&SpatialEditor::_toggle_maximize_view);
ADD_SIGNAL( MethodInfo("transform_key_request") );
}
void SpatialEditor::clear() {
settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov",60.0));
settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near",0.1));
settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far",1500.0));
for(int i=0;i<4;i++) {
viewports[i]->reset();
}
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
_menu_item_pressed(MENU_VIEW_DISPLAY_NORMAL);
VisualServer::get_singleton()->instance_set_visible(origin_instance,true);
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
for(int i=0;i<3;++i) {
if (grid_enable[i]) {
VisualServer::get_singleton()->instance_set_visible(grid_instance[i],true);
grid_visible[i]=true;
}
}
for(int i=0;i<4;i++) {
viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER),i==0);
viewports[i]->viewport->set_as_audio_listener(i==0);
}
view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true );
settings_default_light_rot_x=Math_PI*0.3;
settings_default_light_rot_y=Math_PI*0.2;
//viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,Color(0.15,0.15,0.15));
settings_ambient_color->set_pick_color(Color(0.15,0.15,0.15));
if (!light_instance.is_valid())
_menu_item_pressed(MENU_VIEW_USE_DEFAULT_LIGHT);
_update_default_light_angle();
}
void SpatialEditor::_update_ambient_light_color(const Color& p_color) {
//viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,settings_ambient_color->get_color());
}
void SpatialEditor::_update_default_light_angle() {
Transform t;
t.basis.rotate(Vector3(1,0,0),-settings_default_light_rot_x);
t.basis.rotate(Vector3(0,1,0),-settings_default_light_rot_y);
settings_dlight->set_transform(t);
if (light_instance.is_valid()) {
VS::get_singleton()->instance_set_transform(light_instance,t);
}
}
void SpatialEditor::_default_light_angle_input(const InputEvent& p_event) {
if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&(0x1|0x2|0x4)) {
settings_default_light_rot_y = Math::fposmod(settings_default_light_rot_y - p_event.mouse_motion.relative_x*0.01,Math_PI*2.0);
settings_default_light_rot_x = Math::fposmod(settings_default_light_rot_x - p_event.mouse_motion.relative_y*0.01,Math_PI*2.0);
_update_default_light_angle();
}
}
SpatialEditor::SpatialEditor(EditorNode *p_editor) {
gizmo.visible=true;
gizmo.scale=1.0;
viewport_environment = Ref<Environment>( memnew( Environment ) );
undo_redo=p_editor->get_undo_redo();
VBoxContainer *vbc = this;
custom_camera=NULL;
singleton=this;
editor=p_editor;
editor_selection=editor->get_editor_selection();
editor_selection->add_editor_plugin(this);
snap_enabled=false;
tool_mode = TOOL_MODE_SELECT;
//set_focus_mode(FOCUS_ALL);
hbc_menu = memnew( HBoxContainer );
vbc->add_child(hbc_menu);
Vector<Variant> button_binds;
button_binds.resize(1);
tool_button[TOOL_MODE_SELECT] = memnew( ToolButton );
hbc_menu->add_child( tool_button[TOOL_MODE_SELECT] );
tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_SELECT]->set_flat(true);
tool_button[TOOL_MODE_SELECT]->set_pressed(true);
button_binds[0]=MENU_TOOL_SELECT;
tool_button[TOOL_MODE_SELECT]->connect("pressed", this,"_menu_item_pressed",button_binds);
tool_button[TOOL_MODE_SELECT]->set_tooltip("Select Mode (Q)\n"+keycode_get_string(KEY_MASK_CMD)+"Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection");
tool_button[TOOL_MODE_MOVE] = memnew( ToolButton );
hbc_menu->add_child( tool_button[TOOL_MODE_MOVE] );
tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
tool_button[TOOL_MODE_MOVE]->set_flat(true);
button_binds[0]=MENU_TOOL_MOVE;
tool_button[TOOL_MODE_MOVE]->connect("pressed", this,"_menu_item_pressed",button_binds);
tool_button[TOOL_MODE_MOVE]->set_tooltip(TTR("Move Mode (W)"));
tool_button[TOOL_MODE_ROTATE] = memnew( ToolButton );
hbc_menu->add_child( tool_button[TOOL_MODE_ROTATE] );
tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
tool_button[TOOL_MODE_ROTATE]->set_flat(true);
button_binds[0]=MENU_TOOL_ROTATE;
tool_button[TOOL_MODE_ROTATE]->connect("pressed", this,"_menu_item_pressed",button_binds);
tool_button[TOOL_MODE_ROTATE]->set_tooltip(TTR("Rotate Mode (E)"));
tool_button[TOOL_MODE_SCALE] = memnew( ToolButton );
hbc_menu->add_child( tool_button[TOOL_MODE_SCALE] );
tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
tool_button[TOOL_MODE_SCALE]->set_flat(true);
button_binds[0]=MENU_TOOL_SCALE;
tool_button[TOOL_MODE_SCALE]->connect("pressed", this,"_menu_item_pressed",button_binds);
tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)"));
instance_button = memnew( Button );
hbc_menu->add_child( instance_button );
instance_button->set_flat(true);
instance_button->connect("pressed",this,"_instance_scene");
instance_button->hide();
VSeparator *vs = memnew( VSeparator );
hbc_menu->add_child(vs);
tool_button[TOOL_MODE_LIST_SELECT] = memnew( ToolButton );
hbc_menu->add_child( tool_button[TOOL_MODE_LIST_SELECT] );
tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
button_binds[0]=MENU_TOOL_LIST_SELECT;
tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this,"_menu_item_pressed",button_binds);
tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
vs = memnew( VSeparator );
hbc_menu->add_child(vs);
ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT+KEY_KP_7);
ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7);
ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KEY_MASK_ALT+KEY_KP_1);
ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1);
ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT+KEY_KP_3);
ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3);
ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal view"), KEY_KP_5);
ED_SHORTCUT("spatial_editor/snap", TTR("Snap"), KEY_S);
ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K);
ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O);
ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
ED_SHORTCUT("spatial_editor/align_selection_with_view", TTR("Align Selection With View"), KEY_MASK_ALT+KEY_MASK_CMD+KEY_F);
PopupMenu *p;
transform_menu = memnew( MenuButton );
transform_menu->set_text(TTR("Transform"));
hbc_menu->add_child( transform_menu );
p = transform_menu->get_popup();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_snap", TTR("Use Snap")), MENU_TRANSFORM_USE_SNAP);
p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap..")), MENU_TRANSFORM_CONFIGURE_SNAP);
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Local Coords")), MENU_TRANSFORM_LOCAL_COORDS);
//p->set_item_checked(p->get_item_count()-1,true);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog..")), MENU_TRANSFORM_DIALOG);
p->connect("id_pressed", this,"_menu_item_pressed");
view_menu = memnew( MenuButton );
view_menu->set_text(TTR("View"));
view_menu->set_pos( Point2( 212,0) );
hbc_menu->add_child( view_menu );
p = view_menu->get_popup();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_default_light", TTR("Use Default Light")), MENU_VIEW_USE_DEFAULT_LIGHT);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_default_srgb", TTR("Use Default sRGB")), MENU_VIEW_USE_DEFAULT_SRGB);
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD+KEY_1), MENU_VIEW_USE_1_VIEWPORT);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD+KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT+KEY_MASK_CMD+KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"),KEY_MASK_CMD+KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT+KEY_MASK_CMD+KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD+KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_normal", TTR("Display Normal")), MENU_VIEW_DISPLAY_NORMAL);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe")), MENU_VIEW_DISPLAY_WIREFRAME);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_overdraw", TTR("Display Overdraw")), MENU_VIEW_DISPLAY_OVERDRAW);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_shadeless", TTR("Display Shadeless")), MENU_VIEW_DISPLAY_SHADELESS);
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS);
p->set_item_checked( p->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), true );
p->set_item_checked( p->get_item_index(MENU_VIEW_DISPLAY_NORMAL), true );
p->set_item_checked( p->get_item_index(MENU_VIEW_ORIGIN), true );
p->set_item_checked( p->get_item_index(MENU_VIEW_GRID), true );
p->connect("id_pressed", this,"_menu_item_pressed");
/* REST OF MENU */
palette_split = memnew( HSplitContainer);
palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
vbc->add_child(palette_split);
shader_split = memnew( VSplitContainer );
shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
palette_split->add_child(shader_split);
viewport_base = memnew( Control );
shader_split->add_child(viewport_base);
viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
for(int i=0;i<4;i++) {
viewports[i] = memnew( SpatialEditorViewport(this,editor,i) );
viewports[i]->connect("toggle_maximize_view",this,"_toggle_maximize_view");
viewport_base->add_child(viewports[i]);
}
//vbc->add_child(viewport_base);
/* SNAP DIALOG */
snap_dialog = memnew( ConfirmationDialog );
snap_dialog->set_title(TTR("Snap Settings"));
add_child(snap_dialog);
VBoxContainer *snap_dialog_vbc = memnew( VBoxContainer );
snap_dialog->add_child(snap_dialog_vbc);
//snap_dialog->set_child_rect(snap_dialog_vbc);
snap_translate = memnew( LineEdit );
snap_translate->set_text("1");
snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"),snap_translate);
snap_rotate = memnew( LineEdit );
snap_rotate->set_text("5");
snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"),snap_rotate);
snap_scale = memnew( LineEdit );
snap_scale->set_text("5");
snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"),snap_scale);
/* SETTINGS DIALOG */
settings_dialog = memnew( ConfirmationDialog );
settings_dialog->set_title(TTR("Viewport Settings"));
add_child(settings_dialog);
settings_vbc = memnew( VBoxContainer );
settings_vbc->set_custom_minimum_size(Size2(200,0));
settings_dialog->add_child(settings_vbc);
//settings_dialog->set_child_rect(settings_vbc);
settings_light_base = memnew( ViewportContainer );
settings_light_base->set_custom_minimum_size(Size2(128,128));
settings_light_base->connect("gui_input",this,"_default_light_angle_input");
settings_vbc->add_margin_child(TTR("Default Light Normal:"),settings_light_base);
settings_light_vp = memnew( Viewport );
settings_light_vp->set_disable_input(true);
settings_light_vp->set_use_own_world(true);
settings_light_base->add_child(settings_light_vp);
settings_dlight = memnew( DirectionalLight );
settings_light_vp->add_child(settings_dlight);
settings_sphere = memnew( ImmediateGeometry );
settings_sphere->begin(Mesh::PRIMITIVE_TRIANGLES,Ref<Texture>());
settings_sphere->set_color(Color(1,1,1));
settings_sphere->add_sphere(32,16,1);
settings_sphere->end();
settings_light_vp->add_child(settings_sphere);
settings_camera = memnew( Camera );
settings_light_vp->add_child(settings_camera);
settings_camera->set_translation(Vector3(0,0,2));
settings_camera->set_orthogonal(2.1,0.1,5);
settings_default_light_rot_x=Math_PI*0.3;
settings_default_light_rot_y=Math_PI*0.2;
settings_ambient_color = memnew( ColorPickerButton );
settings_vbc->add_margin_child(TTR("Ambient Light Color:"),settings_ambient_color);
settings_ambient_color->connect("color_changed",this,"_update_ambient_light_color");
settings_ambient_color->set_pick_color(Color(0.15,0.15,0.15));
settings_fov = memnew( SpinBox );
settings_fov->set_max(179);
settings_fov->set_min(1);
settings_fov->set_step(0.01);
settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov",60.0));
settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"),settings_fov);
settings_znear = memnew( SpinBox );
settings_znear->set_max(10000);
settings_znear->set_min(0.1);
settings_znear->set_step(0.01);
settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near",0.1));
settings_vbc->add_margin_child(TTR("View Z-Near:"),settings_znear);
settings_zfar = memnew( SpinBox );
settings_zfar->set_max(10000);
settings_zfar->set_min(0.1);
settings_zfar->set_step(0.01);
settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far",1500));
settings_vbc->add_margin_child(TTR("View Z-Far:"),settings_zfar);
//settings_dialog->get_cancel()->hide();
/* XFORM DIALOG */
xform_dialog = memnew( ConfirmationDialog );
xform_dialog->set_title(TTR("Transform Change"));
add_child(xform_dialog);
Label *l = memnew(Label);
l->set_text(TTR("Translate:"));
l->set_pos(Point2(5,5));
xform_dialog->add_child(l);
for(int i=0;i<3;i++) {
xform_translate[i] = memnew( LineEdit );
xform_translate[i]->set_pos( Point2(15+i*60,22) );
xform_translate[i]->set_size( Size2(50,12 ) );
xform_dialog->add_child( xform_translate[i] );
}
l = memnew(Label);
l->set_text(TTR("Rotate (deg.):"));
l->set_pos(Point2(5,45));
xform_dialog->add_child(l);
for(int i=0;i<3;i++) {
xform_rotate[i] = memnew( LineEdit );
xform_rotate[i]->set_pos( Point2(15+i*60,62) );
xform_rotate[i]->set_size( Size2(50,22 ) );
xform_dialog->add_child(xform_rotate[i]);
}
l = memnew(Label);
l->set_text(TTR("Scale (ratio):"));
l->set_pos(Point2(5,85));
xform_dialog->add_child(l);
for(int i=0;i<3;i++) {
xform_scale[i] = memnew( LineEdit );
xform_scale[i]->set_pos( Point2(15+i*60,102) );
xform_scale[i]->set_size( Size2(50,22 ) );
xform_dialog->add_child(xform_scale[i]);
}
l = memnew(Label);
l->set_text(TTR("Transform Type"));
l->set_pos(Point2(5,125));
xform_dialog->add_child(l);
xform_type = memnew( OptionButton );
xform_type->set_anchor( MARGIN_RIGHT, ANCHOR_END );
xform_type->set_begin( Point2(15,142) );
xform_type->set_end( Point2(15,75) );
xform_type->add_item(TTR("Pre"));
xform_type->add_item(TTR("Post"));
xform_dialog->add_child(xform_type);
xform_dialog->connect("confirmed", this,"_xform_dialog_action");
scenario_debug=VisualServer::SCENARIO_DEBUG_DISABLED;
selected=NULL;
set_process_unhandled_key_input(true);
add_to_group("_spatial_editor_group");
EDITOR_DEF("editors/3d/manipulator_gizmo_size",80);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT,"editors/3d/manipulator_gizmo_size",PROPERTY_HINT_RANGE,"16,1024,1"));
EDITOR_DEF("editors/3d/manipulator_gizmo_opacity",0.2);
over_gizmo_handle=-1;
}
SpatialEditor::~SpatialEditor() {
}
void SpatialEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
spatial_editor->show();
spatial_editor->set_process(true);
//VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),false);
spatial_editor->grab_focus();
} else {
spatial_editor->hide();
spatial_editor->set_process(false);
//VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),true);
}
}
void SpatialEditorPlugin::edit(Object *p_object) {
spatial_editor->edit(p_object->cast_to<Spatial>());
}
bool SpatialEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("Spatial");
}
Dictionary SpatialEditorPlugin::get_state() const {
return spatial_editor->get_state();
}
void SpatialEditorPlugin::set_state(const Dictionary& p_state) {
spatial_editor->set_state(p_state);
}
void SpatialEditor::snap_cursor_to_plane(const Plane& p_plane) {
//cursor.pos=p_plane.project(cursor.pos);
}
void SpatialEditorPlugin::_bind_methods() {
ClassDB::bind_method("snap_cursor_to_plane",&SpatialEditorPlugin::snap_cursor_to_plane);
}
void SpatialEditorPlugin::snap_cursor_to_plane(const Plane& p_plane) {
spatial_editor->snap_cursor_to_plane(p_plane);
}
SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
editor=p_node;
spatial_editor = memnew( SpatialEditor(p_node) );
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
editor->get_viewport()->add_child(spatial_editor);
//spatial_editor->set_area_as_parent_rect();
spatial_editor->hide();
spatial_editor->connect("transform_key_request",editor,"_transform_keyed");
//spatial_editor->set_process(true);
}
SpatialEditorPlugin::~SpatialEditorPlugin() {
}