2016-06-18 14:46:12 +02:00
/*************************************************************************/
/* collision_polygon.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2017-01-01 22:01:57 +01:00
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2016-06-18 14:46:12 +02: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. */
/*************************************************************************/
2014-09-17 02:19:54 +02:00
# include "collision_polygon.h"
# include "collision_object.h"
# include "scene/resources/concave_polygon_shape.h"
# include "scene/resources/convex_polygon_shape.h"
void CollisionPolygon : : _add_to_collision_object ( Object * p_obj ) {
2015-09-16 03:07:03 +02:00
if ( ! can_update_body )
return ;
2014-09-17 02:19:54 +02:00
CollisionObject * co = p_obj - > cast_to < CollisionObject > ( ) ;
ERR_FAIL_COND ( ! co ) ;
if ( polygon . size ( ) = = 0 )
return ;
bool solids = build_mode = = BUILD_SOLIDS ;
Vector < Vector < Vector2 > > decomp = Geometry : : decompose_polygon ( polygon ) ;
if ( decomp . size ( ) = = 0 )
return ;
if ( true | | solids ) {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
2015-09-16 03:07:03 +02:00
shape_from = co - > get_shape_count ( ) ;
2014-09-17 02:19:54 +02:00
for ( int i = 0 ; i < decomp . size ( ) ; i + + ) {
Ref < ConvexPolygonShape > convex = memnew ( ConvexPolygonShape ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > cp ;
2014-09-17 02:19:54 +02:00
int cs = decomp [ i ] . size ( ) ;
cp . resize ( cs * 2 ) ;
{
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > : : Write w = cp . write ( ) ;
2014-09-17 02:19:54 +02:00
int idx = 0 ;
for ( int j = 0 ; j < cs ; j + + ) {
Vector2 d = decomp [ i ] [ j ] ;
w [ idx + + ] = Vector3 ( d . x , d . y , depth * 0.5 ) ;
w [ idx + + ] = Vector3 ( d . x , d . y , - depth * 0.5 ) ;
}
}
convex - > set_points ( cp ) ;
co - > add_shape ( convex , get_transform ( ) ) ;
}
2015-09-16 03:07:03 +02:00
shape_to = co - > get_shape_count ( ) - 1 ;
if ( shape_to < shape_from ) {
shape_from = - 1 ;
shape_to = - 1 ;
}
2014-09-17 02:19:54 +02:00
} else {
#if 0
Ref < ConcavePolygonShape > concave = memnew ( ConcavePolygonShape ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector2 > segments ;
2014-09-17 02:19:54 +02:00
segments . resize ( polygon . size ( ) * 2 ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector2 > : : Write w = segments . write ( ) ;
2014-09-17 02:19:54 +02:00
for ( int i = 0 ; i < polygon . size ( ) ; i + + ) {
w [ ( i < < 1 ) + 0 ] = polygon [ i ] ;
w [ ( i < < 1 ) + 1 ] = polygon [ ( i + 1 ) % polygon . size ( ) ] ;
}
2017-01-07 22:25:37 +01:00
w = PoolVector < Vector2 > : : Write ( ) ;
2014-09-17 02:19:54 +02:00
concave - > set_segments ( segments ) ;
co - > add_shape ( concave , get_transform ( ) ) ;
# endif
}
//co->add_shape(shape,get_transform());
}
void CollisionPolygon : : _update_parent ( ) {
2015-09-16 03:07:03 +02:00
if ( ! can_update_body )
return ;
2014-09-17 02:19:54 +02:00
Node * parent = get_parent ( ) ;
if ( ! parent )
return ;
CollisionObject * co = parent - > cast_to < CollisionObject > ( ) ;
if ( ! co )
return ;
co - > _update_shapes_from_children ( ) ;
}
2015-09-16 03:07:03 +02:00
void CollisionPolygon : : _set_shape_range ( const Vector2 & p_range ) {
shape_from = p_range . x ;
shape_to = p_range . y ;
}
Vector2 CollisionPolygon : : _get_shape_range ( ) const {
return Vector2 ( shape_from , shape_to ) ;
}
2014-09-17 02:19:54 +02:00
void CollisionPolygon : : _notification ( int p_what ) {
switch ( p_what ) {
2015-09-16 03:07:03 +02:00
case NOTIFICATION_ENTER_TREE : {
can_update_body = get_tree ( ) - > is_editor_hint ( ) ;
set_notify_local_transform ( ! can_update_body ) ;
//indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario());
} break ;
case NOTIFICATION_EXIT_TREE : {
can_update_body = false ;
set_notify_local_transform ( false ) ;
} break ;
2014-09-17 02:19:54 +02:00
case NOTIFICATION_TRANSFORM_CHANGED : {
2014-11-06 01:20:42 +01:00
if ( ! is_inside_tree ( ) )
2014-09-17 02:19:54 +02:00
break ;
2015-09-16 03:07:03 +02:00
if ( can_update_body ) {
_update_parent ( ) ;
}
} break ;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED : {
2015-10-17 15:29:54 +02:00
if ( ! can_update_body & & shape_from > = 0 & & shape_to > = 0 ) {
2015-09-16 03:07:03 +02:00
CollisionObject * co = get_parent ( ) - > cast_to < CollisionObject > ( ) ;
if ( co ) {
for ( int i = shape_from ; i < = shape_to ; i + + ) {
co - > set_shape_transform ( i , get_transform ( ) ) ;
}
}
}
2014-09-17 02:19:54 +02:00
} break ;
#if 0
case NOTIFICATION_DRAW : {
for ( int i = 0 ; i < polygon . size ( ) ; i + + ) {
Vector2 p = polygon [ i ] ;
Vector2 n = polygon [ ( i + 1 ) % polygon . size ( ) ] ;
draw_line ( p , n , Color ( 0 , 0.6 , 0.7 , 0.5 ) , 3 ) ;
}
Vector < Vector < Vector2 > > decomp = Geometry : : decompose_polygon ( polygon ) ;
# define DEBUG_DECOMPOSE
# ifdef DEBUG_DECOMPOSE
Color c ( 0.4 , 0.9 , 0.1 ) ;
for ( int i = 0 ; i < decomp . size ( ) ; i + + ) {
c . set_hsv ( Math : : fmod ( c . get_h ( ) + 0.738 , 1 ) , c . get_s ( ) , c . get_v ( ) , 0.5 ) ;
draw_colored_polygon ( decomp [ i ] , c ) ;
}
# endif
} break ;
# endif
}
}
void CollisionPolygon : : set_polygon ( const Vector < Point2 > & p_polygon ) {
polygon = p_polygon ;
2015-09-16 03:07:03 +02:00
if ( can_update_body ) {
2014-09-17 02:19:54 +02:00
2015-09-16 03:07:03 +02:00
for ( int i = 0 ; i < polygon . size ( ) ; i + + ) {
2014-09-17 02:19:54 +02:00
2015-09-16 03:07:03 +02:00
Vector3 p1 ( polygon [ i ] . x , polygon [ i ] . y , depth * 0.5 ) ;
2014-09-17 02:19:54 +02:00
2015-09-16 03:07:03 +02:00
if ( i = = 0 )
2017-01-11 04:52:51 +01:00
aabb = Rect3 ( p1 , Vector3 ( ) ) ;
2015-09-16 03:07:03 +02:00
else
aabb . expand_to ( p1 ) ;
2014-09-17 02:19:54 +02:00
2015-09-16 03:07:03 +02:00
Vector3 p2 ( polygon [ i ] . x , polygon [ i ] . y , - depth * 0.5 ) ;
aabb . expand_to ( p2 ) ;
2014-09-17 02:19:54 +02:00
2015-09-16 03:07:03 +02:00
}
2017-01-11 04:52:51 +01:00
if ( aabb = = Rect3 ( ) ) {
2014-09-17 02:19:54 +02:00
2017-01-11 04:52:51 +01:00
aabb = Rect3 ( Vector3 ( - 1 , - 1 , - 1 ) , Vector3 ( 2 , 2 , 2 ) ) ;
2015-09-16 03:07:03 +02:00
} else {
aabb . pos - = aabb . size * 0.3 ;
aabb . size + = aabb . size * 0.6 ;
}
_update_parent ( ) ;
2014-09-17 02:19:54 +02:00
}
update_gizmo ( ) ;
}
Vector < Point2 > CollisionPolygon : : get_polygon ( ) const {
return polygon ;
}
void CollisionPolygon : : set_build_mode ( BuildMode p_mode ) {
ERR_FAIL_INDEX ( p_mode , 2 ) ;
build_mode = p_mode ;
2015-09-16 03:07:03 +02:00
if ( ! can_update_body )
return ;
2014-09-17 02:19:54 +02:00
_update_parent ( ) ;
}
CollisionPolygon : : BuildMode CollisionPolygon : : get_build_mode ( ) const {
return build_mode ;
}
2017-01-11 04:52:51 +01:00
Rect3 CollisionPolygon : : get_item_rect ( ) const {
2014-09-17 02:19:54 +02:00
return aabb ;
}
void CollisionPolygon : : set_depth ( float p_depth ) {
depth = p_depth ;
2015-09-16 03:07:03 +02:00
if ( ! can_update_body )
return ;
2014-09-17 02:19:54 +02:00
_update_parent ( ) ;
update_gizmo ( ) ;
}
float CollisionPolygon : : get_depth ( ) const {
return depth ;
}
2016-05-17 23:27:15 +02:00
String CollisionPolygon : : get_configuration_warning ( ) const {
if ( ! get_parent ( ) - > cast_to < CollisionObject > ( ) ) {
return TTR ( " CollisionPolygon only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape. " ) ;
}
if ( polygon . empty ( ) ) {
return TTR ( " An empty CollisionPolygon has no effect on collision. " ) ;
}
return String ( ) ;
}
2014-09-17 02:19:54 +02:00
void CollisionPolygon : : _bind_methods ( ) {
2017-01-03 03:03:46 +01:00
ClassDB : : bind_method ( _MD ( " _add_to_collision_object " ) , & CollisionPolygon : : _add_to_collision_object ) ;
2015-09-16 03:07:03 +02:00
2017-01-03 03:03:46 +01:00
ClassDB : : bind_method ( _MD ( " set_build_mode " , " build_mode " ) , & CollisionPolygon : : set_build_mode ) ;
ClassDB : : bind_method ( _MD ( " get_build_mode " ) , & CollisionPolygon : : get_build_mode ) ;
2014-09-17 02:19:54 +02:00
2017-01-03 03:03:46 +01:00
ClassDB : : bind_method ( _MD ( " set_depth " , " depth " ) , & CollisionPolygon : : set_depth ) ;
ClassDB : : bind_method ( _MD ( " get_depth " ) , & CollisionPolygon : : get_depth ) ;
2014-09-17 02:19:54 +02:00
2017-01-03 03:03:46 +01:00
ClassDB : : bind_method ( _MD ( " set_polygon " , " polygon " ) , & CollisionPolygon : : set_polygon ) ;
ClassDB : : bind_method ( _MD ( " get_polygon " ) , & CollisionPolygon : : get_polygon ) ;
2015-09-16 03:07:03 +02:00
2017-01-03 03:03:46 +01:00
ClassDB : : bind_method ( _MD ( " _set_shape_range " , " shape_range " ) , & CollisionPolygon : : _set_shape_range ) ;
ClassDB : : bind_method ( _MD ( " _get_shape_range " ) , & CollisionPolygon : : _get_shape_range ) ;
2015-09-16 03:07:03 +02:00
2017-01-03 03:03:46 +01:00
ClassDB : : bind_method ( _MD ( " get_collision_object_first_shape " ) , & CollisionPolygon : : get_collision_object_first_shape ) ;
ClassDB : : bind_method ( _MD ( " get_collision_object_last_shape " ) , & CollisionPolygon : : get_collision_object_last_shape ) ;
2014-09-17 02:19:54 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " build_mode " , PROPERTY_HINT_ENUM , " Solids,Triangles " ) , _SCS ( " set_build_mode " ) , _SCS ( " get_build_mode " ) ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " depth " ) , _SCS ( " set_depth " ) , _SCS ( " get_depth " ) ) ;
2017-01-11 04:52:51 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : POOL_VECTOR2_ARRAY , " polygon " ) , _SCS ( " set_polygon " ) , _SCS ( " get_polygon " ) ) ;
2015-09-16 03:07:03 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " shape_range " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR ) , _SCS ( " _set_shape_range " ) , _SCS ( " _get_shape_range " ) ) ;
2014-09-17 02:19:54 +02:00
}
CollisionPolygon : : CollisionPolygon ( ) {
2015-09-16 03:07:03 +02:00
shape_from = - 1 ;
shape_to = - 1 ;
can_update_body = false ;
2017-01-11 04:52:51 +01:00
aabb = Rect3 ( Vector3 ( - 1 , - 1 , - 1 ) , Vector3 ( 2 , 2 , 2 ) ) ;
2014-09-17 02:19:54 +02:00
build_mode = BUILD_SOLIDS ;
depth = 1.0 ;
}