2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* tile_map.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01: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. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "tile_map.h"
2017-12-10 16:40:31 +01:00
2019-02-06 00:45:40 +01:00
# include "collision_object_2d.h"
2018-09-11 18:13:45 +02:00
# include "core/io/marshalls.h"
# include "core/method_bind_ext.gen.inc"
# include "core/os/os.h"
2019-02-06 00:45:40 +01:00
# include "scene/2d/area_2d.h"
2017-03-05 16:44:50 +01:00
# include "servers/physics_2d_server.h"
2015-12-12 14:45:31 +01:00
2015-03-09 06:34:56 +01:00
int TileMap : : _get_quadrant_size ( ) const {
if ( y_sort_mode )
return 1 ;
else
return quadrant_size ;
}
2014-02-10 02:10:30 +01:00
void TileMap : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
switch ( p_what ) {
2014-02-10 02:10:30 +01:00
2014-11-06 01:20:42 +01:00
case NOTIFICATION_ENTER_TREE : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Node2D * c = this ;
while ( c ) {
2015-03-09 06:34:56 +01:00
2017-08-24 22:58:51 +02:00
navigation = Object : : cast_to < Navigation2D > ( c ) ;
2015-03-09 06:34:56 +01:00
if ( navigation ) {
break ;
}
2017-08-24 22:58:51 +02:00
c = Object : : cast_to < Node2D > ( c - > get_parent ( ) ) ;
2015-03-09 06:34:56 +01:00
}
2019-02-06 00:45:40 +01:00
if ( use_parent ) {
_clear_quadrants ( ) ;
collision_parent = Object : : cast_to < CollisionObject2D > ( get_parent ( ) ) ;
}
2017-03-05 16:44:50 +01:00
pending_update = true ;
2018-01-20 20:21:00 +01:00
_recreate_quadrants ( ) ;
2018-07-22 15:26:14 +02:00
update_dirty_quadrants ( ) ;
2014-02-10 02:10:30 +01:00
RID space = get_world_2d ( ) - > get_space ( ) ;
_update_quadrant_transform ( ) ;
_update_quadrant_space ( space ) ;
2019-02-06 00:45:40 +01:00
update_configuration_warning ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2019-02-06 00:45:40 +01:00
2014-11-06 01:20:42 +01:00
case NOTIFICATION_EXIT_TREE : {
2014-02-10 02:10:30 +01:00
_update_quadrant_space ( RID ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
2017-03-05 16:44:50 +01:00
Quadrant & q = E - > get ( ) ;
2015-03-09 06:34:56 +01:00
if ( navigation ) {
2019-02-12 21:10:08 +01:00
for ( Map < PosKey , Quadrant : : NavPoly > : : Element * F = q . navpoly_ids . front ( ) ; F ; F = F - > next ( ) ) {
2015-03-09 06:34:56 +01:00
2019-02-12 21:10:08 +01:00
navigation - > navpoly_remove ( F - > get ( ) . id ) ;
2015-03-09 06:34:56 +01:00
}
q . navpoly_ids . clear ( ) ;
}
2019-02-06 00:45:40 +01:00
if ( collision_parent ) {
collision_parent - > remove_shape_owner ( q . shape_owner_id ) ;
q . shape_owner_id = - 1 ;
}
2019-02-12 21:10:08 +01:00
for ( Map < PosKey , Quadrant : : Occluder > : : Element * F = q . occluder_instances . front ( ) ; F ; F = F - > next ( ) ) {
VS : : get_singleton ( ) - > free ( F - > get ( ) . id ) ;
2015-03-09 06:34:56 +01:00
}
q . occluder_instances . clear ( ) ;
}
2019-02-06 00:45:40 +01:00
collision_parent = NULL ;
2017-03-05 16:44:50 +01:00
navigation = NULL ;
2014-02-10 02:10:30 +01:00
} break ;
2019-02-06 00:45:40 +01:00
2014-02-10 02:10:30 +01:00
case NOTIFICATION_TRANSFORM_CHANGED : {
//move stuff
_update_quadrant_transform ( ) ;
} break ;
2019-02-06 00:45:40 +01:00
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED : {
if ( use_parent ) {
_recreate_quadrants ( ) ;
}
} break ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
void TileMap : : _update_quadrant_space ( const RID & p_space ) {
2014-02-10 02:10:30 +01:00
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2019-02-06 00:45:40 +01:00
Quadrant & q = E - > get ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_space ( q . body , p_space ) ;
}
2014-02-10 02:10:30 +01:00
}
}
void TileMap : : _update_quadrant_transform ( ) {
2014-11-06 01:20:42 +01:00
if ( ! is_inside_tree ( ) )
2014-02-10 02:10:30 +01:00
return ;
2017-01-11 04:52:51 +01:00
Transform2D global_transform = get_global_transform ( ) ;
2014-02-10 02:10:30 +01:00
2019-02-06 00:45:40 +01:00
Transform2D local_transform ;
if ( collision_parent )
local_transform = get_transform ( ) ;
2017-01-11 04:52:51 +01:00
Transform2D nav_rel ;
2015-03-09 06:34:56 +01:00
if ( navigation )
2015-12-29 01:05:57 +01:00
nav_rel = get_relative_transform_to_parent ( navigation ) ;
2015-03-09 06:34:56 +01:00
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Quadrant & q = E - > get ( ) ;
2017-01-11 04:52:51 +01:00
Transform2D xform ;
2017-03-05 16:44:50 +01:00
xform . set_origin ( q . pos ) ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
xform = global_transform * xform ;
Physics2DServer : : get_singleton ( ) - > body_set_state ( q . body , Physics2DServer : : BODY_STATE_TRANSFORM , xform ) ;
}
2015-03-09 06:34:56 +01:00
if ( navigation ) {
2019-02-12 21:10:08 +01:00
for ( Map < PosKey , Quadrant : : NavPoly > : : Element * F = q . navpoly_ids . front ( ) ; F ; F = F - > next ( ) ) {
2015-03-09 06:34:56 +01:00
2019-02-12 21:10:08 +01:00
navigation - > navpoly_set_transform ( F - > get ( ) . id , nav_rel * F - > get ( ) . xform ) ;
2015-03-09 06:34:56 +01:00
}
}
2019-02-12 21:10:08 +01:00
for ( Map < PosKey , Quadrant : : Occluder > : : Element * F = q . occluder_instances . front ( ) ; F ; F = F - > next ( ) ) {
VS : : get_singleton ( ) - > canvas_light_occluder_set_transform ( F - > get ( ) . id , global_transform * F - > get ( ) . xform ) ;
2015-03-09 06:34:56 +01:00
}
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
void TileMap : : set_tileset ( const Ref < TileSet > & p_tileset ) {
2014-02-10 02:10:30 +01:00
2018-03-11 12:24:50 +01:00
if ( tile_set . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
tile_set - > disconnect ( " changed " , this , " _recreate_quadrants " ) ;
2018-03-11 12:24:50 +01:00
tile_set - > remove_change_receptor ( this ) ;
}
2014-02-10 02:10:30 +01:00
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
tile_set = p_tileset ;
2014-02-10 02:10:30 +01:00
2018-03-11 12:24:50 +01:00
if ( tile_set . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
tile_set - > connect ( " changed " , this , " _recreate_quadrants " ) ;
2018-03-11 12:24:50 +01:00
tile_set - > add_change_receptor ( this ) ;
} else {
2014-02-10 02:10:30 +01:00
clear ( ) ;
2018-03-11 12:24:50 +01:00
}
2014-02-10 02:10:30 +01:00
_recreate_quadrants ( ) ;
2014-04-19 21:46:52 +02:00
emit_signal ( " settings_changed " ) ;
2014-02-10 02:10:30 +01:00
}
Ref < TileSet > TileMap : : get_tileset ( ) const {
return tile_set ;
}
2014-10-03 05:10:51 +02:00
void TileMap : : set_cell_size ( Size2 p_size ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_size . x < 1 | | p_size . y < 1 ) ;
2014-02-10 02:10:30 +01:00
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
cell_size = p_size ;
2014-02-10 02:10:30 +01:00
_recreate_quadrants ( ) ;
2014-04-19 21:46:52 +02:00
emit_signal ( " settings_changed " ) ;
2014-02-10 02:10:30 +01:00
}
2017-12-10 16:40:31 +01:00
2014-10-03 05:10:51 +02:00
Size2 TileMap : : get_cell_size ( ) const {
2014-02-10 02:10:30 +01:00
return cell_size ;
}
2017-12-10 16:40:31 +01:00
2014-02-10 02:10:30 +01:00
void TileMap : : set_quadrant_size ( int p_size ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_size < 1 ) ;
2014-02-10 02:10:30 +01:00
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
quadrant_size = p_size ;
2014-02-10 02:10:30 +01:00
_recreate_quadrants ( ) ;
2014-04-19 21:46:52 +02:00
emit_signal ( " settings_changed " ) ;
2014-02-10 02:10:30 +01:00
}
2017-12-10 16:40:31 +01:00
2014-02-10 02:10:30 +01:00
int TileMap : : get_quadrant_size ( ) const {
return quadrant_size ;
}
2017-03-05 16:44:50 +01:00
void TileMap : : _fix_cell_transform ( Transform2D & xform , const Cell & p_cell , const Vector2 & p_offset , const Size2 & p_sc ) {
2015-03-09 06:34:56 +01:00
2017-03-05 16:44:50 +01:00
Size2 s = p_sc ;
2015-03-09 09:28:08 +01:00
Vector2 offset = p_offset ;
2016-06-18 00:01:00 +02:00
2019-07-01 22:43:52 +02:00
if ( compatibility_mode & & ! centered_textures ) {
if ( tile_origin = = TILE_ORIGIN_BOTTOM_LEFT ) {
offset . y + = cell_size . y ;
} else if ( tile_origin = = TILE_ORIGIN_CENTER ) {
offset + = cell_size / 2 ;
}
if ( s . y > s . x ) {
if ( ( p_cell . flip_h & & ( p_cell . flip_v | | p_cell . transpose ) ) | | ( p_cell . flip_v & & ! p_cell . transpose ) ) {
offset . y + = s . y - s . x ;
}
} else if ( s . y < s . x ) {
if ( ( p_cell . flip_v & & ( p_cell . flip_h | | p_cell . transpose ) ) | | ( p_cell . flip_h & & ! p_cell . transpose ) ) {
offset . x + = s . x - s . y ;
}
}
}
2015-03-09 09:28:08 +01:00
if ( p_cell . transpose ) {
2015-03-09 06:34:56 +01:00
SWAP ( xform . elements [ 0 ] . x , xform . elements [ 0 ] . y ) ;
SWAP ( xform . elements [ 1 ] . x , xform . elements [ 1 ] . y ) ;
SWAP ( offset . x , offset . y ) ;
SWAP ( s . x , s . y ) ;
}
2019-05-15 04:14:27 +02:00
2015-03-09 09:28:08 +01:00
if ( p_cell . flip_h ) {
2017-03-05 16:44:50 +01:00
xform . elements [ 0 ] . x = - xform . elements [ 0 ] . x ;
xform . elements [ 1 ] . x = - xform . elements [ 1 ] . x ;
2019-07-01 22:43:52 +02:00
if ( compatibility_mode & & ! centered_textures ) {
if ( tile_origin = = TILE_ORIGIN_TOP_LEFT | | tile_origin = = TILE_ORIGIN_BOTTOM_LEFT ) {
offset . x = s . x - offset . x ;
} else if ( tile_origin = = TILE_ORIGIN_CENTER ) {
offset . x = s . x - offset . x / 2 ;
}
} else {
offset . x = s . x - offset . x ;
}
2015-03-09 06:34:56 +01:00
}
2019-05-15 04:14:27 +02:00
2015-03-09 09:28:08 +01:00
if ( p_cell . flip_v ) {
2017-03-05 16:44:50 +01:00
xform . elements [ 0 ] . y = - xform . elements [ 0 ] . y ;
xform . elements [ 1 ] . y = - xform . elements [ 1 ] . y ;
2019-07-01 22:43:52 +02:00
if ( compatibility_mode & & ! centered_textures ) {
if ( tile_origin = = TILE_ORIGIN_TOP_LEFT ) {
offset . y = s . y - offset . y ;
} else if ( tile_origin = = TILE_ORIGIN_BOTTOM_LEFT ) {
offset . y + = s . y ;
} else if ( tile_origin = = TILE_ORIGIN_CENTER ) {
offset . y + = s . y ;
}
} else {
offset . y = s . y - offset . y ;
}
}
if ( centered_textures ) {
offset + = cell_size / 2 - s / 2 ;
2015-03-09 06:34:56 +01:00
}
2019-05-15 04:14:27 +02:00
xform . elements [ 2 ] + = offset ;
2015-03-09 06:34:56 +01:00
}
2019-02-06 00:45:40 +01:00
void TileMap : : _add_shape ( int & shape_idx , const Quadrant & p_q , const Ref < Shape2D > & p_shape , const TileSet : : ShapeData & p_shape_data , const Transform2D & p_xform , const Vector2 & p_metadata ) {
Physics2DServer * ps = Physics2DServer : : get_singleton ( ) ;
if ( ! use_parent ) {
ps - > body_add_shape ( p_q . body , p_shape - > get_rid ( ) , p_xform ) ;
ps - > body_set_shape_metadata ( p_q . body , shape_idx , p_metadata ) ;
ps - > body_set_shape_as_one_way_collision ( p_q . body , shape_idx , p_shape_data . one_way_collision , p_shape_data . one_way_collision_margin ) ;
} else if ( collision_parent ) {
Transform2D xform = p_xform ;
xform . set_origin ( xform . get_origin ( ) + p_q . pos ) ;
collision_parent - > shape_owner_add_shape ( p_q . shape_owner_id , p_shape ) ;
int real_index = collision_parent - > shape_owner_get_shape_index ( p_q . shape_owner_id , shape_idx ) ;
RID rid = collision_parent - > get_rid ( ) ;
if ( Object : : cast_to < Area2D > ( collision_parent ) ! = NULL ) {
ps - > area_set_shape_transform ( rid , real_index , get_transform ( ) * xform ) ;
} else {
ps - > body_set_shape_transform ( rid , real_index , get_transform ( ) * xform ) ;
ps - > body_set_shape_metadata ( rid , real_index , p_metadata ) ;
ps - > body_set_shape_as_one_way_collision ( rid , real_index , p_shape_data . one_way_collision , p_shape_data . one_way_collision_margin ) ;
}
}
shape_idx + + ;
}
2018-07-22 15:26:14 +02:00
void TileMap : : update_dirty_quadrants ( ) {
2014-02-10 02:10:30 +01:00
if ( ! pending_update )
return ;
2017-01-01 18:31:29 +01:00
if ( ! is_inside_tree ( ) | | ! tile_set . is_valid ( ) ) {
pending_update = false ;
2014-02-10 02:10:30 +01:00
return ;
2017-01-01 18:31:29 +01:00
}
2014-02-10 02:10:30 +01:00
VisualServer * vs = VisualServer : : get_singleton ( ) ;
Physics2DServer * ps = Physics2DServer : : get_singleton ( ) ;
2014-10-03 05:10:51 +02:00
Vector2 tofs = get_cell_draw_offset ( ) ;
2017-01-11 04:52:51 +01:00
Transform2D nav_rel ;
2015-03-09 06:34:56 +01:00
if ( navigation )
2015-12-29 01:05:57 +01:00
nav_rel = get_relative_transform_to_parent ( navigation ) ;
2015-03-09 06:34:56 +01:00
Vector2 qofs ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
SceneTree * st = SceneTree : : get_singleton ( ) ;
2015-09-20 18:03:46 +02:00
Color debug_collision_color ;
2018-03-25 18:22:36 +02:00
Color debug_navigation_color ;
2015-09-20 18:03:46 +02:00
bool debug_shapes = st & & st - > is_debugging_collisions_hint ( ) ;
if ( debug_shapes ) {
2017-03-05 16:44:50 +01:00
debug_collision_color = st - > get_debug_collisions_color ( ) ;
2015-09-20 18:03:46 +02:00
}
2018-03-25 18:22:36 +02:00
bool debug_navigation = st & & st - > is_debugging_navigation_hint ( ) ;
if ( debug_navigation ) {
debug_navigation_color = st - > get_debug_navigation_color ( ) ;
}
2014-02-10 02:10:30 +01:00
while ( dirty_quadrant_list . first ( ) ) {
Quadrant & q = * dirty_quadrant_list . first ( ) - > self ( ) ;
2017-03-05 16:44:50 +01:00
for ( List < RID > : : Element * E = q . canvas_items . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
vs - > free ( E - > get ( ) ) ;
}
q . canvas_items . clear ( ) ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
ps - > body_clear_shapes ( q . body ) ;
} else if ( collision_parent ) {
collision_parent - > shape_owner_clear_shapes ( q . shape_owner_id ) ;
}
2017-03-05 16:44:50 +01:00
int shape_idx = 0 ;
2014-02-10 02:10:30 +01:00
2015-03-09 06:34:56 +01:00
if ( navigation ) {
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant : : NavPoly > : : Element * E = q . navpoly_ids . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
navigation - > navpoly_remove ( E - > get ( ) . id ) ;
}
q . navpoly_ids . clear ( ) ;
}
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant : : Occluder > : : Element * E = q . occluder_instances . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
VS : : get_singleton ( ) - > free ( E - > get ( ) . id ) ;
}
q . occluder_instances . clear ( ) ;
2017-04-07 04:36:37 +02:00
Ref < ShaderMaterial > prev_material ;
2018-10-04 13:04:58 +02:00
int prev_z_index = 0 ;
2015-03-09 06:34:56 +01:00
RID prev_canvas_item ;
2015-12-12 12:11:36 +01:00
RID prev_debug_canvas_item ;
2015-03-09 06:34:56 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < q . cells . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Map < PosKey , Cell > : : Element * E = tile_map . find ( q . cells [ i ] ) ;
Cell & c = E - > get ( ) ;
2014-02-10 02:10:30 +01:00
//moment of truth
if ( ! tile_set - > has_tile ( c . id ) )
continue ;
Ref < Texture > tex = tile_set - > tile_get_texture ( c . id ) ;
2014-02-19 15:57:14 +01:00
Vector2 tile_ofs = tile_set - > tile_get_texture_offset ( c . id ) ;
2014-02-10 02:10:30 +01:00
2015-03-09 06:34:56 +01:00
Vector2 wofs = _map_to_world ( E - > key ( ) . x , E - > key ( ) . y ) ;
Vector2 offset = wofs - q . pos + tofs ;
2014-02-10 02:10:30 +01:00
if ( ! tex . is_valid ( ) )
continue ;
2017-04-07 04:36:37 +02:00
Ref < ShaderMaterial > mat = tile_set - > tile_get_material ( c . id ) ;
2018-02-17 11:58:07 +01:00
int z_index = tile_set - > tile_get_z_index ( c . id ) ;
2015-03-09 06:34:56 +01:00
2018-12-17 13:03:50 +01:00
if ( tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : AUTO_TILE | |
tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : ATLAS_TILE ) {
2018-07-02 15:39:39 +02:00
z_index + = tile_set - > autotile_get_z_index ( c . id , Vector2 ( c . autotile_coord_x , c . autotile_coord_y ) ) ;
}
2015-03-09 06:34:56 +01:00
RID canvas_item ;
2015-12-12 12:11:36 +01:00
RID debug_canvas_item ;
2015-03-09 06:34:56 +01:00
2018-02-17 11:58:07 +01:00
if ( prev_canvas_item = = RID ( ) | | prev_material ! = mat | | prev_z_index ! = z_index ) {
2015-03-09 06:34:56 +01:00
2017-03-05 16:44:50 +01:00
canvas_item = vs - > canvas_item_create ( ) ;
2015-03-09 06:34:56 +01:00
if ( mat . is_valid ( ) )
2017-03-05 16:44:50 +01:00
vs - > canvas_item_set_material ( canvas_item , mat - > get_rid ( ) ) ;
vs - > canvas_item_set_parent ( canvas_item , get_canvas_item ( ) ) ;
2017-08-15 23:33:19 +02:00
_update_item_material_state ( canvas_item ) ;
2017-01-11 04:52:51 +01:00
Transform2D xform ;
2017-03-05 16:44:50 +01:00
xform . set_origin ( q . pos ) ;
vs - > canvas_item_set_transform ( canvas_item , xform ) ;
vs - > canvas_item_set_light_mask ( canvas_item , get_light_mask ( ) ) ;
2018-02-17 11:58:07 +01:00
vs - > canvas_item_set_z_index ( canvas_item , z_index ) ;
2015-12-29 18:47:13 +01:00
2015-03-09 06:34:56 +01:00
q . canvas_items . push_back ( canvas_item ) ;
2015-12-12 12:11:36 +01:00
if ( debug_shapes ) {
2017-03-05 16:44:50 +01:00
debug_canvas_item = vs - > canvas_item_create ( ) ;
vs - > canvas_item_set_parent ( debug_canvas_item , canvas_item ) ;
vs - > canvas_item_set_z_as_relative_to_parent ( debug_canvas_item , false ) ;
2017-12-29 23:06:03 +01:00
vs - > canvas_item_set_z_index ( debug_canvas_item , VS : : CANVAS_ITEM_Z_MAX - 1 ) ;
2015-12-12 12:11:36 +01:00
q . canvas_items . push_back ( debug_canvas_item ) ;
2017-03-05 16:44:50 +01:00
prev_debug_canvas_item = debug_canvas_item ;
2015-12-12 12:11:36 +01:00
}
2017-03-05 16:44:50 +01:00
prev_canvas_item = canvas_item ;
prev_material = mat ;
2018-02-17 11:58:07 +01:00
prev_z_index = z_index ;
2015-03-09 06:34:56 +01:00
} else {
2017-03-05 16:44:50 +01:00
canvas_item = prev_canvas_item ;
2015-12-12 12:11:36 +01:00
if ( debug_shapes ) {
2017-03-05 16:44:50 +01:00
debug_canvas_item = prev_debug_canvas_item ;
2015-12-12 12:11:36 +01:00
}
2015-03-09 06:34:56 +01:00
}
2014-02-10 02:10:30 +01:00
Rect2 r = tile_set - > tile_get_region ( c . id ) ;
2018-07-29 23:54:12 +02:00
if ( tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : AUTO_TILE | | tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : ATLAS_TILE ) {
2017-10-22 03:42:23 +02:00
int spacing = tile_set - > autotile_get_spacing ( c . id ) ;
r . size = tile_set - > autotile_get_size ( c . id ) ;
r . position + = ( r . size + Vector2 ( spacing , spacing ) ) * Vector2 ( c . autotile_coord_x , c . autotile_coord_y ) ;
}
2014-02-10 02:10:30 +01:00
2019-01-14 23:04:47 +01:00
Size2 s ;
2017-03-05 16:44:50 +01:00
if ( r = = Rect2 ( ) )
2014-02-10 02:10:30 +01:00
s = tex - > get_size ( ) ;
2019-01-14 23:04:47 +01:00
else
2014-02-10 02:10:30 +01:00
s = r . size ;
Rect2 rect ;
2017-06-04 00:25:13 +02:00
rect . position = offset . floor ( ) ;
2017-03-05 16:44:50 +01:00
rect . size = s ;
2017-08-25 15:40:29 +02:00
rect . size . x + = fp_adjust ;
rect . size . y + = fp_adjust ;
2014-02-10 02:10:30 +01:00
2019-07-01 22:43:52 +02:00
if ( compatibility_mode & & ! centered_textures ) {
if ( rect . size . y > rect . size . x ) {
if ( ( c . flip_h & & ( c . flip_v | | c . transpose ) ) | | ( c . flip_v & & ! c . transpose ) )
tile_ofs . y + = rect . size . y - rect . size . x ;
} else if ( rect . size . y < rect . size . x ) {
if ( ( c . flip_v & & ( c . flip_h | | c . transpose ) ) | | ( c . flip_h & & ! c . transpose ) )
tile_ofs . x + = rect . size . x - rect . size . y ;
}
}
2019-05-15 04:14:27 +02:00
if ( c . transpose ) {
2016-01-02 18:17:20 +01:00
SWAP ( tile_ofs . x , tile_ofs . y ) ;
2019-07-01 22:43:52 +02:00
if ( centered_textures ) {
rect . position . x + = cell_size . x / 2 - rect . size . y / 2 ;
rect . position . y + = cell_size . y / 2 - rect . size . x / 2 ;
}
} else if ( centered_textures ) {
rect . position + = cell_size / 2 - rect . size / 2 ;
2019-05-15 04:14:27 +02:00
}
2016-01-02 18:17:20 +01:00
if ( c . flip_h ) {
2017-03-05 16:44:50 +01:00
rect . size . x = - rect . size . x ;
tile_ofs . x = - tile_ofs . x ;
2016-01-02 18:17:20 +01:00
}
2019-05-15 04:14:27 +02:00
2016-01-02 18:17:20 +01:00
if ( c . flip_v ) {
2017-03-05 16:44:50 +01:00
rect . size . y = - rect . size . y ;
tile_ofs . y = - tile_ofs . y ;
2016-01-02 18:17:20 +01:00
}
2014-02-10 02:10:30 +01:00
2019-07-01 22:43:52 +02:00
if ( compatibility_mode & & ! centered_textures ) {
if ( tile_origin = = TILE_ORIGIN_TOP_LEFT ) {
rect . position + = tile_ofs ;
} else if ( tile_origin = = TILE_ORIGIN_BOTTOM_LEFT ) {
rect . position + = tile_ofs ;
if ( c . transpose ) {
if ( c . flip_h )
rect . position . x - = cell_size . x ;
else
rect . position . x + = cell_size . x ;
} else {
if ( c . flip_v )
rect . position . y - = cell_size . y ;
else
rect . position . y + = cell_size . y ;
}
} else if ( tile_origin = = TILE_ORIGIN_CENTER ) {
rect . position + = tile_ofs ;
if ( c . flip_h )
rect . position . x - = cell_size . x / 2 ;
else
rect . position . x + = cell_size . x / 2 ;
if ( c . flip_v )
rect . position . y - = cell_size . y / 2 ;
else
rect . position . y + = cell_size . y / 2 ;
}
} else {
rect . position + = tile_ofs ;
}
2015-03-09 06:34:56 +01:00
2017-06-22 17:15:50 +02:00
Ref < Texture > normal_map = tile_set - > tile_get_normal_map ( c . id ) ;
2016-11-30 14:33:39 +01:00
Color modulate = tile_set - > tile_get_modulate ( c . id ) ;
2017-03-05 11:39:00 +01:00
Color self_modulate = get_self_modulate ( ) ;
2017-03-05 16:44:50 +01:00
modulate = Color ( modulate . r * self_modulate . r , modulate . g * self_modulate . g ,
modulate . b * self_modulate . b , modulate . a * self_modulate . a ) ;
if ( r = = Rect2 ( ) ) {
2017-06-22 17:15:50 +02:00
tex - > draw_rect ( canvas_item , rect , false , modulate , c . transpose , normal_map ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-11-10 13:21:33 +01:00
tex - > draw_rect_region ( canvas_item , rect , r , modulate , c . transpose , normal_map , clip_uv ) ;
2014-02-10 02:10:30 +01:00
}
2017-06-25 20:47:30 +02:00
Vector < TileSet : : ShapeData > shapes = tile_set - > tile_get_shapes ( c . id ) ;
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
for ( int j = 0 ; j < shapes . size ( ) ; j + + ) {
Ref < Shape2D > shape = shapes [ j ] . shape ;
2014-02-10 02:10:30 +01:00
if ( shape . is_valid ( ) ) {
2019-02-12 21:10:08 +01:00
if ( tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : SINGLE_TILE | | ( shapes [ j ] . autotile_coord . x = = c . autotile_coord_x & & shapes [ j ] . autotile_coord . y = = c . autotile_coord_y ) ) {
2017-10-22 03:42:23 +02:00
Transform2D xform ;
xform . set_origin ( offset . floor ( ) ) ;
2019-02-12 21:10:08 +01:00
Vector2 shape_ofs = shapes [ j ] . shape_transform . get_origin ( ) ;
2017-10-22 03:42:23 +02:00
2019-05-15 04:14:27 +02:00
_fix_cell_transform ( xform , c , shape_ofs , s ) ;
2017-10-22 03:42:23 +02:00
2019-02-12 21:10:08 +01:00
xform * = shapes [ j ] . shape_transform . untranslated ( ) ;
2018-06-03 15:32:23 +02:00
2017-10-22 03:42:23 +02:00
if ( debug_canvas_item . is_valid ( ) ) {
vs - > canvas_item_add_set_transform ( debug_canvas_item , xform ) ;
shape - > draw ( debug_canvas_item , debug_collision_color ) ;
}
2019-03-04 03:05:43 +01:00
if ( shape - > has_meta ( " decomposed " ) ) {
Array _shapes = shape - > get_meta ( " decomposed " ) ;
for ( int k = 0 ; k < _shapes . size ( ) ; k + + ) {
Ref < ConvexPolygonShape2D > convex = _shapes [ k ] ;
if ( convex . is_valid ( ) ) {
2019-02-06 00:45:40 +01:00
_add_shape ( shape_idx , q , convex , shapes [ j ] , xform , Vector2 ( E - > key ( ) . x , E - > key ( ) . y ) ) ;
2019-03-04 03:05:43 +01:00
# ifdef DEBUG_ENABLED
} else {
2019-05-19 12:34:40 +02:00
print_error ( " The TileSet assigned to the TileMap " + get_name ( ) + " has an invalid convex shape. " ) ;
2019-03-04 03:05:43 +01:00
# endif
}
}
} else {
2019-02-06 00:45:40 +01:00
_add_shape ( shape_idx , q , shape , shapes [ j ] , xform , Vector2 ( E - > key ( ) . x , E - > key ( ) . y ) ) ;
2019-03-04 03:05:43 +01:00
}
2015-09-20 18:03:46 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2015-03-09 06:34:56 +01:00
2016-10-03 21:33:42 +02:00
if ( debug_canvas_item . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
vs - > canvas_item_add_set_transform ( debug_canvas_item , Transform2D ( ) ) ;
2016-02-20 14:01:34 +01:00
}
2015-03-09 06:34:56 +01:00
if ( navigation ) {
2017-10-22 03:42:23 +02:00
Ref < NavigationPolygon > navpoly ;
Vector2 npoly_ofs ;
2018-07-29 23:54:12 +02:00
if ( tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : AUTO_TILE | | tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : ATLAS_TILE ) {
2017-10-22 03:42:23 +02:00
navpoly = tile_set - > autotile_get_navigation_polygon ( c . id , Vector2 ( c . autotile_coord_x , c . autotile_coord_y ) ) ;
npoly_ofs = Vector2 ( ) ;
} else {
navpoly = tile_set - > tile_get_navigation_polygon ( c . id ) ;
npoly_ofs = tile_set - > tile_get_navigation_polygon_offset ( c . id ) ;
}
2015-04-09 06:18:01 +02:00
if ( navpoly . is_valid ( ) ) {
2017-01-11 04:52:51 +01:00
Transform2D xform ;
2017-03-05 16:44:50 +01:00
xform . set_origin ( offset . floor ( ) + q . pos ) ;
2019-05-15 04:14:27 +02:00
_fix_cell_transform ( xform , c , npoly_ofs , s ) ;
2015-03-09 06:34:56 +01:00
2017-12-15 21:09:06 +01:00
int pid = navigation - > navpoly_add ( navpoly , nav_rel * xform ) ;
2015-03-09 06:34:56 +01:00
2015-04-09 06:18:01 +02:00
Quadrant : : NavPoly np ;
2017-03-05 16:44:50 +01:00
np . id = pid ;
np . xform = xform ;
q . navpoly_ids [ E - > key ( ) ] = np ;
2018-03-25 18:22:36 +02:00
if ( debug_navigation ) {
RID debug_navigation_item = vs - > canvas_item_create ( ) ;
vs - > canvas_item_set_parent ( debug_navigation_item , canvas_item ) ;
vs - > canvas_item_set_z_as_relative_to_parent ( debug_navigation_item , false ) ;
vs - > canvas_item_set_z_index ( debug_navigation_item , VS : : CANVAS_ITEM_Z_MAX - 2 ) ; // Display one below collision debug
if ( debug_navigation_item . is_valid ( ) ) {
PoolVector < Vector2 > navigation_polygon_vertices = navpoly - > get_vertices ( ) ;
int vsize = navigation_polygon_vertices . size ( ) ;
if ( vsize > 2 ) {
Vector < Color > colors ;
Vector < Vector2 > vertices ;
vertices . resize ( vsize ) ;
colors . resize ( vsize ) ;
{
PoolVector < Vector2 > : : Read vr = navigation_polygon_vertices . read ( ) ;
2019-02-12 21:10:08 +01:00
for ( int j = 0 ; j < vsize ; j + + ) {
vertices . write [ j ] = vr [ j ] ;
colors . write [ j ] = debug_navigation_color ;
2018-03-25 18:22:36 +02:00
}
}
Vector < int > indices ;
2019-02-12 21:10:08 +01:00
for ( int j = 0 ; j < navpoly - > get_polygon_count ( ) ; j + + ) {
Vector < int > polygon = navpoly - > get_polygon ( j ) ;
2018-03-25 18:22:36 +02:00
2019-02-12 21:10:08 +01:00
for ( int k = 2 ; k < polygon . size ( ) ; k + + ) {
2018-03-25 18:22:36 +02:00
2019-02-12 21:10:08 +01:00
int kofs [ 3 ] = { 0 , k - 1 , k } ;
for ( int l = 0 ; l < 3 ; l + + ) {
2018-03-25 18:22:36 +02:00
2019-02-12 21:10:08 +01:00
int idx = polygon [ kofs [ l ] ] ;
2018-03-25 18:22:36 +02:00
ERR_FAIL_INDEX ( idx , vsize ) ;
indices . push_back ( idx ) ;
}
}
}
Transform2D navxform ;
navxform . set_origin ( offset . floor ( ) ) ;
2019-05-15 04:14:27 +02:00
_fix_cell_transform ( navxform , c , npoly_ofs , s ) ;
2018-03-25 18:22:36 +02:00
vs - > canvas_item_set_transform ( debug_navigation_item , navxform ) ;
vs - > canvas_item_add_triangle_array ( debug_navigation_item , indices , vertices , colors ) ;
}
}
}
2015-04-09 06:18:01 +02:00
}
2015-03-09 06:34:56 +01:00
}
2017-10-22 03:42:23 +02:00
Ref < OccluderPolygon2D > occluder ;
2018-07-29 23:54:12 +02:00
if ( tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : AUTO_TILE | | tile_set - > tile_get_tile_mode ( c . id ) = = TileSet : : ATLAS_TILE ) {
2017-10-22 03:42:23 +02:00
occluder = tile_set - > autotile_get_light_occluder ( c . id , Vector2 ( c . autotile_coord_x , c . autotile_coord_y ) ) ;
} else {
occluder = tile_set - > tile_get_light_occluder ( c . id ) ;
}
2015-03-09 06:34:56 +01:00
if ( occluder . is_valid ( ) ) {
2017-12-08 20:14:06 +01:00
Vector2 occluder_ofs = tile_set - > tile_get_occluder_offset ( c . id ) ;
2017-01-11 04:52:51 +01:00
Transform2D xform ;
2017-03-05 16:44:50 +01:00
xform . set_origin ( offset . floor ( ) + q . pos ) ;
2019-05-15 04:14:27 +02:00
_fix_cell_transform ( xform , c , occluder_ofs , s ) ;
2015-03-09 06:34:56 +01:00
RID orid = VS : : get_singleton ( ) - > canvas_light_occluder_create ( ) ;
2017-03-05 16:44:50 +01:00
VS : : get_singleton ( ) - > canvas_light_occluder_set_transform ( orid , get_global_transform ( ) * xform ) ;
VS : : get_singleton ( ) - > canvas_light_occluder_set_polygon ( orid , occluder - > get_rid ( ) ) ;
VS : : get_singleton ( ) - > canvas_light_occluder_attach_to_canvas ( orid , get_canvas ( ) ) ;
VS : : get_singleton ( ) - > canvas_light_occluder_set_light_mask ( orid , occluder_light_mask ) ;
2015-03-09 06:34:56 +01:00
Quadrant : : Occluder oc ;
2017-03-05 16:44:50 +01:00
oc . xform = xform ;
oc . id = orid ;
q . occluder_instances [ E - > key ( ) ] = oc ;
2015-03-09 06:34:56 +01:00
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
dirty_quadrant_list . remove ( dirty_quadrant_list . first ( ) ) ;
quadrant_order_dirty = true ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
pending_update = false ;
2014-02-10 02:10:30 +01:00
2014-09-19 23:39:50 +02:00
if ( quadrant_order_dirty ) {
2018-10-04 15:38:52 +02:00
int index = - ( int64_t ) 0x80000000 ; //always must be drawn below children
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-09-19 23:39:50 +02:00
2017-03-05 16:44:50 +01:00
Quadrant & q = E - > get ( ) ;
2019-02-12 21:10:08 +01:00
for ( List < RID > : : Element * F = q . canvas_items . front ( ) ; F ; F = F - > next ( ) ) {
2014-09-19 23:39:50 +02:00
2019-02-12 21:10:08 +01:00
VS : : get_singleton ( ) - > canvas_item_set_draw_index ( F - > get ( ) , index + + ) ;
2015-03-09 06:34:56 +01:00
}
2014-09-19 23:39:50 +02:00
}
2017-03-05 16:44:50 +01:00
quadrant_order_dirty = false ;
2014-09-19 23:39:50 +02:00
}
2014-02-10 02:10:30 +01:00
_recompute_rect_cache ( ) ;
}
void TileMap : : _recompute_rect_cache ( ) {
# ifdef DEBUG_ENABLED
if ( ! rect_cache_dirty )
return ;
Rect2 r_total ;
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2014-10-03 05:10:51 +02:00
Rect2 r ;
2017-06-04 00:25:13 +02:00
r . position = _map_to_world ( E - > key ( ) . x * _get_quadrant_size ( ) , E - > key ( ) . y * _get_quadrant_size ( ) ) ;
2017-03-05 16:44:50 +01:00
r . expand_to ( _map_to_world ( E - > key ( ) . x * _get_quadrant_size ( ) + _get_quadrant_size ( ) , E - > key ( ) . y * _get_quadrant_size ( ) ) ) ;
r . expand_to ( _map_to_world ( E - > key ( ) . x * _get_quadrant_size ( ) + _get_quadrant_size ( ) , E - > key ( ) . y * _get_quadrant_size ( ) + _get_quadrant_size ( ) ) ) ;
r . expand_to ( _map_to_world ( E - > key ( ) . x * _get_quadrant_size ( ) , E - > key ( ) . y * _get_quadrant_size ( ) + _get_quadrant_size ( ) ) ) ;
if ( E = = quadrant_map . front ( ) )
r_total = r ;
2014-02-10 02:10:30 +01:00
else
2017-03-05 16:44:50 +01:00
r_total = r_total . merge ( r ) ;
2014-02-10 02:10:30 +01:00
}
2014-10-03 13:58:41 +02:00
2018-07-29 23:09:59 +02:00
rect_cache = r_total ;
2014-02-10 02:10:30 +01:00
item_rect_changed ( ) ;
2017-03-05 16:44:50 +01:00
rect_cache_dirty = false ;
2014-02-10 02:10:30 +01:00
# endif
}
2017-03-05 16:44:50 +01:00
Map < TileMap : : PosKey , TileMap : : Quadrant > : : Element * TileMap : : _create_quadrant ( const PosKey & p_qk ) {
2014-02-10 02:10:30 +01:00
2017-01-11 04:52:51 +01:00
Transform2D xform ;
2014-10-03 05:10:51 +02:00
//xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size);
2014-02-10 02:10:30 +01:00
Quadrant q ;
2017-03-05 16:44:50 +01:00
q . pos = _map_to_world ( p_qk . x * _get_quadrant_size ( ) , p_qk . y * _get_quadrant_size ( ) ) ;
q . pos + = get_cell_draw_offset ( ) ;
if ( tile_origin = = TILE_ORIGIN_CENTER )
q . pos + = cell_size / 2 ;
else if ( tile_origin = = TILE_ORIGIN_BOTTOM_LEFT )
q . pos . y + = cell_size . y ;
xform . set_origin ( q . pos ) ;
2017-01-14 12:26:56 +01:00
//q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
q . body = Physics2DServer : : get_singleton ( ) - > body_create ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_mode ( q . body , use_kinematic ? Physics2DServer : : BODY_MODE_KINEMATIC : Physics2DServer : : BODY_MODE_STATIC ) ;
Physics2DServer : : get_singleton ( ) - > body_attach_object_instance_id ( q . body , get_instance_id ( ) ) ;
Physics2DServer : : get_singleton ( ) - > body_set_collision_layer ( q . body , collision_layer ) ;
Physics2DServer : : get_singleton ( ) - > body_set_collision_mask ( q . body , collision_mask ) ;
Physics2DServer : : get_singleton ( ) - > body_set_param ( q . body , Physics2DServer : : BODY_PARAM_FRICTION , friction ) ;
Physics2DServer : : get_singleton ( ) - > body_set_param ( q . body , Physics2DServer : : BODY_PARAM_BOUNCE , bounce ) ;
2014-02-10 02:10:30 +01:00
2019-02-06 00:45:40 +01:00
if ( is_inside_tree ( ) ) {
xform = get_global_transform ( ) * xform ;
RID space = get_world_2d ( ) - > get_space ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_space ( q . body , space ) ;
}
Physics2DServer : : get_singleton ( ) - > body_set_state ( q . body , Physics2DServer : : BODY_STATE_TRANSFORM , xform ) ;
} else if ( collision_parent ) {
xform = get_transform ( ) * xform ;
q . shape_owner_id = collision_parent - > create_shape_owner ( this ) ;
} else {
q . shape_owner_id = - 1 ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
rect_cache_dirty = true ;
quadrant_order_dirty = true ;
return quadrant_map . insert ( p_qk , q ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void TileMap : : _erase_quadrant ( Map < PosKey , Quadrant > : : Element * Q ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Quadrant & q = Q - > get ( ) ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
Physics2DServer : : get_singleton ( ) - > free ( q . body ) ;
} else if ( collision_parent ) {
collision_parent - > remove_shape_owner ( q . shape_owner_id ) ;
}
2017-03-05 16:44:50 +01:00
for ( List < RID > : : Element * E = q . canvas_items . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
VisualServer : : get_singleton ( ) - > free ( E - > get ( ) ) ;
}
q . canvas_items . clear ( ) ;
2014-02-10 02:10:30 +01:00
if ( q . dirty_list . in_list ( ) )
dirty_quadrant_list . remove ( & q . dirty_list ) ;
2015-03-09 06:34:56 +01:00
if ( navigation ) {
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant : : NavPoly > : : Element * E = q . navpoly_ids . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
navigation - > navpoly_remove ( E - > get ( ) . id ) ;
}
q . navpoly_ids . clear ( ) ;
}
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant : : Occluder > : : Element * E = q . occluder_instances . front ( ) ; E ; E = E - > next ( ) ) {
2015-03-09 06:34:56 +01:00
VS : : get_singleton ( ) - > free ( E - > get ( ) . id ) ;
}
q . occluder_instances . clear ( ) ;
2014-02-10 02:10:30 +01:00
quadrant_map . erase ( Q ) ;
2017-03-05 16:44:50 +01:00
rect_cache_dirty = true ;
2014-02-10 02:10:30 +01:00
}
2018-06-26 03:24:12 +02:00
void TileMap : : _make_quadrant_dirty ( Map < PosKey , Quadrant > : : Element * Q , bool update ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Quadrant & q = Q - > get ( ) ;
2014-02-10 02:10:30 +01:00
if ( ! q . dirty_list . in_list ( ) )
dirty_quadrant_list . add ( & q . dirty_list ) ;
if ( pending_update )
return ;
2017-03-05 16:44:50 +01:00
pending_update = true ;
2014-11-06 01:20:42 +01:00
if ( ! is_inside_tree ( ) )
2014-02-10 02:10:30 +01:00
return ;
2018-06-26 03:24:12 +02:00
if ( update ) {
2018-07-22 15:26:14 +02:00
call_deferred ( " update_dirty_quadrants " ) ;
2018-06-26 03:24:12 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void TileMap : : set_cellv ( const Vector2 & p_pos , int p_tile , bool p_flip_x , bool p_flip_y , bool p_transpose ) {
2015-08-02 17:29:37 +02:00
2017-03-05 16:44:50 +01:00
set_cell ( p_pos . x , p_pos . y , p_tile , p_flip_x , p_flip_y , p_transpose ) ;
2015-08-02 17:29:37 +02:00
}
2014-02-10 02:10:30 +01:00
2018-08-29 14:00:00 +02:00
void TileMap : : _set_celld ( const Vector2 & p_pos , const Dictionary & p_data ) {
2018-05-25 18:59:05 +02:00
2019-04-08 23:38:31 +02:00
Variant v_pos_x = p_pos . x , v_pos_y = p_pos . y , v_tile = p_data [ " id " ] , v_flip_h = p_data [ " flip_h " ] , v_flip_v = p_data [ " flip_y " ] , v_transpose = p_data [ " transpose " ] , v_autotile_coord = p_data [ " auto_coord " ] ;
const Variant * args [ 7 ] = { & v_pos_x , & v_pos_y , & v_tile , & v_flip_h , & v_flip_v , & v_transpose , & v_autotile_coord } ;
Variant : : CallError ce ;
call ( " set_cell " , args , 7 , ce ) ;
2018-05-25 18:59:05 +02:00
}
2017-10-22 03:42:23 +02:00
void TileMap : : set_cell ( int p_x , int p_y , int p_tile , bool p_flip_x , bool p_flip_y , bool p_transpose , Vector2 p_autotile_coord ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
PosKey pk ( p_x , p_y ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
if ( ! E & & p_tile = = INVALID_CELL )
2014-02-10 02:10:30 +01:00
return ; //nothing to do
2017-03-05 16:44:50 +01:00
PosKey qk ( p_x / _get_quadrant_size ( ) , p_y / _get_quadrant_size ( ) ) ;
if ( p_tile = = INVALID_CELL ) {
2014-02-10 02:10:30 +01:00
//erase existing
tile_map . erase ( pk ) ;
2017-03-05 16:44:50 +01:00
Map < PosKey , Quadrant > : : Element * Q = quadrant_map . find ( qk ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! Q ) ;
2017-03-05 16:44:50 +01:00
Quadrant & q = Q - > get ( ) ;
2014-02-10 02:10:30 +01:00
q . cells . erase ( pk ) ;
2017-03-05 16:44:50 +01:00
if ( q . cells . size ( ) = = 0 )
2014-02-10 02:10:30 +01:00
_erase_quadrant ( Q ) ;
else
_make_quadrant_dirty ( Q ) ;
2019-03-15 04:58:30 +01:00
used_size_cache_dirty = true ;
2014-02-10 02:10:30 +01:00
return ;
}
2017-03-05 16:44:50 +01:00
Map < PosKey , Quadrant > : : Element * Q = quadrant_map . find ( qk ) ;
2014-02-10 02:10:30 +01:00
if ( ! E ) {
2017-03-05 16:44:50 +01:00
E = tile_map . insert ( pk , Cell ( ) ) ;
2014-09-19 23:39:50 +02:00
if ( ! Q ) {
2017-03-05 16:44:50 +01:00
Q = _create_quadrant ( qk ) ;
2014-09-19 23:39:50 +02:00
}
2017-03-05 16:44:50 +01:00
Quadrant & q = Q - > get ( ) ;
2014-02-10 02:10:30 +01:00
q . cells . insert ( pk ) ;
} else {
ERR_FAIL_COND ( ! Q ) ; // quadrant should exist...
2017-12-01 01:50:09 +01:00
if ( E - > get ( ) . id = = p_tile & & E - > get ( ) . flip_h = = p_flip_x & & E - > get ( ) . flip_v = = p_flip_y & & E - > get ( ) . transpose = = p_transpose & & E - > get ( ) . autotile_coord_x = = ( uint16_t ) p_autotile_coord . x & & E - > get ( ) . autotile_coord_y = = ( uint16_t ) p_autotile_coord . y )
2014-02-10 02:10:30 +01:00
return ; //nothing changed
}
Cell & c = E - > get ( ) ;
2017-03-05 16:44:50 +01:00
c . id = p_tile ;
c . flip_h = p_flip_x ;
c . flip_v = p_flip_y ;
c . transpose = p_transpose ;
2017-10-22 03:42:23 +02:00
c . autotile_coord_x = ( uint16_t ) p_autotile_coord . x ;
c . autotile_coord_y = ( uint16_t ) p_autotile_coord . y ;
2014-02-10 02:10:30 +01:00
_make_quadrant_dirty ( Q ) ;
2017-03-05 16:44:50 +01:00
used_size_cache_dirty = true ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int TileMap : : get_cellv ( const Vector2 & p_pos ) const {
2017-10-22 03:42:23 +02:00
2017-03-05 16:44:50 +01:00
return get_cell ( p_pos . x , p_pos . y ) ;
2016-02-06 13:27:26 +01:00
}
2017-10-22 03:42:23 +02:00
void TileMap : : make_bitmask_area_dirty ( const Vector2 & p_pos ) {
for ( int x = p_pos . x - 1 ; x < = p_pos . x + 1 ; x + + ) {
2017-12-01 01:50:09 +01:00
for ( int y = p_pos . y - 1 ; y < = p_pos . y + 1 ; y + + ) {
2017-10-22 03:42:23 +02:00
PosKey p ( x , y ) ;
if ( dirty_bitmask . find ( p ) = = NULL ) {
dirty_bitmask . push_back ( p ) ;
}
}
}
}
void TileMap : : update_bitmask_area ( const Vector2 & p_pos ) {
for ( int x = p_pos . x - 1 ; x < = p_pos . x + 1 ; x + + ) {
for ( int y = p_pos . y - 1 ; y < = p_pos . y + 1 ; y + + ) {
update_cell_bitmask ( x , y ) ;
}
}
}
2017-12-06 01:14:33 +01:00
void TileMap : : update_bitmask_region ( const Vector2 & p_start , const Vector2 & p_end ) {
if ( ( p_end . x < p_start . x | | p_end . y < p_start . y ) | | ( p_end . x = = p_start . x & & p_end . y = = p_start . y ) ) {
int i ;
Array a = get_used_cells ( ) ;
for ( i = 0 ; i < a . size ( ) ; i + + ) {
// update_bitmask_area() in order to update cells adjacent to the
// current cell, since ordering in array may not be reliable
Vector2 vector = ( Vector2 ) a [ i ] ;
update_bitmask_area ( Vector2 ( vector . x , vector . y ) ) ;
}
return ;
}
for ( int x = p_start . x - 1 ; x < = p_end . x + 1 ; x + + ) {
for ( int y = p_start . y - 1 ; y < = p_end . y + 1 ; y + + ) {
update_cell_bitmask ( x , y ) ;
}
}
}
2017-10-22 03:42:23 +02:00
void TileMap : : update_cell_bitmask ( int p_x , int p_y ) {
PosKey p ( p_x , p_y ) ;
Map < PosKey , Cell > : : Element * E = tile_map . find ( p ) ;
if ( E ! = NULL ) {
int id = get_cell ( p_x , p_y ) ;
2018-12-20 18:17:52 +01:00
if ( tile_set - > tile_get_tile_mode ( id ) = = TileSet : : AUTO_TILE ) {
2017-10-22 03:42:23 +02:00
uint16_t mask = 0 ;
if ( tile_set - > autotile_get_bitmask_mode ( id ) = = TileSet : : BITMASK_2X2 ) {
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y ) ) ) {
mask | = TileSet : : BIND_TOPLEFT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y ) ) ) {
mask | = TileSet : : BIND_TOPRIGHT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y ) ) ) {
mask | = TileSet : : BIND_BOTTOMLEFT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y ) ) ) {
mask | = TileSet : : BIND_BOTTOMRIGHT ;
}
2018-05-17 05:39:43 +02:00
} else {
if ( tile_set - > autotile_get_bitmask_mode ( id ) = = TileSet : : BITMASK_3X3_MINIMAL ) {
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y ) ) ) {
mask | = TileSet : : BIND_TOPLEFT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y - 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y ) ) ) {
mask | = TileSet : : BIND_TOPRIGHT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y ) ) ) {
mask | = TileSet : : BIND_BOTTOMLEFT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y + 1 ) ) & & tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y ) ) ) {
mask | = TileSet : : BIND_BOTTOMRIGHT ;
}
} else {
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y - 1 ) ) ) {
mask | = TileSet : : BIND_TOPLEFT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y - 1 ) ) ) {
mask | = TileSet : : BIND_TOPRIGHT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y + 1 ) ) ) {
mask | = TileSet : : BIND_BOTTOMLEFT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y + 1 ) ) ) {
mask | = TileSet : : BIND_BOTTOMRIGHT ;
}
2017-10-22 03:42:23 +02:00
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y - 1 ) ) ) {
mask | = TileSet : : BIND_TOP ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x - 1 , p_y ) ) ) {
mask | = TileSet : : BIND_LEFT ;
}
mask | = TileSet : : BIND_CENTER ;
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x + 1 , p_y ) ) ) {
mask | = TileSet : : BIND_RIGHT ;
}
if ( tile_set - > is_tile_bound ( id , get_cell ( p_x , p_y + 1 ) ) ) {
mask | = TileSet : : BIND_BOTTOM ;
}
}
Vector2 coord = tile_set - > autotile_get_subtile_for_bitmask ( id , mask , this , Vector2 ( p_x , p_y ) ) ;
E - > get ( ) . autotile_coord_x = ( int ) coord . x ;
E - > get ( ) . autotile_coord_y = ( int ) coord . y ;
2017-12-01 01:50:09 +01:00
PosKey qk ( p_x / _get_quadrant_size ( ) , p_y / _get_quadrant_size ( ) ) ;
Map < PosKey , Quadrant > : : Element * Q = quadrant_map . find ( qk ) ;
_make_quadrant_dirty ( Q ) ;
2018-12-20 18:17:52 +01:00
} else if ( tile_set - > tile_get_tile_mode ( id ) = = TileSet : : SINGLE_TILE ) {
2018-12-23 14:06:53 +01:00
2017-10-22 03:42:23 +02:00
E - > get ( ) . autotile_coord_x = 0 ;
E - > get ( ) . autotile_coord_y = 0 ;
2018-12-23 14:06:53 +01:00
} else if ( tile_set - > tile_get_tile_mode ( id ) = = TileSet : : ATLAS_TILE ) {
if ( tile_set - > autotile_get_bitmask ( id , Vector2 ( p_x , p_y ) ) = = TileSet : : BIND_CENTER ) {
Vector2 coord = tile_set - > atlastile_get_subtile_by_priority ( id , this , Vector2 ( p_x , p_y ) ) ;
E - > get ( ) . autotile_coord_x = ( int ) coord . x ;
E - > get ( ) . autotile_coord_y = ( int ) coord . y ;
}
2017-10-22 03:42:23 +02:00
}
}
}
void TileMap : : update_dirty_bitmask ( ) {
while ( dirty_bitmask . size ( ) > 0 ) {
update_cell_bitmask ( dirty_bitmask [ 0 ] . x , dirty_bitmask [ 0 ] . y ) ;
dirty_bitmask . pop_front ( ) ;
}
}
2018-02-24 06:56:48 +01:00
void TileMap : : fix_invalid_tiles ( ) {
for ( Map < PosKey , Cell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! tile_set - > has_tile ( get_cell ( E - > key ( ) . x , E - > key ( ) . y ) ) ) {
set_cell ( E - > key ( ) . x , E - > key ( ) . y , INVALID_CELL ) ;
}
}
}
2017-03-05 16:44:50 +01:00
int TileMap : : get_cell ( int p_x , int p_y ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
PosKey pk ( p_x , p_y ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
2014-02-10 02:10:30 +01:00
if ( ! E )
return INVALID_CELL ;
return E - > get ( ) . id ;
}
2017-03-05 16:44:50 +01:00
bool TileMap : : is_cell_x_flipped ( int p_x , int p_y ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
PosKey pk ( p_x , p_y ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
2014-02-10 02:10:30 +01:00
if ( ! E )
return false ;
return E - > get ( ) . flip_h ;
}
2017-03-05 16:44:50 +01:00
bool TileMap : : is_cell_y_flipped ( int p_x , int p_y ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
PosKey pk ( p_x , p_y ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
2014-02-10 02:10:30 +01:00
if ( ! E )
return false ;
return E - > get ( ) . flip_v ;
}
2017-03-05 16:44:50 +01:00
bool TileMap : : is_cell_transposed ( int p_x , int p_y ) const {
2015-01-19 14:07:25 +01:00
2017-03-05 16:44:50 +01:00
PosKey pk ( p_x , p_y ) ;
2015-01-19 14:07:25 +01:00
2017-03-05 16:44:50 +01:00
const Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
2015-01-19 14:07:25 +01:00
if ( ! E )
return false ;
return E - > get ( ) . transpose ;
}
2014-02-10 02:10:30 +01:00
2017-12-01 01:50:09 +01:00
void TileMap : : set_cell_autotile_coord ( int p_x , int p_y , const Vector2 & p_coord ) {
2017-10-22 03:42:23 +02:00
PosKey pk ( p_x , p_y ) ;
const Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
if ( ! E )
2017-12-01 01:50:09 +01:00
return ;
2017-10-22 03:42:23 +02:00
2017-12-01 01:50:09 +01:00
Cell c = E - > get ( ) ;
c . autotile_coord_x = p_coord . x ;
c . autotile_coord_y = p_coord . y ;
tile_map [ pk ] = c ;
2018-06-01 23:12:25 +02:00
PosKey qk ( p_x / _get_quadrant_size ( ) , p_y / _get_quadrant_size ( ) ) ;
Map < PosKey , Quadrant > : : Element * Q = quadrant_map . find ( qk ) ;
if ( ! Q )
return ;
_make_quadrant_dirty ( Q ) ;
2017-10-22 03:42:23 +02:00
}
2017-12-01 01:50:09 +01:00
Vector2 TileMap : : get_cell_autotile_coord ( int p_x , int p_y ) const {
2017-10-22 03:42:23 +02:00
PosKey pk ( p_x , p_y ) ;
const Map < PosKey , Cell > : : Element * E = tile_map . find ( pk ) ;
if ( ! E )
2017-12-01 01:50:09 +01:00
return Vector2 ( ) ;
2017-10-22 03:42:23 +02:00
2017-12-01 01:50:09 +01:00
return Vector2 ( E - > get ( ) . autotile_coord_x , E - > get ( ) . autotile_coord_y ) ;
2017-10-22 03:42:23 +02:00
}
2014-02-10 02:10:30 +01:00
void TileMap : : _recreate_quadrants ( ) {
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Cell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
PosKey qk ( E - > key ( ) . x / _get_quadrant_size ( ) , E - > key ( ) . y / _get_quadrant_size ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Map < PosKey , Quadrant > : : Element * Q = quadrant_map . find ( qk ) ;
2014-02-10 02:10:30 +01:00
if ( ! Q ) {
2017-03-05 16:44:50 +01:00
Q = _create_quadrant ( qk ) ;
2014-02-10 02:10:30 +01:00
dirty_quadrant_list . add ( & Q - > get ( ) . dirty_list ) ;
}
Q - > get ( ) . cells . insert ( E - > key ( ) ) ;
2018-06-26 03:24:12 +02:00
_make_quadrant_dirty ( Q , false ) ;
2014-02-10 02:10:30 +01:00
}
2018-07-22 15:26:14 +02:00
update_dirty_quadrants ( ) ;
2014-02-10 02:10:30 +01:00
}
void TileMap : : _clear_quadrants ( ) {
while ( quadrant_map . size ( ) ) {
2017-03-05 16:44:50 +01:00
_erase_quadrant ( quadrant_map . front ( ) ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-08-15 23:33:19 +02:00
void TileMap : : set_material ( const Ref < Material > & p_material ) {
CanvasItem : : set_material ( p_material ) ;
_update_all_items_material_state ( ) ;
}
void TileMap : : set_use_parent_material ( bool p_use_parent_material ) {
CanvasItem : : set_use_parent_material ( p_use_parent_material ) ;
_update_all_items_material_state ( ) ;
}
void TileMap : : _update_all_items_material_state ( ) {
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
Quadrant & q = E - > get ( ) ;
2019-02-12 21:10:08 +01:00
for ( List < RID > : : Element * F = q . canvas_items . front ( ) ; F ; F = F - > next ( ) ) {
2017-08-15 23:33:19 +02:00
2019-02-12 21:10:08 +01:00
_update_item_material_state ( F - > get ( ) ) ;
2017-08-15 23:33:19 +02:00
}
}
}
void TileMap : : _update_item_material_state ( const RID & p_canvas_item ) {
VS : : get_singleton ( ) - > canvas_item_set_use_parent_material ( p_canvas_item , get_use_parent_material ( ) | | get_material ( ) . is_valid ( ) ) ;
}
2014-02-10 02:10:30 +01:00
void TileMap : : clear ( ) {
_clear_quadrants ( ) ;
tile_map . clear ( ) ;
2017-03-05 16:44:50 +01:00
used_size_cache_dirty = true ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void TileMap : : _set_tile_data ( const PoolVector < int > & p_data ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int c = p_data . size ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < int > : : Read r = p_data . read ( ) ;
2014-02-10 02:10:30 +01:00
2017-12-09 17:44:26 +01:00
int offset = ( format = = FORMAT_2 ) ? 3 : 2 ;
2017-10-22 03:42:23 +02:00
2017-12-01 01:50:09 +01:00
clear ( ) ;
2017-10-22 03:42:23 +02:00
for ( int i = 0 ; i < c ; i + = offset ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const uint8_t * ptr = ( const uint8_t * ) & r [ i ] ;
2017-10-22 03:42:23 +02:00
uint8_t local [ 12 ] ;
2017-12-09 17:44:26 +01:00
for ( int j = 0 ; j < ( ( format = = FORMAT_2 ) ? 12 : 8 ) ; j + + )
2017-03-05 16:44:50 +01:00
local [ j ] = ptr [ j ] ;
2014-02-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
2017-03-05 16:44:50 +01:00
SWAP ( local [ 0 ] , local [ 3 ] ) ;
SWAP ( local [ 1 ] , local [ 2 ] ) ;
SWAP ( local [ 4 ] , local [ 7 ] ) ;
SWAP ( local [ 5 ] , local [ 6 ] ) ;
2017-10-22 03:42:23 +02:00
//TODO: ask someone to check this...
2017-12-09 17:44:26 +01:00
if ( FORMAT = = FORMAT_2 ) {
2017-10-22 03:42:23 +02:00
SWAP ( local [ 8 ] , local [ 11 ] ) ;
SWAP ( local [ 9 ] , local [ 10 ] ) ;
}
2014-02-10 02:10:30 +01:00
# endif
2014-04-19 21:46:52 +02:00
int16_t x = decode_uint16 ( & local [ 0 ] ) ;
int16_t y = decode_uint16 ( & local [ 2 ] ) ;
2014-02-10 02:10:30 +01:00
uint32_t v = decode_uint32 ( & local [ 4 ] ) ;
2017-03-05 16:44:50 +01:00
bool flip_h = v & ( 1 < < 29 ) ;
bool flip_v = v & ( 1 < < 30 ) ;
bool transpose = v & ( 1 < < 31 ) ;
v & = ( 1 < < 29 ) - 1 ;
2018-01-11 23:35:12 +01:00
int16_t coord_x = 0 ;
int16_t coord_y = 0 ;
2017-12-09 17:44:26 +01:00
if ( format = = FORMAT_2 ) {
2017-10-22 03:42:23 +02:00
coord_x = decode_uint16 ( & local [ 8 ] ) ;
coord_y = decode_uint16 ( & local [ 10 ] ) ;
}
2019-07-01 22:43:52 +02:00
2017-10-22 03:42:23 +02:00
set_cell ( x , y , v , flip_h , flip_v , transpose , Vector2 ( coord_x , coord_y ) ) ;
2014-02-10 02:10:30 +01:00
}
2018-11-10 02:40:08 +01:00
format = FORMAT_2 ;
2014-02-10 02:10:30 +01:00
}
2017-01-07 22:25:37 +01:00
PoolVector < int > TileMap : : _get_tile_data ( ) const {
2014-02-10 02:10:30 +01:00
2017-01-07 22:25:37 +01:00
PoolVector < int > data ;
2017-10-22 03:42:23 +02:00
data . resize ( tile_map . size ( ) * 3 ) ;
2017-01-07 22:25:37 +01:00
PoolVector < int > : : Write w = data . write ( ) ;
2014-02-10 02:10:30 +01:00
2017-12-09 17:44:26 +01:00
format = FORMAT_2 ;
2017-03-05 16:44:50 +01:00
int idx = 0 ;
for ( const Map < PosKey , Cell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
uint8_t * ptr = ( uint8_t * ) & w [ idx ] ;
encode_uint16 ( E - > key ( ) . x , & ptr [ 0 ] ) ;
encode_uint16 ( E - > key ( ) . y , & ptr [ 2 ] ) ;
2014-02-10 02:10:30 +01:00
uint32_t val = E - > get ( ) . id ;
if ( E - > get ( ) . flip_h )
2017-03-05 16:44:50 +01:00
val | = ( 1 < < 29 ) ;
2014-02-10 02:10:30 +01:00
if ( E - > get ( ) . flip_v )
2017-03-05 16:44:50 +01:00
val | = ( 1 < < 30 ) ;
2015-01-19 14:07:25 +01:00
if ( E - > get ( ) . transpose )
2017-03-05 16:44:50 +01:00
val | = ( 1 < < 31 ) ;
encode_uint32 ( val , & ptr [ 4 ] ) ;
2017-10-22 03:42:23 +02:00
encode_uint16 ( E - > get ( ) . autotile_coord_x , & ptr [ 8 ] ) ;
encode_uint16 ( E - > get ( ) . autotile_coord_y , & ptr [ 10 ] ) ;
idx + = 3 ;
2014-02-10 02:10:30 +01:00
}
2017-01-07 22:25:37 +01:00
w = PoolVector < int > : : Write ( ) ;
2014-02-10 02:10:30 +01:00
return data ;
}
2018-07-29 23:09:59 +02:00
Rect2 TileMap : : _edit_get_rect ( ) const {
const_cast < TileMap * > ( this ) - > update_dirty_quadrants ( ) ;
return rect_cache ;
}
2015-05-03 21:47:21 +02:00
void TileMap : : set_collision_layer ( uint32_t p_layer ) {
2014-05-14 06:22:15 +02:00
2017-03-05 16:44:50 +01:00
collision_layer = p_layer ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-05-14 06:22:15 +02:00
2019-02-06 00:45:40 +01:00
Quadrant & q = E - > get ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_collision_layer ( q . body , collision_layer ) ;
}
2014-05-14 06:22:15 +02:00
}
}
2015-05-03 21:47:21 +02:00
void TileMap : : set_collision_mask ( uint32_t p_mask ) {
2017-03-05 16:44:50 +01:00
collision_mask = p_mask ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2015-05-03 21:47:21 +02:00
2019-02-06 00:45:40 +01:00
Quadrant & q = E - > get ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_collision_mask ( q . body , collision_mask ) ;
}
2015-05-03 21:47:21 +02:00
}
}
2017-04-05 20:51:31 +02:00
void TileMap : : set_collision_layer_bit ( int p_bit , bool p_value ) {
uint32_t layer = get_collision_layer ( ) ;
if ( p_value )
layer | = 1 < < p_bit ;
else
layer & = ~ ( 1 < < p_bit ) ;
set_collision_layer ( layer ) ;
}
void TileMap : : set_collision_mask_bit ( int p_bit , bool p_value ) {
uint32_t mask = get_collision_mask ( ) ;
if ( p_value )
mask | = 1 < < p_bit ;
else
mask & = ~ ( 1 < < p_bit ) ;
set_collision_mask ( mask ) ;
}
2017-03-05 16:44:50 +01:00
bool TileMap : : get_collision_use_kinematic ( ) const {
2015-02-13 11:49:21 +01:00
2015-02-13 21:43:50 +01:00
return use_kinematic ;
2015-02-13 11:49:21 +01:00
}
2015-02-13 21:43:50 +01:00
void TileMap : : set_collision_use_kinematic ( bool p_use_kinematic ) {
2015-02-13 11:49:21 +01:00
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
use_kinematic = p_use_kinematic ;
2015-02-13 11:49:21 +01:00
_recreate_quadrants ( ) ;
}
2019-02-06 00:45:40 +01:00
bool TileMap : : get_collision_use_parent ( ) const {
return use_parent ;
}
void TileMap : : set_collision_use_parent ( bool p_use_parent ) {
if ( use_parent = = p_use_parent ) return ;
_clear_quadrants ( ) ;
use_parent = p_use_parent ;
set_notify_local_transform ( use_parent ) ;
if ( use_parent & & is_inside_tree ( ) ) {
collision_parent = Object : : cast_to < CollisionObject2D > ( get_parent ( ) ) ;
} else {
collision_parent = NULL ;
}
_recreate_quadrants ( ) ;
_change_notify ( ) ;
update_configuration_warning ( ) ;
}
2014-06-30 03:41:02 +02:00
void TileMap : : set_collision_friction ( float p_friction ) {
2017-03-05 16:44:50 +01:00
friction = p_friction ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-06-30 03:41:02 +02:00
2019-02-06 00:45:40 +01:00
Quadrant & q = E - > get ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_param ( q . body , Physics2DServer : : BODY_PARAM_FRICTION , p_friction ) ;
}
2014-06-30 03:41:02 +02:00
}
}
2017-03-05 16:44:50 +01:00
float TileMap : : get_collision_friction ( ) const {
2014-06-30 03:41:02 +02:00
return friction ;
}
2017-03-05 16:44:50 +01:00
void TileMap : : set_collision_bounce ( float p_bounce ) {
2014-06-30 03:41:02 +02:00
2017-03-05 16:44:50 +01:00
bounce = p_bounce ;
2019-02-06 00:45:40 +01:00
if ( ! use_parent ) {
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-06-30 03:41:02 +02:00
2019-02-06 00:45:40 +01:00
Quadrant & q = E - > get ( ) ;
Physics2DServer : : get_singleton ( ) - > body_set_param ( q . body , Physics2DServer : : BODY_PARAM_BOUNCE , p_bounce ) ;
}
2014-06-30 03:41:02 +02:00
}
}
2017-03-05 16:44:50 +01:00
float TileMap : : get_collision_bounce ( ) const {
2014-06-30 03:41:02 +02:00
return bounce ;
}
2015-05-03 21:47:21 +02:00
uint32_t TileMap : : get_collision_layer ( ) const {
2014-05-14 06:22:15 +02:00
return collision_layer ;
}
2015-05-03 21:47:21 +02:00
uint32_t TileMap : : get_collision_mask ( ) const {
return collision_mask ;
}
2017-04-05 20:51:31 +02:00
bool TileMap : : get_collision_layer_bit ( int p_bit ) const {
return get_collision_layer ( ) & ( 1 < < p_bit ) ;
}
bool TileMap : : get_collision_mask_bit ( int p_bit ) const {
return get_collision_mask ( ) & ( 1 < < p_bit ) ;
}
2014-10-03 05:10:51 +02:00
void TileMap : : set_mode ( Mode p_mode ) {
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
mode = p_mode ;
2014-10-03 05:10:51 +02:00
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
TileMap : : Mode TileMap : : get_mode ( ) const {
return mode ;
}
void TileMap : : set_half_offset ( HalfOffset p_half_offset ) {
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
half_offset = p_half_offset ;
2014-10-03 05:10:51 +02:00
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
2015-03-09 06:34:56 +01:00
void TileMap : : set_tile_origin ( TileOrigin p_tile_origin ) {
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
tile_origin = p_tile_origin ;
2015-03-09 06:34:56 +01:00
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
2017-03-05 16:44:50 +01:00
TileMap : : TileOrigin TileMap : : get_tile_origin ( ) const {
2015-03-09 06:34:56 +01:00
return tile_origin ;
}
2014-10-03 05:10:51 +02:00
Vector2 TileMap : : get_cell_draw_offset ( ) const {
2017-03-05 16:44:50 +01:00
switch ( mode ) {
2014-10-03 05:10:51 +02:00
case MODE_SQUARE : {
return Vector2 ( ) ;
} break ;
case MODE_ISOMETRIC : {
2017-03-05 16:44:50 +01:00
return Vector2 ( - cell_size . x * 0.5 , 0 ) ;
2014-10-03 05:10:51 +02:00
} break ;
case MODE_CUSTOM : {
Vector2 min ;
2017-03-05 16:44:50 +01:00
min . x = MIN ( custom_transform [ 0 ] . x , min . x ) ;
min . y = MIN ( custom_transform [ 0 ] . y , min . y ) ;
min . x = MIN ( custom_transform [ 1 ] . x , min . x ) ;
min . y = MIN ( custom_transform [ 1 ] . y , min . y ) ;
2014-10-03 05:10:51 +02:00
return min ;
} break ;
}
return Vector2 ( ) ;
}
TileMap : : HalfOffset TileMap : : get_half_offset ( ) const {
return half_offset ;
}
2017-01-11 04:52:51 +01:00
Transform2D TileMap : : get_cell_transform ( ) const {
2014-10-03 05:10:51 +02:00
2017-03-05 16:44:50 +01:00
switch ( mode ) {
2014-10-03 05:10:51 +02:00
case MODE_SQUARE : {
2017-01-11 04:52:51 +01:00
Transform2D m ;
2017-03-05 16:44:50 +01:00
m [ 0 ] * = cell_size . x ;
m [ 1 ] * = cell_size . y ;
2014-10-03 05:10:51 +02:00
return m ;
} break ;
case MODE_ISOMETRIC : {
//isometric only makes sense when y is positive in both x and y vectors, otherwise
//the drawing of tiles will overlap
2017-01-11 04:52:51 +01:00
Transform2D m ;
2017-03-05 16:44:50 +01:00
m [ 0 ] = Vector2 ( cell_size . x * 0.5 , cell_size . y * 0.5 ) ;
m [ 1 ] = Vector2 ( - cell_size . x * 0.5 , cell_size . y * 0.5 ) ;
2014-10-03 05:10:51 +02:00
return m ;
} break ;
case MODE_CUSTOM : {
return custom_transform ;
} break ;
}
2017-01-11 04:52:51 +01:00
return Transform2D ( ) ;
2014-10-03 05:10:51 +02:00
}
2017-03-05 16:44:50 +01:00
void TileMap : : set_custom_transform ( const Transform2D & p_xform ) {
2014-10-03 05:10:51 +02:00
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
custom_transform = p_xform ;
2014-10-03 05:10:51 +02:00
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
2017-03-05 16:44:50 +01:00
Transform2D TileMap : : get_custom_transform ( ) const {
2014-10-03 05:10:51 +02:00
return custom_transform ;
}
2017-08-11 21:10:05 +02:00
Vector2 TileMap : : _map_to_world ( int p_x , int p_y , bool p_ignore_ofs ) const {
2014-10-03 05:10:51 +02:00
2017-08-11 21:10:05 +02:00
Vector2 ret = get_cell_transform ( ) . xform ( Vector2 ( p_x , p_y ) ) ;
2014-10-03 05:10:51 +02:00
if ( ! p_ignore_ofs ) {
2017-03-05 16:44:50 +01:00
switch ( half_offset ) {
2014-10-03 05:10:51 +02:00
2019-03-24 00:59:24 +01:00
case HALF_OFFSET_X :
case HALF_OFFSET_NEGATIVE_X : {
2017-08-11 21:10:05 +02:00
if ( ABS ( p_y ) & 1 ) {
2014-10-03 05:10:51 +02:00
2019-03-24 00:59:24 +01:00
ret + = get_cell_transform ( ) [ 0 ] * ( half_offset = = HALF_OFFSET_X ? 0.5 : - 0.5 ) ;
2014-10-03 05:10:51 +02:00
}
} break ;
2019-03-24 00:59:24 +01:00
case HALF_OFFSET_Y :
case HALF_OFFSET_NEGATIVE_Y : {
2017-08-11 21:10:05 +02:00
if ( ABS ( p_x ) & 1 ) {
2019-03-24 00:59:24 +01:00
ret + = get_cell_transform ( ) [ 1 ] * ( half_offset = = HALF_OFFSET_Y ? 0.5 : - 0.5 ) ;
2014-10-03 05:10:51 +02:00
}
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-10-03 05:10:51 +02:00
}
}
return ret ;
}
2017-10-22 03:42:23 +02:00
bool TileMap : : _set ( const StringName & p_name , const Variant & p_value ) {
if ( p_name = = " format " ) {
if ( p_value . get_type ( ) = = Variant : : INT ) {
format = ( DataFormat ) ( p_value . operator int64_t ( ) ) ;
return true ;
}
} else if ( p_name = = " tile_data " ) {
if ( p_value . is_array ( ) ) {
_set_tile_data ( p_value ) ;
return true ;
}
return false ;
}
return false ;
}
bool TileMap : : _get ( const StringName & p_name , Variant & r_ret ) const {
if ( p_name = = " format " ) {
2018-11-10 02:40:08 +01:00
r_ret = format ;
2017-10-22 03:42:23 +02:00
return true ;
} else if ( p_name = = " tile_data " ) {
r_ret = _get_tile_data ( ) ;
return true ;
}
return false ;
}
void TileMap : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2018-01-11 23:35:12 +01:00
PropertyInfo p ( Variant : : INT , " format " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ;
2017-10-22 03:42:23 +02:00
p_list - > push_back ( p ) ;
2018-01-11 23:35:12 +01:00
p = PropertyInfo ( Variant : : OBJECT , " tile_data " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ;
2017-10-22 03:42:23 +02:00
p_list - > push_back ( p ) ;
}
2019-02-06 00:45:40 +01:00
void TileMap : : _validate_property ( PropertyInfo & property ) const {
if ( use_parent & & property . name ! = " collision_use_parent " & & property . name . begins_with ( " collision_ " ) ) {
property . usage = PROPERTY_USAGE_NOEDITOR ;
}
}
2017-03-05 16:44:50 +01:00
Vector2 TileMap : : map_to_world ( const Vector2 & p_pos , bool p_ignore_ofs ) const {
2014-10-03 05:10:51 +02:00
2017-03-05 16:44:50 +01:00
return _map_to_world ( p_pos . x , p_pos . y , p_ignore_ofs ) ;
2014-10-03 05:10:51 +02:00
}
2017-10-22 03:42:23 +02:00
2017-03-05 16:44:50 +01:00
Vector2 TileMap : : world_to_map ( const Vector2 & p_pos ) const {
2014-10-03 05:10:51 +02:00
Vector2 ret = get_cell_transform ( ) . affine_inverse ( ) . xform ( p_pos ) ;
2017-03-05 16:44:50 +01:00
switch ( half_offset ) {
2014-10-03 05:10:51 +02:00
case HALF_OFFSET_X : {
2017-03-05 16:44:50 +01:00
if ( ret . y > 0 ? int ( ret . y ) & 1 : ( int ( ret . y ) - 1 ) & 1 ) {
ret . x - = 0.5 ;
2014-10-03 05:10:51 +02:00
}
} break ;
2019-03-24 00:59:24 +01:00
case HALF_OFFSET_NEGATIVE_X : {
if ( ret . y > 0 ? int ( ret . y ) & 1 : ( int ( ret . y ) - 1 ) & 1 ) {
ret . x + = 0.5 ;
}
} break ;
2014-10-03 05:10:51 +02:00
case HALF_OFFSET_Y : {
2017-03-05 16:44:50 +01:00
if ( ret . x > 0 ? int ( ret . x ) & 1 : ( int ( ret . x ) - 1 ) & 1 ) {
ret . y - = 0.5 ;
2014-10-03 05:10:51 +02:00
}
} break ;
2019-03-24 00:59:24 +01:00
case HALF_OFFSET_NEGATIVE_Y : {
if ( ret . x > 0 ? int ( ret . x ) & 1 : ( int ( ret . x ) - 1 ) & 1 ) {
ret . y + = 0.5 ;
}
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-10-03 05:10:51 +02:00
}
2018-11-02 13:06:43 +01:00
// Account for precision errors on the border (GH-23250).
2019-02-13 09:23:29 +01:00
// 0.00005 is 5*CMP_EPSILON, results would start being unpredictable if
2018-11-02 13:06:43 +01:00
// cell size is > 15,000, but we can hardly have more precision anyway with
// floating point.
ret + = Vector2 ( 0.00005 , 0.00005 ) ;
2014-10-03 05:10:51 +02:00
return ret . floor ( ) ;
}
2015-03-09 06:34:56 +01:00
void TileMap : : set_y_sort_mode ( bool p_enable ) {
_clear_quadrants ( ) ;
2017-03-05 16:44:50 +01:00
y_sort_mode = p_enable ;
VS : : get_singleton ( ) - > canvas_item_set_sort_children_by_y ( get_canvas_item ( ) , y_sort_mode ) ;
2015-03-09 06:34:56 +01:00
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
bool TileMap : : is_y_sort_mode_enabled ( ) const {
return y_sort_mode ;
}
2019-07-01 22:43:52 +02:00
void TileMap : : set_compatibility_mode ( bool p_enable ) {
_clear_quadrants ( ) ;
compatibility_mode = p_enable ;
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
bool TileMap : : is_compatibility_mode_enabled ( ) const {
return compatibility_mode ;
}
void TileMap : : set_centered_textures ( bool p_enable ) {
_clear_quadrants ( ) ;
centered_textures = p_enable ;
_recreate_quadrants ( ) ;
emit_signal ( " settings_changed " ) ;
}
bool TileMap : : is_centered_textures_enabled ( ) const {
return centered_textures ;
}
2015-04-18 19:00:15 +02:00
Array TileMap : : get_used_cells ( ) const {
Array a ;
a . resize ( tile_map . size ( ) ) ;
2017-03-05 16:44:50 +01:00
int i = 0 ;
for ( Map < PosKey , Cell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
2015-04-18 19:00:15 +02:00
2017-03-05 16:44:50 +01:00
Vector2 p ( E - > key ( ) . x , E - > key ( ) . y ) ;
a [ i + + ] = p ;
2015-04-18 19:00:15 +02:00
}
return a ;
}
2014-05-14 06:22:15 +02:00
2017-08-02 12:40:32 +02:00
Array TileMap : : get_used_cells_by_id ( int p_id ) const {
Array a ;
for ( Map < PosKey , Cell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > value ( ) . id = = p_id ) {
Vector2 p ( E - > key ( ) . x , E - > key ( ) . y ) ;
a . push_back ( p ) ;
}
}
return a ;
}
2017-02-20 22:02:03 +01:00
Rect2 TileMap : : get_used_rect ( ) { // Not const because of cache
if ( used_size_cache_dirty ) {
2017-03-05 16:44:50 +01:00
if ( tile_map . size ( ) > 0 ) {
2017-02-20 22:02:03 +01:00
used_size_cache = Rect2 ( tile_map . front ( ) - > key ( ) . x , tile_map . front ( ) - > key ( ) . y , 0 , 0 ) ;
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Cell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-20 22:02:03 +01:00
used_size_cache . expand_to ( Vector2 ( E - > key ( ) . x , E - > key ( ) . y ) ) ;
}
2017-03-05 16:44:50 +01:00
used_size_cache . size + = Vector2 ( 1 , 1 ) ;
2017-02-20 22:02:03 +01:00
} else {
used_size_cache = Rect2 ( ) ;
}
used_size_cache_dirty = false ;
}
return used_size_cache ;
}
2015-12-12 14:45:31 +01:00
void TileMap : : set_occluder_light_mask ( int p_mask ) {
2017-03-05 16:44:50 +01:00
occluder_light_mask = p_mask ;
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2015-12-12 14:45:31 +01:00
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant : : Occluder > : : Element * F = E - > get ( ) . occluder_instances . front ( ) ; F ; F = F - > next ( ) ) {
VisualServer : : get_singleton ( ) - > canvas_light_occluder_set_light_mask ( F - > get ( ) . id , occluder_light_mask ) ;
2015-12-12 14:45:31 +01:00
}
}
}
2017-03-05 16:44:50 +01:00
int TileMap : : get_occluder_light_mask ( ) const {
2015-12-12 14:45:31 +01:00
return occluder_light_mask ;
}
2015-12-29 18:47:13 +01:00
void TileMap : : set_light_mask ( int p_light_mask ) {
CanvasItem : : set_light_mask ( p_light_mask ) ;
2017-03-05 16:44:50 +01:00
for ( Map < PosKey , Quadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2015-12-12 14:45:31 +01:00
2017-03-05 16:44:50 +01:00
for ( List < RID > : : Element * F = E - > get ( ) . canvas_items . front ( ) ; F ; F = F - > next ( ) ) {
VisualServer : : get_singleton ( ) - > canvas_item_set_light_mask ( F - > get ( ) , get_light_mask ( ) ) ;
2015-12-29 18:47:13 +01:00
}
}
}
2015-12-12 14:45:31 +01:00
2017-11-10 13:21:33 +01:00
void TileMap : : set_clip_uv ( bool p_enable ) {
if ( clip_uv = = p_enable )
return ;
_clear_quadrants ( ) ;
clip_uv = p_enable ;
_recreate_quadrants ( ) ;
}
bool TileMap : : get_clip_uv ( ) const {
return clip_uv ;
}
2019-02-06 00:45:40 +01:00
String TileMap : : get_configuration_warning ( ) const {
String warning = Node2D : : get_configuration_warning ( ) ;
if ( use_parent & & ! collision_parent ) {
if ( ! warning . empty ( ) ) {
warning + = " \n " ;
}
return TTR ( " TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape. " ) ;
}
return warning ;
}
2014-02-10 02:10:30 +01:00
void TileMap : : _bind_methods ( ) {
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_tileset " , " tileset " ) , & TileMap : : set_tileset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tileset " ) , & TileMap : : get_tileset ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_mode " , " mode " ) , & TileMap : : set_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_mode " ) , & TileMap : : get_mode ) ;
2014-10-03 05:10:51 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_half_offset " , " half_offset " ) , & TileMap : : set_half_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_half_offset " ) , & TileMap : : get_half_offset ) ;
2014-10-03 05:10:51 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_transform " , " custom_transform " ) , & TileMap : : set_custom_transform ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_transform " ) , & TileMap : : get_custom_transform ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_cell_size " , " size " ) , & TileMap : : set_cell_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_cell_size " ) , & TileMap : : get_cell_size ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _set_old_cell_size " , " size " ) , & TileMap : : _set_old_cell_size ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_old_cell_size " ) , & TileMap : : _get_old_cell_size ) ;
2014-10-03 05:10:51 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_quadrant_size " , " size " ) , & TileMap : : set_quadrant_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_quadrant_size " ) , & TileMap : : get_quadrant_size ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_tile_origin " , " origin " ) , & TileMap : : set_tile_origin ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tile_origin " ) , & TileMap : : get_tile_origin ) ;
2015-03-09 06:34:56 +01:00
2017-11-10 13:21:33 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_clip_uv " , " enable " ) , & TileMap : : set_clip_uv ) ;
ClassDB : : bind_method ( D_METHOD ( " get_clip_uv " ) , & TileMap : : get_clip_uv ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_y_sort_mode " , " enable " ) , & TileMap : : set_y_sort_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " is_y_sort_mode_enabled " ) , & TileMap : : is_y_sort_mode_enabled ) ;
2015-03-09 06:34:56 +01:00
2019-07-01 22:43:52 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_compatibility_mode " , " enable " ) , & TileMap : : set_compatibility_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " is_compatibility_mode_enabled " ) , & TileMap : : is_compatibility_mode_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_centered_textures " , " enable " ) , & TileMap : : set_centered_textures ) ;
ClassDB : : bind_method ( D_METHOD ( " is_centered_textures_enabled " ) , & TileMap : : is_centered_textures_enabled ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_use_kinematic " , " use_kinematic " ) , & TileMap : : set_collision_use_kinematic ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_use_kinematic " ) , & TileMap : : get_collision_use_kinematic ) ;
2015-02-13 21:43:50 +01:00
2019-02-06 00:45:40 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_use_parent " , " use_parent " ) , & TileMap : : set_collision_use_parent ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_use_parent " ) , & TileMap : : get_collision_use_parent ) ;
2017-04-05 20:51:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_layer " , " layer " ) , & TileMap : : set_collision_layer ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_collision_layer " ) , & TileMap : : get_collision_layer ) ;
2015-05-03 21:47:21 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_mask " , " mask " ) , & TileMap : : set_collision_mask ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_mask " ) , & TileMap : : get_collision_mask ) ;
2014-02-10 02:10:30 +01:00
2017-04-05 20:51:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_layer_bit " , " bit " , " value " ) , & TileMap : : set_collision_layer_bit ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_layer_bit " , " bit " ) , & TileMap : : get_collision_layer_bit ) ;
ClassDB : : bind_method ( D_METHOD ( " set_collision_mask_bit " , " bit " , " value " ) , & TileMap : : set_collision_mask_bit ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_mask_bit " , " bit " ) , & TileMap : : get_collision_mask_bit ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_friction " , " value " ) , & TileMap : : set_collision_friction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_friction " ) , & TileMap : : get_collision_friction ) ;
2014-06-30 03:41:02 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_bounce " , " value " ) , & TileMap : : set_collision_bounce ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_bounce " ) , & TileMap : : get_collision_bounce ) ;
2014-06-30 03:41:02 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_occluder_light_mask " , " mask " ) , & TileMap : : set_occluder_light_mask ) ;
ClassDB : : bind_method ( D_METHOD ( " get_occluder_light_mask " ) , & TileMap : : get_occluder_light_mask ) ;
2015-12-12 14:45:31 +01:00
2017-11-24 05:43:15 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_cell " , " x " , " y " , " tile " , " flip_x " , " flip_y " , " transpose " , " autotile_coord " ) , & TileMap : : set_cell , DEFVAL ( false ) , DEFVAL ( false ) , DEFVAL ( false ) , DEFVAL ( Vector2 ( ) ) ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_cellv " , " position " , " tile " , " flip_x " , " flip_y " , " transpose " ) , & TileMap : : set_cellv , DEFVAL ( false ) , DEFVAL ( false ) , DEFVAL ( false ) ) ;
2018-08-29 14:00:00 +02:00
ClassDB : : bind_method ( D_METHOD ( " _set_celld " , " position " , " data " ) , & TileMap : : _set_celld ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_cell " , " x " , " y " ) , & TileMap : : get_cell ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_cellv " , " position " ) , & TileMap : : get_cellv ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_cell_x_flipped " , " x " , " y " ) , & TileMap : : is_cell_x_flipped ) ;
ClassDB : : bind_method ( D_METHOD ( " is_cell_y_flipped " , " x " , " y " ) , & TileMap : : is_cell_y_flipped ) ;
ClassDB : : bind_method ( D_METHOD ( " is_cell_transposed " , " x " , " y " ) , & TileMap : : is_cell_transposed ) ;
2014-02-10 02:10:30 +01:00
2018-12-20 18:43:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_cell_autotile_coord " , " x " , " y " ) , & TileMap : : get_cell_autotile_coord ) ;
2018-02-24 06:56:48 +01:00
ClassDB : : bind_method ( D_METHOD ( " fix_invalid_tiles " ) , & TileMap : : fix_invalid_tiles ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & TileMap : : clear ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_used_cells " ) , & TileMap : : get_used_cells ) ;
2017-08-02 12:40:32 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_used_cells_by_id " , " id " ) , & TileMap : : get_used_cells_by_id ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_used_rect " ) , & TileMap : : get_used_rect ) ;
2015-04-18 19:00:15 +02:00
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " map_to_world " , " map_position " , " ignore_half_ofs " ) , & TileMap : : map_to_world , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " world_to_map " , " world_position " ) , & TileMap : : world_to_map ) ;
2014-10-03 05:10:51 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _clear_quadrants " ) , & TileMap : : _clear_quadrants ) ;
ClassDB : : bind_method ( D_METHOD ( " _recreate_quadrants " ) , & TileMap : : _recreate_quadrants ) ;
2018-07-22 15:26:14 +02:00
ClassDB : : bind_method ( D_METHOD ( " update_dirty_quadrants " ) , & TileMap : : update_dirty_quadrants ) ;
2014-02-10 02:10:30 +01:00
2017-12-25 15:19:56 +01:00
ClassDB : : bind_method ( D_METHOD ( " update_bitmask_area " , " position " ) , & TileMap : : update_bitmask_area ) ;
2017-12-06 01:14:33 +01:00
ClassDB : : bind_method ( D_METHOD ( " update_bitmask_region " , " start " , " end " ) , & TileMap : : update_bitmask_region , DEFVAL ( Vector2 ( ) ) , DEFVAL ( Vector2 ( ) ) ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _set_tile_data " ) , & TileMap : : _set_tile_data ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_tile_data " ) , & TileMap : : _get_tile_data ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " mode " , PROPERTY_HINT_ENUM , " Square,Isometric,Custom " ) , " set_mode " , " get_mode " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " tile_set " , PROPERTY_HINT_RESOURCE_TYPE , " TileSet " ) , " set_tileset " , " get_tileset " ) ;
2015-05-03 21:47:21 +02:00
2017-03-05 16:44:50 +01:00
ADD_GROUP ( " Cell " , " cell_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " cell_size " , PROPERTY_HINT_RANGE , " 1,8192,1 " ) , " set_cell_size " , " get_cell_size " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " cell_quadrant_size " , PROPERTY_HINT_RANGE , " 1,128,1 " ) , " set_quadrant_size " , " get_quadrant_size " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : TRANSFORM2D , " cell_custom_transform " ) , " set_custom_transform " , " get_custom_transform " ) ;
2019-03-24 00:59:24 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " cell_half_offset " , PROPERTY_HINT_ENUM , " Offset X,Offset Y,Disabled,Offset Negative X,Offset Negative Y " ) , " set_half_offset " , " get_half_offset " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " cell_tile_origin " , PROPERTY_HINT_ENUM , " Top Left,Center,Bottom Left " ) , " set_tile_origin " , " get_tile_origin " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " cell_y_sort " ) , " set_y_sort_mode " , " is_y_sort_mode_enabled " ) ;
2019-07-01 22:43:52 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " compatibility_mode " ) , " set_compatibility_mode " , " is_compatibility_mode_enabled " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " centered_textures " ) , " set_centered_textures " , " is_centered_textures_enabled " ) ;
2017-11-10 13:21:33 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " cell_clip_uv " ) , " set_clip_uv " , " get_clip_uv " ) ;
2017-01-04 05:16:14 +01:00
2017-03-05 16:44:50 +01:00
ADD_GROUP ( " Collision " , " collision_ " ) ;
2019-02-06 00:45:40 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " collision_use_parent " , PROPERTY_HINT_NONE , " " ) , " set_collision_use_parent " , " get_collision_use_parent " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " collision_use_kinematic " , PROPERTY_HINT_NONE , " " ) , " set_collision_use_kinematic " , " get_collision_use_kinematic " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " collision_friction " , PROPERTY_HINT_RANGE , " 0,1,0.01 " ) , " set_collision_friction " , " get_collision_friction " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " collision_bounce " , PROPERTY_HINT_RANGE , " 0,1,0.01 " ) , " set_collision_bounce " , " get_collision_bounce " ) ;
2017-06-13 17:45:01 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " collision_layer " , PROPERTY_HINT_LAYERS_2D_PHYSICS ) , " set_collision_layer " , " get_collision_layer " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " collision_mask " , PROPERTY_HINT_LAYERS_2D_PHYSICS ) , " set_collision_mask " , " get_collision_mask " ) ;
2017-01-04 05:16:14 +01:00
2017-03-05 16:44:50 +01:00
ADD_GROUP ( " Occluder " , " occluder_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " occluder_light_mask " , PROPERTY_HINT_LAYERS_2D_RENDER ) , " set_occluder_light_mask " , " get_occluder_light_mask " ) ;
2014-02-10 02:10:30 +01:00
2014-04-19 21:46:52 +02:00
ADD_SIGNAL ( MethodInfo ( " settings_changed " ) ) ;
2017-03-05 16:44:50 +01:00
BIND_CONSTANT ( INVALID_CELL ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( MODE_SQUARE ) ;
BIND_ENUM_CONSTANT ( MODE_ISOMETRIC ) ;
BIND_ENUM_CONSTANT ( MODE_CUSTOM ) ;
BIND_ENUM_CONSTANT ( HALF_OFFSET_X ) ;
BIND_ENUM_CONSTANT ( HALF_OFFSET_Y ) ;
BIND_ENUM_CONSTANT ( HALF_OFFSET_DISABLED ) ;
2019-03-24 00:59:24 +01:00
BIND_ENUM_CONSTANT ( HALF_OFFSET_NEGATIVE_X ) ;
BIND_ENUM_CONSTANT ( HALF_OFFSET_NEGATIVE_Y ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( TILE_ORIGIN_TOP_LEFT ) ;
BIND_ENUM_CONSTANT ( TILE_ORIGIN_CENTER ) ;
BIND_ENUM_CONSTANT ( TILE_ORIGIN_BOTTOM_LEFT ) ;
2014-02-10 02:10:30 +01:00
}
2018-03-11 12:24:50 +01:00
void TileMap : : _changed_callback ( Object * p_changed , const char * p_prop ) {
if ( tile_set . is_valid ( ) & & tile_set . ptr ( ) = = p_changed ) {
emit_signal ( " settings_changed " ) ;
}
}
2014-02-10 02:10:30 +01:00
TileMap : : TileMap ( ) {
2017-03-05 16:44:50 +01:00
rect_cache_dirty = true ;
used_size_cache_dirty = true ;
pending_update = false ;
quadrant_order_dirty = false ;
quadrant_size = 16 ;
cell_size = Size2 ( 64 , 64 ) ;
collision_layer = 1 ;
collision_mask = 1 ;
friction = 1 ;
bounce = 0 ;
mode = MODE_SQUARE ;
half_offset = HALF_OFFSET_DISABLED ;
2019-02-06 00:45:40 +01:00
use_parent = false ;
collision_parent = NULL ;
2019-06-29 21:45:14 +02:00
use_kinematic = false ;
2017-03-05 16:44:50 +01:00
navigation = NULL ;
y_sort_mode = false ;
2019-07-01 22:43:52 +02:00
compatibility_mode = false ;
centered_textures = false ;
2017-03-05 16:44:50 +01:00
occluder_light_mask = 1 ;
2017-11-10 13:21:33 +01:00
clip_uv = false ;
2017-12-09 17:44:26 +01:00
format = FORMAT_1 ; //Always initialize with the lowest format
2017-03-05 16:44:50 +01:00
fp_adjust = 0.00001 ;
tile_origin = TILE_ORIGIN_TOP_LEFT ;
2017-01-13 00:35:46 +01:00
set_notify_transform ( true ) ;
2019-02-06 00:45:40 +01:00
set_notify_local_transform ( false ) ;
2014-02-10 02:10:30 +01:00
}
TileMap : : ~ TileMap ( ) {
2018-03-11 12:24:50 +01:00
if ( tile_set . is_valid ( ) )
tile_set - > remove_change_receptor ( this ) ;
2014-02-10 02:10:30 +01:00
clear ( ) ;
}