2014-02-10 09:10:30 +08:00
/*************************************************************************/
/* spatial.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2017-01-02 05:01:57 +08:00
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2017-04-08 06:11:42 +08:00
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 09:10:30 +08:00
/* */
/* 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.h"
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
# include "message_queue.h"
2017-03-05 23:44:50 +08:00
# include "scene/main/viewport.h"
2014-02-10 09:10:30 +08:00
# include "scene/scene_string_names.h"
/*
possible algorithms :
Algorithm 1 : ( current )
definition of invalidation : global is invalid
1 ) If a node sets a LOCAL , it produces an invalidation of everything above
a ) If above is invalid , don ' t keep invalidating upwards
2 ) If a node sets a GLOBAL , it is converted to LOCAL ( and forces validation of everything pending below )
drawback : setting / reading globals is useful and used very very often , and using affine inverses is slow
- - -
Algorithm 2 : ( no longer current )
definition of invalidation : NONE dirty , LOCAL dirty , GLOBAL dirty
1 ) If a node sets a LOCAL , it must climb the tree and set it as GLOBAL dirty
a ) marking GLOBALs as dirty up all the tree must be done always
2 ) If a node sets a GLOBAL , it marks local as dirty , and that ' s all ?
//is clearing the dirty state correct in this case?
drawback : setting a local down the tree forces many tree walks often
- -
future : no idea
*/
SpatialGizmo : : SpatialGizmo ( ) {
}
void Spatial : : _notify_dirty ( ) {
2017-01-13 07:35:46 +08:00
if ( data . notify_transform & & ! data . ignore_notification & & ! xform_change . in_list ( ) ) {
2014-02-10 09:10:30 +08:00
2014-11-06 08:20:42 +08:00
get_tree ( ) - > xform_change_list . add ( & xform_change ) ;
2014-02-10 09:10:30 +08:00
}
}
void Spatial : : _update_local_transform ( ) const {
2017-01-11 11:52:51 +08:00
data . local_transform . basis = Basis ( ) ;
2014-02-10 09:10:30 +08:00
data . local_transform . basis . scale ( data . scale ) ;
2017-01-06 01:31:39 +08:00
data . local_transform . basis . rotate ( data . rotation ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
data . dirty & = ~ DIRTY_LOCAL ;
2014-02-10 09:10:30 +08:00
}
void Spatial : : _propagate_transform_changed ( Spatial * p_origin ) {
2014-11-06 08:20:42 +08:00
if ( ! is_inside_tree ( ) ) {
2014-02-10 09:10:30 +08:00
return ;
}
2017-01-14 19:26:56 +08:00
/*
if ( data . dirty & DIRTY_GLOBAL )
return ; //already dirty
*/
2014-02-10 09:10:30 +08:00
data . children_lock + + ;
2016-03-09 07:00:52 +08:00
2017-03-05 23:44:50 +08:00
for ( List < Spatial * > : : Element * E = data . children . front ( ) ; E ; E = E - > next ( ) ) {
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
if ( E - > get ( ) - > data . toplevel_active )
continue ; //don't propagate to a toplevel
E - > get ( ) - > _propagate_transform_changed ( p_origin ) ;
}
2016-03-09 07:00:52 +08:00
2017-01-13 07:35:46 +08:00
if ( data . notify_transform & & ! data . ignore_notification & & ! xform_change . in_list ( ) ) {
2014-02-10 09:10:30 +08:00
2014-11-06 08:20:42 +08:00
get_tree ( ) - > xform_change_list . add ( & xform_change ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
data . dirty | = DIRTY_GLOBAL ;
2014-02-10 09:10:30 +08:00
data . children_lock - - ;
}
void Spatial : : _notification ( int p_what ) {
2017-03-05 23:44:50 +08:00
switch ( p_what ) {
2014-11-06 08:20:42 +08:00
case NOTIFICATION_ENTER_TREE : {
2014-02-10 09:10:30 +08:00
Node * p = get_parent ( ) ;
if ( p )
2017-03-05 23:44:50 +08:00
data . parent = p - > cast_to < Spatial > ( ) ;
2014-02-10 09:10:30 +08:00
if ( data . parent )
2017-03-05 23:44:50 +08:00
data . C = data . parent - > data . children . push_back ( this ) ;
2014-02-10 09:10:30 +08:00
else
2017-03-05 23:44:50 +08:00
data . C = NULL ;
2014-02-10 09:10:30 +08:00
2014-11-06 08:20:42 +08:00
if ( data . toplevel & & ! get_tree ( ) - > is_editor_hint ( ) ) {
2014-02-10 09:10:30 +08:00
if ( data . parent ) {
data . local_transform = data . parent - > get_global_transform ( ) * get_transform ( ) ;
2017-03-05 23:44:50 +08:00
data . dirty = DIRTY_VECTORS ; //global is always dirty upon entering a scene
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
data . toplevel_active = true ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
data . dirty | = DIRTY_GLOBAL ; //global is always dirty upon entering a scene
2014-02-10 09:10:30 +08:00
_notify_dirty ( ) ;
notification ( NOTIFICATION_ENTER_WORLD ) ;
} break ;
2014-11-06 08:20:42 +08:00
case NOTIFICATION_EXIT_TREE : {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
notification ( NOTIFICATION_EXIT_WORLD , true ) ;
2014-02-10 09:10:30 +08:00
if ( xform_change . in_list ( ) )
2014-11-06 08:20:42 +08:00
get_tree ( ) - > xform_change_list . remove ( & xform_change ) ;
2014-02-10 09:10:30 +08:00
if ( data . C )
data . parent - > data . children . erase ( data . C ) ;
2017-03-05 23:44:50 +08:00
data . parent = NULL ;
data . C = NULL ;
data . toplevel_active = false ;
2014-02-10 09:10:30 +08:00
} break ;
case NOTIFICATION_ENTER_WORLD : {
2017-03-05 23:44:50 +08:00
data . inside_world = true ;
data . viewport = NULL ;
2014-02-10 09:10:30 +08:00
Node * parent = get_parent ( ) ;
2017-03-05 23:44:50 +08:00
while ( parent & & ! data . viewport ) {
data . viewport = parent - > cast_to < Viewport > ( ) ;
parent = parent - > get_parent ( ) ;
2014-02-10 09:10:30 +08:00
}
ERR_FAIL_COND ( ! data . viewport ) ;
if ( get_script_instance ( ) ) {
Variant : : CallError err ;
2017-03-05 23:44:50 +08:00
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _enter_world , NULL , 0 ) ;
2014-02-10 09:10:30 +08:00
}
# ifdef TOOLS_ENABLED
2014-11-06 08:20:42 +08:00
if ( get_tree ( ) - > is_editor_hint ( ) ) {
2014-02-10 09:10:30 +08:00
2017-01-14 19:26:56 +08:00
//get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
2017-03-05 23:44:50 +08:00
get_tree ( ) - > call_group_flags ( 0 , SceneStringNames : : get_singleton ( ) - > _spatial_editor_group , SceneStringNames : : get_singleton ( ) - > _request_gizmo , this ) ;
2014-02-10 09:10:30 +08:00
if ( ! data . gizmo_disabled ) {
if ( data . gizmo . is_valid ( ) )
data . gizmo - > create ( ) ;
}
}
# endif
} break ;
case NOTIFICATION_EXIT_WORLD : {
# ifdef TOOLS_ENABLED
if ( data . gizmo . is_valid ( ) ) {
data . gizmo - > free ( ) ;
}
# endif
if ( get_script_instance ( ) ) {
Variant : : CallError err ;
2017-03-05 23:44:50 +08:00
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _exit_world , NULL , 0 ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
data . viewport = NULL ;
data . inside_world = false ;
2014-02-10 09:10:30 +08:00
} break ;
case NOTIFICATION_TRANSFORM_CHANGED : {
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
# ifdef TOOLS_ENABLED
if ( data . gizmo . is_valid ( ) ) {
data . gizmo - > transform ( ) ;
}
# endif
} break ;
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
default : { }
}
}
2017-03-05 23:44:50 +08:00
void Spatial : : set_transform ( const Transform & p_transform ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
data . local_transform = p_transform ;
data . dirty | = DIRTY_VECTORS ;
2017-04-04 00:34:44 +08:00
_change_notify ( " translation " ) ;
_change_notify ( " rotation " ) ;
_change_notify ( " rotation_deg " ) ;
_change_notify ( " scale " ) ;
2014-02-10 09:10:30 +08:00
_propagate_transform_changed ( this ) ;
2015-09-16 09:07:03 +08:00
if ( data . notify_local_transform ) {
notification ( NOTIFICATION_LOCAL_TRANSFORM_CHANGED ) ;
}
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void Spatial : : set_global_transform ( const Transform & p_transform ) {
2014-02-10 09:10:30 +08:00
Transform xform =
( data . parent & & ! data . toplevel_active ) ?
2017-03-05 23:44:50 +08:00
data . parent - > get_global_transform ( ) . affine_inverse ( ) * p_transform :
p_transform ;
2014-02-10 09:10:30 +08:00
set_transform ( xform ) ;
}
Transform Spatial : : get_transform ( ) const {
if ( data . dirty & DIRTY_LOCAL ) {
_update_local_transform ( ) ;
}
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
return data . local_transform ;
}
Transform Spatial : : get_global_transform ( ) const {
2014-11-06 08:20:42 +08:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Transform ( ) ) ;
2014-02-10 09:10:30 +08:00
if ( data . dirty & DIRTY_GLOBAL ) {
if ( data . dirty & DIRTY_LOCAL ) {
_update_local_transform ( ) ;
}
if ( data . parent & & ! data . toplevel_active ) {
2016-03-09 07:00:52 +08:00
2017-03-05 23:44:50 +08:00
data . global_transform = data . parent - > get_global_transform ( ) * data . local_transform ;
2014-02-10 09:10:30 +08:00
} else {
2016-03-09 07:00:52 +08:00
2017-03-05 23:44:50 +08:00
data . global_transform = data . local_transform ;
2014-02-10 09:10:30 +08:00
}
2016-03-09 07:00:52 +08:00
2017-03-05 23:44:50 +08:00
data . dirty & = ~ DIRTY_GLOBAL ;
2014-02-10 09:10:30 +08:00
}
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
return data . global_transform ;
}
#if 0
void Spatial : : add_child_notify ( Node * p_child ) {
/*
Spatial * s = p_child - > cast_to < Spatial > ( ) ;
if ( ! s )
return ;
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
ERR_FAIL_COND ( data . children_lock > 0 ) ;
s - > data . dirty = DIRTY_GLOBAL ; // don't allow global transform to be valid
s - > data . parent = this ;
data . children . push_back ( s ) ;
s - > data . C = data . children . back ( ) ;
*/
}
void Spatial : : remove_child_notify ( Node * p_child ) {
/*
Spatial * s = p_child - > cast_to < Spatial > ( ) ;
if ( ! s )
return ;
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
ERR_FAIL_COND ( data . children_lock > 0 ) ;
2016-03-09 07:00:52 +08:00
2014-02-10 09:10:30 +08:00
if ( s - > data . C )
data . children . erase ( s - > data . C ) ;
2016-03-09 07:00:52 +08:00
s - > data . parent = NULL ;
2014-02-10 09:10:30 +08:00
s - > data . C = NULL ;
*/
}
# endif
Spatial * Spatial : : get_parent_spatial ( ) const {
return data . parent ;
}
Transform Spatial : : get_relative_transform ( const Node * p_parent ) const {
2017-03-05 23:44:50 +08:00
if ( p_parent = = this )
2014-02-10 09:10:30 +08:00
return Transform ( ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND_V ( ! data . parent , Transform ( ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( p_parent = = data . parent )
2014-02-10 09:10:30 +08:00
return get_transform ( ) ;
else
return data . parent - > get_relative_transform ( p_parent ) * get_transform ( ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : set_translation ( const Vector3 & p_translation ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
data . local_transform . origin = p_translation ;
2014-02-10 09:10:30 +08:00
_propagate_transform_changed ( this ) ;
2015-09-16 09:07:03 +08:00
if ( data . notify_local_transform ) {
notification ( NOTIFICATION_LOCAL_TRANSFORM_CHANGED ) ;
}
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void Spatial : : set_rotation ( const Vector3 & p_euler_rad ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( data . dirty & DIRTY_VECTORS ) {
data . scale = data . local_transform . basis . get_scale ( ) ;
data . dirty & = ~ DIRTY_VECTORS ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
data . rotation = p_euler_rad ;
data . dirty | = DIRTY_LOCAL ;
2014-02-10 09:10:30 +08:00
_propagate_transform_changed ( this ) ;
2015-09-16 09:07:03 +08:00
if ( data . notify_local_transform ) {
notification ( NOTIFICATION_LOCAL_TRANSFORM_CHANGED ) ;
}
2014-02-10 09:10:30 +08:00
}
2016-05-07 05:38:08 +08:00
2017-03-05 23:44:50 +08:00
void Spatial : : set_rotation_in_degrees ( const Vector3 & p_euler_deg ) {
2016-05-07 05:38:08 +08:00
set_rotation ( p_euler_deg * Math_PI / 180.0 ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : _set_rotation_deg ( const Vector3 & p_euler_deg ) {
2016-05-07 05:38:08 +08:00
WARN_PRINT ( " Deprecated method Spatial._set_rotation_deg(): This method was renamed to set_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted. " ) ;
2017-01-04 12:16:14 +08:00
set_rotation_in_degrees ( p_euler_deg ) ;
2016-05-07 05:38:08 +08:00
}
2017-03-05 23:44:50 +08:00
void Spatial : : set_scale ( const Vector3 & p_scale ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( data . dirty & DIRTY_VECTORS ) {
data . rotation = data . local_transform . basis . get_rotation ( ) ;
data . dirty & = ~ DIRTY_VECTORS ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
data . scale = p_scale ;
data . dirty | = DIRTY_LOCAL ;
2014-02-10 09:10:30 +08:00
_propagate_transform_changed ( this ) ;
2015-09-16 09:07:03 +08:00
if ( data . notify_local_transform ) {
notification ( NOTIFICATION_LOCAL_TRANSFORM_CHANGED ) ;
}
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
Vector3 Spatial : : get_translation ( ) const {
2014-02-10 09:10:30 +08:00
return data . local_transform . origin ;
}
2016-05-07 05:38:08 +08:00
2017-03-05 23:44:50 +08:00
Vector3 Spatial : : get_rotation ( ) const {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( data . dirty & DIRTY_VECTORS ) {
data . scale = data . local_transform . basis . get_scale ( ) ;
data . rotation = data . local_transform . basis . get_rotation ( ) ;
2017-01-06 01:31:39 +08:00
2017-03-05 23:44:50 +08:00
data . dirty & = ~ DIRTY_VECTORS ;
2014-02-10 09:10:30 +08:00
}
return data . rotation ;
}
2016-05-07 05:38:08 +08:00
2017-01-04 12:16:14 +08:00
Vector3 Spatial : : get_rotation_in_degrees ( ) const {
2016-05-07 05:38:08 +08:00
return get_rotation ( ) * 180.0 / Math_PI ;
}
// Kept for compatibility after rename to set_rotd.
// Could be removed after a couple releases.
Vector3 Spatial : : _get_rotation_deg ( ) const {
WARN_PRINT ( " Deprecated method Spatial._get_rotation_deg(): This method was renamed to get_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted. " ) ;
2017-01-04 12:16:14 +08:00
return get_rotation_in_degrees ( ) ;
2016-05-07 05:38:08 +08:00
}
2017-03-05 23:44:50 +08:00
Vector3 Spatial : : get_scale ( ) const {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( data . dirty & DIRTY_VECTORS ) {
data . scale = data . local_transform . basis . get_scale ( ) ;
data . rotation = data . local_transform . basis . get_rotation ( ) ;
2017-01-06 01:31:39 +08:00
2017-03-05 23:44:50 +08:00
data . dirty & = ~ DIRTY_VECTORS ;
2014-02-10 09:10:30 +08:00
}
return data . scale ;
}
void Spatial : : update_gizmo ( ) {
# ifdef TOOLS_ENABLED
if ( ! is_inside_world ( ) )
return ;
if ( ! data . gizmo . is_valid ( ) )
return ;
if ( data . gizmo_dirty )
return ;
2017-03-05 23:44:50 +08:00
data . gizmo_dirty = true ;
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_gizmo " ) ;
2014-02-10 09:10:30 +08:00
# endif
}
2017-03-05 23:44:50 +08:00
void Spatial : : set_gizmo ( const Ref < SpatialGizmo > & p_gizmo ) {
2014-02-10 09:10:30 +08:00
# ifdef TOOLS_ENABLED
if ( data . gizmo_disabled )
return ;
if ( data . gizmo . is_valid ( ) & & is_inside_world ( ) )
data . gizmo - > free ( ) ;
2017-03-05 23:44:50 +08:00
data . gizmo = p_gizmo ;
2014-02-10 09:10:30 +08:00
if ( data . gizmo . is_valid ( ) & & is_inside_world ( ) ) {
data . gizmo - > create ( ) ;
data . gizmo - > redraw ( ) ;
data . gizmo - > transform ( ) ;
}
# endif
}
Ref < SpatialGizmo > Spatial : : get_gizmo ( ) const {
# ifdef TOOLS_ENABLED
return data . gizmo ;
# else
return Ref < SpatialGizmo > ( ) ;
# endif
}
# ifdef TOOLS_ENABLED
void Spatial : : _update_gizmo ( ) {
2017-03-05 23:44:50 +08:00
data . gizmo_dirty = false ;
2014-09-20 05:39:50 +08:00
if ( data . gizmo . is_valid ( ) ) {
2017-01-13 21:45:50 +08:00
if ( is_visible_in_tree ( ) )
2014-09-20 05:39:50 +08:00
data . gizmo - > redraw ( ) ;
else
data . gizmo - > clear ( ) ;
}
2014-02-10 09:10:30 +08:00
}
void Spatial : : set_disable_gizmo ( bool p_enabled ) {
2017-03-05 23:44:50 +08:00
data . gizmo_disabled = p_enabled ;
2014-02-10 09:10:30 +08:00
if ( ! p_enabled & & data . gizmo . is_valid ( ) )
2017-03-05 23:44:50 +08:00
data . gizmo = Ref < SpatialGizmo > ( ) ;
2014-02-10 09:10:30 +08:00
}
# endif
void Spatial : : set_as_toplevel ( bool p_enabled ) {
2017-03-05 23:44:50 +08:00
if ( data . toplevel = = p_enabled )
2014-02-10 09:10:30 +08:00
return ;
2014-11-06 08:20:42 +08:00
if ( is_inside_tree ( ) & & ! get_tree ( ) - > is_editor_hint ( ) ) {
2014-02-10 09:10:30 +08:00
if ( p_enabled )
set_transform ( get_global_transform ( ) ) ;
else if ( data . parent )
set_transform ( data . parent - > get_global_transform ( ) . affine_inverse ( ) * get_global_transform ( ) ) ;
2017-03-05 23:44:50 +08:00
data . toplevel = p_enabled ;
data . toplevel_active = p_enabled ;
2014-02-10 09:10:30 +08:00
} else {
2017-03-05 23:44:50 +08:00
data . toplevel = p_enabled ;
2014-02-10 09:10:30 +08:00
}
}
2017-03-05 23:44:50 +08:00
bool Spatial : : is_set_as_toplevel ( ) const {
2014-02-10 09:10:30 +08:00
return data . toplevel ;
}
Ref < World > Spatial : : get_world ( ) const {
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND_V ( ! is_inside_world ( ) , Ref < World > ( ) ) ;
2014-02-10 09:10:30 +08:00
return data . viewport - > find_world ( ) ;
}
2014-08-14 21:31:38 +08:00
void Spatial : : _propagate_visibility_changed ( ) {
notification ( NOTIFICATION_VISIBILITY_CHANGED ) ;
emit_signal ( SceneStringNames : : get_singleton ( ) - > visibility_changed ) ;
2017-04-04 00:34:44 +08:00
_change_notify ( " visible " ) ;
2014-09-20 05:39:50 +08:00
# ifdef TOOLS_ENABLED
if ( data . gizmo . is_valid ( ) )
_update_gizmo ( ) ;
# endif
2014-08-14 21:31:38 +08:00
2017-03-05 23:44:50 +08:00
for ( List < Spatial * > : : Element * E = data . children . front ( ) ; E ; E = E - > next ( ) ) {
2014-08-14 21:31:38 +08:00
2017-03-05 23:44:50 +08:00
Spatial * c = E - > get ( ) ;
2014-08-14 21:31:38 +08:00
if ( ! c | | ! c - > data . visible )
continue ;
c - > _propagate_visibility_changed ( ) ;
}
}
void Spatial : : show ( ) {
if ( data . visible )
return ;
2017-03-05 23:44:50 +08:00
data . visible = true ;
2014-08-14 21:31:38 +08:00
2014-11-06 08:20:42 +08:00
if ( ! is_inside_tree ( ) )
2014-08-14 21:31:38 +08:00
return ;
2017-07-02 23:27:27 +08:00
_propagate_visibility_changed ( ) ;
2014-08-14 21:31:38 +08:00
}
2017-03-05 23:44:50 +08:00
void Spatial : : hide ( ) {
2014-08-14 21:31:38 +08:00
if ( ! data . visible )
return ;
2017-03-05 23:44:50 +08:00
data . visible = false ;
2014-08-14 21:31:38 +08:00
2017-07-02 23:27:27 +08:00
if ( ! is_inside_tree ( ) )
return ;
2014-08-14 21:31:38 +08:00
2017-07-02 23:27:27 +08:00
_propagate_visibility_changed ( ) ;
2014-08-14 21:31:38 +08:00
}
2017-07-02 23:27:27 +08:00
2017-03-05 23:44:50 +08:00
bool Spatial : : is_visible_in_tree ( ) const {
2014-08-14 21:31:38 +08:00
2017-03-05 23:44:50 +08:00
const Spatial * s = this ;
2014-08-14 21:31:38 +08:00
2017-03-05 23:44:50 +08:00
while ( s ) {
2014-08-14 21:31:38 +08:00
if ( ! s - > data . visible ) {
return false ;
}
2017-03-05 23:44:50 +08:00
s = s - > data . parent ;
2014-08-14 21:31:38 +08:00
}
return true ;
}
2017-01-13 21:45:50 +08:00
void Spatial : : set_visible ( bool p_visible ) {
2014-08-14 21:31:38 +08:00
if ( p_visible )
show ( ) ;
else
hide ( ) ;
}
2017-01-13 21:45:50 +08:00
bool Spatial : : is_visible ( ) const {
2014-08-14 21:31:38 +08:00
2017-01-19 04:49:30 +08:00
return data . visible ;
2014-08-14 21:31:38 +08:00
}
2017-03-05 23:44:50 +08:00
void Spatial : : rotate ( const Vector3 & p_normal , float p_radians ) {
2015-03-22 21:33:58 +08:00
2017-03-05 23:44:50 +08:00
Transform t = get_transform ( ) ;
t . basis . rotate ( p_normal , p_radians ) ;
2015-03-22 21:33:58 +08:00
set_transform ( t ) ;
}
void Spatial : : rotate_x ( float p_radians ) {
2017-03-05 23:44:50 +08:00
Transform t = get_transform ( ) ;
t . basis . rotate ( Vector3 ( 1 , 0 , 0 ) , p_radians ) ;
2015-03-22 21:33:58 +08:00
set_transform ( t ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : rotate_y ( float p_radians ) {
2015-03-22 21:33:58 +08:00
2017-03-05 23:44:50 +08:00
Transform t = get_transform ( ) ;
t . basis . rotate ( Vector3 ( 0 , 1 , 0 ) , p_radians ) ;
2015-03-22 21:33:58 +08:00
set_transform ( t ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : rotate_z ( float p_radians ) {
2015-03-22 21:33:58 +08:00
2017-03-05 23:44:50 +08:00
Transform t = get_transform ( ) ;
t . basis . rotate ( Vector3 ( 0 , 0 , 1 ) , p_radians ) ;
2015-03-22 21:33:58 +08:00
set_transform ( t ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : translate ( const Vector3 & p_offset ) {
2015-03-22 21:33:58 +08:00
2017-03-05 23:44:50 +08:00
Transform t = get_transform ( ) ;
2015-06-06 20:44:38 +08:00
t . translate ( p_offset ) ;
2015-03-22 21:33:58 +08:00
set_transform ( t ) ;
}
2015-06-06 20:44:38 +08:00
2017-03-05 23:44:50 +08:00
void Spatial : : scale ( const Vector3 & p_ratio ) {
2015-03-22 21:33:58 +08:00
2017-03-05 23:44:50 +08:00
Transform t = get_transform ( ) ;
2015-03-22 21:33:58 +08:00
t . basis . scale ( p_ratio ) ;
set_transform ( t ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : global_rotate ( const Vector3 & p_normal , float p_radians ) {
2015-03-22 21:33:58 +08:00
2017-03-05 23:44:50 +08:00
Basis rotation ( p_normal , p_radians ) ;
2015-03-22 21:33:58 +08:00
Transform t = get_global_transform ( ) ;
2017-03-05 23:44:50 +08:00
t . basis = rotation * t . basis ;
2015-03-22 21:33:58 +08:00
set_global_transform ( t ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : global_translate ( const Vector3 & p_offset ) {
2015-03-22 21:33:58 +08:00
Transform t = get_global_transform ( ) ;
2017-03-05 23:44:50 +08:00
t . origin + = p_offset ;
2015-03-22 21:33:58 +08:00
set_global_transform ( t ) ;
}
void Spatial : : orthonormalize ( ) {
Transform t = get_transform ( ) ;
t . orthonormalize ( ) ;
set_transform ( t ) ;
}
2015-03-22 22:52:07 +08:00
void Spatial : : set_identity ( ) {
set_transform ( Transform ( ) ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : look_at ( const Vector3 & p_target , const Vector3 & p_up_normal ) {
2015-03-22 21:33:58 +08:00
Transform lookat ;
2017-03-05 23:44:50 +08:00
lookat . origin = get_global_transform ( ) . origin ;
if ( lookat . origin = = p_target ) {
2016-06-12 04:22:07 +08:00
ERR_EXPLAIN ( " Node origin and target are in the same position, look_at() failed " ) ;
ERR_FAIL ( ) ;
}
2017-03-05 23:44:50 +08:00
if ( p_up_normal . cross ( p_target - lookat . origin ) = = Vector3 ( ) ) {
2016-06-12 04:25:43 +08:00
ERR_EXPLAIN ( " Up vector and direction between node origin and target are aligned, look_at() failed " ) ;
2016-06-12 04:22:07 +08:00
ERR_FAIL ( ) ;
}
2017-03-05 23:44:50 +08:00
lookat = lookat . looking_at ( p_target , p_up_normal ) ;
2015-03-22 21:33:58 +08:00
set_global_transform ( lookat ) ;
}
2017-03-05 23:44:50 +08:00
void Spatial : : look_at_from_pos ( const Vector3 & p_pos , const Vector3 & p_target , const Vector3 & p_up_normal ) {
2015-03-22 21:33:58 +08:00
Transform lookat ;
2017-03-05 23:44:50 +08:00
lookat . origin = p_pos ;
lookat = lookat . looking_at ( p_target , p_up_normal ) ;
2015-03-22 21:33:58 +08:00
set_global_transform ( lookat ) ;
}
2017-07-23 19:37:26 +08:00
Vector3 Spatial : : to_local ( Vector3 p_global ) const {
return get_global_transform ( ) . affine_inverse ( ) . xform ( p_global ) ;
}
Vector3 Spatial : : to_global ( Vector3 p_local ) const {
return get_global_transform ( ) . xform ( p_local ) ;
}
2017-01-13 07:35:46 +08:00
void Spatial : : set_notify_transform ( bool p_enable ) {
2017-03-05 23:44:50 +08:00
data . notify_transform = p_enable ;
2017-01-13 07:35:46 +08:00
}
bool Spatial : : is_transform_notification_enabled ( ) const {
return data . notify_transform ;
}
2015-09-16 09:07:03 +08:00
void Spatial : : set_notify_local_transform ( bool p_enable ) {
2017-03-05 23:44:50 +08:00
data . notify_local_transform = p_enable ;
2015-09-16 09:07:03 +08:00
}
bool Spatial : : is_local_transform_notification_enabled ( ) const {
return data . notify_local_transform ;
}
2014-08-14 21:31:38 +08:00
2014-02-10 09:10:30 +08:00
void Spatial : : _bind_methods ( ) {
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_transform " , " local " ) , & Spatial : : set_transform ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_transform " ) , & Spatial : : get_transform ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_translation " , " translation " ) , & Spatial : : set_translation ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_translation " ) , & Spatial : : get_translation ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_rotation " , " rotation_rad " ) , & Spatial : : set_rotation ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_rotation " ) , & Spatial : : get_rotation ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_rotation_deg " , " rotation_deg " ) , & Spatial : : set_rotation_in_degrees ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_rotation_deg " ) , & Spatial : : get_rotation_in_degrees ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_scale " , " scale " ) , & Spatial : : set_scale ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_scale " ) , & Spatial : : get_scale ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_global_transform " , " global " ) , & Spatial : : set_global_transform ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_global_transform " ) , & Spatial : : get_global_transform ) ;
2017-07-22 18:11:42 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_parent_spatial:Spatial " ) , & Spatial : : get_parent_spatial ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_ignore_transform_notification " , " enabled " ) , & Spatial : : set_ignore_transform_notification ) ;
ClassDB : : bind_method ( D_METHOD ( " set_as_toplevel " , " enable " ) , & Spatial : : set_as_toplevel ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " is_set_as_toplevel " ) , & Spatial : : is_set_as_toplevel ) ;
ClassDB : : bind_method ( D_METHOD ( " get_world:World " ) , & Spatial : : get_world ) ;
2016-05-07 05:38:08 +08:00
// TODO: Obsolete those two methods (old name) properly (GH-4397)
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " _set_rotation_deg " , " rotation_deg " ) , & Spatial : : _set_rotation_deg ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " _get_rotation_deg " ) , & Spatial : : _get_rotation_deg ) ;
2014-02-10 09:10:30 +08:00
# ifdef TOOLS_ENABLED
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " _update_gizmo " ) , & Spatial : : _update_gizmo ) ;
2014-02-10 09:10:30 +08:00
# endif
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " update_gizmo " ) , & Spatial : : update_gizmo ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_gizmo " , " gizmo:SpatialGizmo " ) , & Spatial : : set_gizmo ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_gizmo:SpatialGizmo " ) , & Spatial : : get_gizmo ) ;
2014-02-10 09:10:30 +08:00
2017-07-22 18:11:42 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_visible " , " visible " ) , & Spatial : : set_visible ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " is_visible " ) , & Spatial : : is_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " is_visible_in_tree " ) , & Spatial : : is_visible_in_tree ) ;
ClassDB : : bind_method ( D_METHOD ( " show " ) , & Spatial : : show ) ;
ClassDB : : bind_method ( D_METHOD ( " hide " ) , & Spatial : : hide ) ;
2014-08-14 21:31:38 +08:00
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_notify_local_transform " , " enable " ) , & Spatial : : set_notify_local_transform ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " is_local_transform_notification_enabled " ) , & Spatial : : is_local_transform_notification_enabled ) ;
2015-09-16 09:07:03 +08:00
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_notify_transform " , " enable " ) , & Spatial : : set_notify_transform ) ;
2017-02-13 19:47:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " is_transform_notification_enabled " ) , & Spatial : : is_transform_notification_enabled ) ;
2017-01-13 07:35:46 +08:00
2017-03-05 23:44:50 +08:00
void rotate ( const Vector3 & p_normal , float p_radians ) ;
2015-03-22 21:33:58 +08:00
void rotate_x ( float p_radians ) ;
void rotate_y ( float p_radians ) ;
void rotate_z ( float p_radians ) ;
2017-03-05 23:44:50 +08:00
void translate ( const Vector3 & p_offset ) ;
void scale ( const Vector3 & p_ratio ) ;
void global_rotate ( const Vector3 & p_normal , float p_radians ) ;
void global_translate ( const Vector3 & p_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " rotate " , " normal " , " radians " ) , & Spatial : : rotate ) ;
ClassDB : : bind_method ( D_METHOD ( " global_rotate " , " normal " , " radians " ) , & Spatial : : global_rotate ) ;
ClassDB : : bind_method ( D_METHOD ( " rotate_x " , " radians " ) , & Spatial : : rotate_x ) ;
ClassDB : : bind_method ( D_METHOD ( " rotate_y " , " radians " ) , & Spatial : : rotate_y ) ;
ClassDB : : bind_method ( D_METHOD ( " rotate_z " , " radians " ) , & Spatial : : rotate_z ) ;
ClassDB : : bind_method ( D_METHOD ( " translate " , " offset " ) , & Spatial : : translate ) ;
ClassDB : : bind_method ( D_METHOD ( " global_translate " , " offset " ) , & Spatial : : global_translate ) ;
ClassDB : : bind_method ( D_METHOD ( " orthonormalize " ) , & Spatial : : orthonormalize ) ;
ClassDB : : bind_method ( D_METHOD ( " set_identity " ) , & Spatial : : set_identity ) ;
ClassDB : : bind_method ( D_METHOD ( " look_at " , " target " , " up " ) , & Spatial : : look_at ) ;
ClassDB : : bind_method ( D_METHOD ( " look_at_from_pos " , " pos " , " target " , " up " ) , & Spatial : : look_at_from_pos ) ;
2017-07-23 19:37:26 +08:00
ClassDB : : bind_method ( D_METHOD ( " to_local " , " global_point " ) , & Spatial : : to_local ) ;
ClassDB : : bind_method ( D_METHOD ( " to_global " , " local_point " ) , & Spatial : : to_global ) ;
2017-03-05 23:44:50 +08:00
BIND_CONSTANT ( NOTIFICATION_TRANSFORM_CHANGED ) ;
BIND_CONSTANT ( NOTIFICATION_ENTER_WORLD ) ;
BIND_CONSTANT ( NOTIFICATION_EXIT_WORLD ) ;
BIND_CONSTANT ( NOTIFICATION_VISIBILITY_CHANGED ) ;
2014-02-10 09:10:30 +08:00
2017-02-12 08:11:37 +08:00
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
2017-03-05 23:44:50 +08:00
ADD_GROUP ( " Transform " , " " ) ;
ADD_PROPERTYNZ ( PropertyInfo ( Variant : : TRANSFORM , " transform " , PROPERTY_HINT_NONE , " " ) , " set_transform " , " get_transform " ) ;
ADD_PROPERTYNZ ( PropertyInfo ( Variant : : TRANSFORM , " global_transform " , PROPERTY_HINT_NONE , " " , 0 ) , " set_global_transform " , " get_global_transform " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR3 , " translation " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR ) , " set_translation " , " get_translation " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR3 , " rotation_deg " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR ) , " set_rotation_deg " , " get_rotation_deg " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR3 , " rotation " , PROPERTY_HINT_NONE , " " , 0 ) , " set_rotation " , " get_rotation " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR3 , " scale " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR ) , " set_scale " , " get_scale " ) ;
ADD_GROUP ( " Visibility " , " " ) ;
ADD_PROPERTYNO ( PropertyInfo ( Variant : : BOOL , " visible " ) , " set_visible " , " is_visible " ) ;
2017-02-12 08:11:37 +08:00
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), "set_transform", "get_transform") ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
ADD_SIGNAL ( MethodInfo ( " visibility_changed " ) ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
Spatial : : Spatial ( )
: xform_change ( this ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
data . dirty = DIRTY_NONE ;
data . children_lock = 0 ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
data . ignore_notification = false ;
data . toplevel = false ;
data . toplevel_active = false ;
data . scale = Vector3 ( 1 , 1 , 1 ) ;
data . viewport = NULL ;
data . inside_world = false ;
data . visible = true ;
2017-01-13 07:35:46 +08:00
2014-02-10 09:10:30 +08:00
# ifdef TOOLS_ENABLED
2017-03-05 23:44:50 +08:00
data . gizmo_disabled = false ;
data . gizmo_dirty = false ;
2014-02-10 09:10:30 +08:00
# endif
2017-03-05 23:44:50 +08:00
data . notify_local_transform = false ;
data . notify_transform = false ;
data . parent = NULL ;
data . C = NULL ;
2014-02-10 09:10:30 +08:00
}
Spatial : : ~ Spatial ( ) {
}