From 09489e3a78de39bb4d8690f3c65f8a5e7a56a95e Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 9 Mar 2015 02:34:56 -0300 Subject: lot of work on 2D lighting and isometric maps added a new demo, isometric_light that does full isometric sorting, lights, shadows, etc. --- scene/2d/canvas_item.cpp | 1 + scene/2d/light_2d.cpp | 17 ++ scene/2d/light_2d.h | 4 + scene/2d/light_occluder_2d.cpp | 5 +- scene/2d/tile_map.cpp | 308 +++++++++++++++++++++++++++++++----- scene/2d/tile_map.h | 41 ++++- scene/2d/visibility_notifier_2d.cpp | 22 +++ scene/2d/visibility_notifier_2d.h | 1 + scene/gui/control.cpp | 84 +++++----- scene/resources/tile_set.cpp | 106 ++++++++++++- scene/resources/tile_set.h | 22 +++ 11 files changed, 525 insertions(+), 86 deletions(-) (limited to 'scene') diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 4a1842100a..1002713740 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -1011,6 +1011,7 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_global_transform_with_canvas"),&CanvasItem::get_global_transform_with_canvas); ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform); ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect); + ObjectTypeDB::bind_method(_MD("get_canvas_transform"),&CanvasItem::get_canvas_transform); ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas); ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d); //ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 93be0c397f..5472e0b00e 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -148,6 +148,18 @@ int Light2D::get_item_mask() const { return item_mask; } +void Light2D::set_item_shadow_mask( int p_mask) { + + item_shadow_mask=p_mask; + VS::get_singleton()->canvas_light_set_item_shadow_mask(canvas_light,item_shadow_mask); + +} + +int Light2D::get_item_shadow_mask() const { + + return item_shadow_mask; +} + void Light2D::set_subtract_mode( bool p_enable ) { subtract_mode=p_enable; @@ -246,6 +258,9 @@ void Light2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_item_mask","item_mask"),&Light2D::set_item_mask); ObjectTypeDB::bind_method(_MD("get_item_mask"),&Light2D::get_item_mask); + ObjectTypeDB::bind_method(_MD("set_item_shadow_mask","item_shadow_mask"),&Light2D::set_item_shadow_mask); + ObjectTypeDB::bind_method(_MD("get_item_shadow_mask"),&Light2D::get_item_shadow_mask); + ObjectTypeDB::bind_method(_MD("set_subtract_mode","enable"),&Light2D::set_subtract_mode); ObjectTypeDB::bind_method(_MD("get_subtract_mode"),&Light2D::get_subtract_mode); @@ -272,6 +287,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled")); ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_shadow_mask"),_SCS("get_item_shadow_mask")); } @@ -288,6 +304,7 @@ Light2D::Light2D() { layer_min=0; layer_max=0; item_mask=1; + item_shadow_mask=1; subtract_mode=false; shadow_buffer_size=2048; shadow_esm_multiplier=80; diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 89f351c3cd..26dc1f4d44 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -17,6 +17,7 @@ private: int layer_min; int layer_max; int item_mask; + int item_shadow_mask; int shadow_buffer_size; float shadow_esm_multiplier; bool subtract_mode; @@ -64,6 +65,9 @@ public: void set_item_mask( int p_mask); int get_item_mask() const; + void set_item_shadow_mask( int p_mask); + int get_item_shadow_mask() const; + void set_subtract_mode( bool p_enable ); bool get_subtract_mode() const; diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 186ea2e248..6ebd499f71 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -18,7 +18,8 @@ void OccluderPolygon2D::set_closed(bool p_closed) { if (closed==p_closed) return; closed=p_closed; - VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed); + if (polygon.size()) + VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed); emit_changed(); } @@ -56,9 +57,9 @@ void OccluderPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&OccluderPolygon2D::set_polygon); ObjectTypeDB::bind_method(_MD("get_polygon"),&OccluderPolygon2D::get_polygon); - ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"closed"),_SCS("set_closed"),_SCS("is_closed")); ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mode",PROPERTY_HINT_ENUM,"Disabled,ClockWise,CounterClockWise"),_SCS("set_cull_mode"),_SCS("get_cull_mode")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); BIND_CONSTANT(CULL_DISABLED); BIND_CONSTANT(CULL_CLOCKWISE); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 75e7957cb8..b9d87c1224 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -30,12 +30,32 @@ #include "io/marshalls.h" #include "servers/physics_2d_server.h" #include "method_bind_ext.inc" + +int TileMap::_get_quadrant_size() const { + + if (y_sort_mode) + return 1; + else + return quadrant_size; +} + void TileMap::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { + Node2D *c=this; + while(c) { + + navigation=c->cast_to(); + if (navigation) { + break; + } + + c=c->get_parent()->cast_to(); + } + pending_update=true; _update_dirty_quadrants(); RID space = get_world_2d()->get_space(); @@ -47,6 +67,25 @@ void TileMap::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { _update_quadrant_space(RID()); + for (Map::Element *E=quadrant_map.front();E;E=E->next()) { + + Quadrant &q=E->get(); + if (navigation) { + for(Map::Element *E=q.navpoly_ids.front();E;E=E->next()) { + + navigation->navpoly_remove(E->get().id); + } + q.navpoly_ids.clear(); + } + + for(Map::Element *E=q.occluder_instances.front();E;E=E->next()) { + VS::get_singleton()->free(E->get().id); + } + q.occluder_instances.clear(); + } + + navigation=NULL; + } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -74,6 +113,10 @@ void TileMap::_update_quadrant_transform() { Matrix32 global_transform = get_global_transform(); + Matrix32 nav_rel; + if (navigation) + nav_rel = get_relative_transform(navigation); + for (Map::Element *E=quadrant_map.front();E;E=E->next()) { Quadrant &q=E->get(); @@ -81,6 +124,17 @@ void TileMap::_update_quadrant_transform() { xform.set_origin( q.pos ); xform = global_transform * xform; Physics2DServer::get_singleton()->body_set_state(q.body,Physics2DServer::BODY_STATE_TRANSFORM,xform); + + if (navigation) { + for(Map::Element *E=q.navpoly_ids.front();E;E=E->next()) { + + navigation->navpoly_set_transform(E->get().id,nav_rel * E->get().xform); + } + } + + for(Map::Element *E=q.occluder_instances.front();E;E=E->next()) { + VS::get_singleton()->canvas_light_occluder_set_transform(E->get().id,global_transform * E->get().xform); + } } } @@ -161,6 +215,33 @@ bool TileMap::get_center_y() const { return center_y; } +void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& c,Vector2& offset,const Size2 &sc) { + + Size2 s=sc; + + if (c.transpose) { + 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); + } + if (c.flip_h) { + xform.elements[0].x=-xform.elements[0].x; + xform.elements[1].x=-xform.elements[1].x; + if (tile_origin==TILE_ORIGIN_TOP_LEFT) + offset.x=s.x-offset.x; + } + if (c.flip_v) { + xform.elements[0].y=-xform.elements[0].y; + xform.elements[1].y=-xform.elements[1].y; + if (tile_origin==TILE_ORIGIN_TOP_LEFT) + offset.y=s.y-offset.y; + } + xform.elements[2].x+=offset.x; + xform.elements[2].y+=offset.y; + +} + void TileMap::_update_dirty_quadrants() { if (!pending_update) @@ -173,15 +254,42 @@ void TileMap::_update_dirty_quadrants() { VisualServer *vs = VisualServer::get_singleton(); Physics2DServer *ps = Physics2DServer::get_singleton(); Vector2 tofs = get_cell_draw_offset(); + Vector2 tcenter = cell_size/2; + Matrix32 nav_rel; + if (navigation) + nav_rel = get_relative_transform(navigation); + + Vector2 qofs; while (dirty_quadrant_list.first()) { Quadrant &q = *dirty_quadrant_list.first()->self(); - vs->canvas_item_clear(q.canvas_item); + for (List::Element *E=q.canvas_items.front();E;E=E->next()) { + + vs->free(E->get()); + } + + q.canvas_items.clear(); + ps->body_clear_shapes(q.body); int shape_idx=0; + if (navigation) { + for(Map::Element *E=q.navpoly_ids.front();E;E=E->next()) { + + navigation->navpoly_remove(E->get().id); + } + q.navpoly_ids.clear(); + } + + for(Map::Element *E=q.occluder_instances.front();E;E=E->next()) { + VS::get_singleton()->free(E->get().id); + } + q.occluder_instances.clear(); + Ref prev_material; + RID prev_canvas_item; + for(int i=0;i::Element *E=tile_map.find( q.cells[i] ); @@ -192,11 +300,35 @@ void TileMap::_update_dirty_quadrants() { Ref tex = tile_set->tile_get_texture(c.id); Vector2 tile_ofs = tile_set->tile_get_texture_offset(c.id); - Vector2 offset = _map_to_world(E->key().x, E->key().y) - q.pos + tofs; + Vector2 wofs = _map_to_world(E->key().x, E->key().y); + Vector2 offset = wofs - q.pos + tofs; if (!tex.is_valid()) continue; + Ref mat = tile_set->tile_get_material(c.id); + + RID canvas_item; + + if (prev_canvas_item==RID() || prev_material!=mat) { + + canvas_item=vs->canvas_item_create(); + if (mat.is_valid()) + vs->canvas_item_set_material(canvas_item,mat->get_rid()); + vs->canvas_item_set_parent( canvas_item, get_canvas_item() ); + Matrix32 xform; + xform.set_origin( q.pos ); + vs->canvas_item_set_transform( canvas_item, xform ); + q.canvas_items.push_back(canvas_item); + + prev_canvas_item=canvas_item; + prev_material=mat; + + } else { + canvas_item=prev_canvas_item; + } + + Rect2 r = tile_set->tile_get_region(c.id); Size2 s = tex->get_size(); @@ -223,12 +355,32 @@ void TileMap::_update_dirty_quadrants() { if (c.flip_v) rect.size.y=-rect.size.y; + Vector2 center_ofs; + + if (tile_origin==TILE_ORIGIN_TOP_LEFT) { + rect.pos+=tile_ofs; + } else if (tile_origin==TILE_ORIGIN_CENTER) { + rect.pos+=tcenter; + + Vector2 center = (s/2) - tile_ofs; + center_ofs=tcenter-(s/2); + + if (c.flip_h) + rect.pos.x-=s.x-center.x; + else + rect.pos.x-=center.x; + + if (c.flip_v) + rect.pos.y-=s.y-center.y; + else + rect.pos.y-=center.y; + } + - rect.pos+=tile_ofs; if (r==Rect2()) { - tex->draw_rect(q.canvas_item,rect,false,Color(1,1,1),c.transpose); + tex->draw_rect(canvas_item,rect,false,Color(1,1,1),c.transpose); } else { - tex->draw_rect_region(q.canvas_item,rect,r,Color(1,1,1),c.transpose); + tex->draw_rect_region(canvas_item,rect,r,Color(1,1,1),c.transpose); } Vector< Ref > shapes = tile_set->tile_get_shapes(c.id); @@ -242,32 +394,48 @@ void TileMap::_update_dirty_quadrants() { Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id); Matrix32 xform; xform.set_origin(offset.floor()); - if (c.transpose) { - SWAP(xform.elements[0].x, xform.elements[0].y); - SWAP(xform.elements[1].x, xform.elements[1].y); - SWAP(shape_ofs.x, shape_ofs.y); - SWAP(s.x, s.y); - } - if (c.flip_h) { - xform.elements[0].x=-xform.elements[0].x; - xform.elements[1].x=-xform.elements[1].x; - shape_ofs.x=s.x-shape_ofs.x; - } - if (c.flip_v) { - xform.elements[0].y=-xform.elements[0].y; - xform.elements[1].y=-xform.elements[1].y; - shape_ofs.y=s.y-shape_ofs.y; - } - xform.elements[2].x+=shape_ofs.x; - xform.elements[2].y+=shape_ofs.y; - + _fix_cell_transform(xform,c,shape_ofs+center_ofs,s); ps->body_add_shape(q.body,shape->get_rid(),xform); ps->body_set_shape_metadata(q.body,shape_idx++,Vector2(E->key().x,E->key().y)); } } + + if (navigation) { + Ref navpoly = tile_set->tile_get_navigation_polygon(c.id); + Vector2 npoly_ofs = tile_set->tile_get_navigation_polygon_offset(c.id); + Matrix32 xform; + xform.set_origin(offset.floor()+q.pos); + _fix_cell_transform(xform,c,npoly_ofs+center_ofs,s); + + int pid = navigation->navpoly_create(navpoly,nav_rel * xform); + + Quadrant::NavPoly np; + np.id=pid; + np.xform=xform; + q.navpoly_ids[E->key()]=np; + } + + + Ref occluder=tile_set->tile_get_light_occluder(c.id); + if (occluder.is_valid()) { + + Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); + Matrix32 xform; + xform.set_origin(offset.floor()+q.pos); + _fix_cell_transform(xform,c,occluder_ofs+center_ofs,s); + + RID orid = VS::get_singleton()->canvas_light_occluder_create(); + 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()); + Quadrant::Occluder oc; + oc.xform=xform; + oc.id=orid; + q.occluder_instances[E->key()]=oc; + } } dirty_quadrant_list.remove( dirty_quadrant_list.first() ); @@ -282,10 +450,10 @@ void TileMap::_update_dirty_quadrants() { for (Map::Element *E=quadrant_map.front();E;E=E->next()) { Quadrant &q=E->get(); - if (q.canvas_item.is_valid()) { - VS::get_singleton()->canvas_item_raise(q.canvas_item); - } + for (List::Element *E=q.canvas_items.front();E;E=E->next()) { + VS::get_singleton()->canvas_item_raise(E->get()); + } } quadrant_order_dirty=false; @@ -308,10 +476,10 @@ void TileMap::_recompute_rect_cache() { Rect2 r; - r.pos=_map_to_world(E->key().x*quadrant_size, E->key().y*quadrant_size); - r.expand_to( _map_to_world(E->key().x*quadrant_size+quadrant_size, E->key().y*quadrant_size) ); - r.expand_to( _map_to_world(E->key().x*quadrant_size+quadrant_size, E->key().y*quadrant_size+quadrant_size) ); - r.expand_to( _map_to_world(E->key().x*quadrant_size, E->key().y*quadrant_size+quadrant_size) ); + r.pos=_map_to_world(E->key().x*_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()) ); + 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; else @@ -322,7 +490,7 @@ void TileMap::_recompute_rect_cache() { if (r_total==Rect2()) { rect_cache=Rect2(-10,-10,20,20); } else { - rect_cache=r_total.grow(MAX(cell_size.x,cell_size.y)*quadrant_size); + rect_cache=r_total.grow(MAX(cell_size.x,cell_size.y)*_get_quadrant_size()); } item_rect_changed(); @@ -338,11 +506,13 @@ Map::Element *TileMap::_create_quadrant(const Matrix32 xform; //xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size); Quadrant q; - q.pos = _map_to_world(p_qk.x*quadrant_size,p_qk.y*quadrant_size); + 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; + xform.set_origin( q.pos ); - q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); - VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() ); - VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform ); +// q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); q.body=Physics2DServer::get_singleton()->body_create(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_layer_mask(q.body,collision_layer); @@ -366,10 +536,27 @@ void TileMap::_erase_quadrant(Map::Element *Q) { Quadrant &q=Q->get(); Physics2DServer::get_singleton()->free(q.body); - VisualServer::get_singleton()->free(q.canvas_item); + for (List::Element *E=q.canvas_items.front();E;E=E->next()) { + + VisualServer::get_singleton()->free(E->get()); + } + q.canvas_items.clear(); if (q.dirty_list.in_list()) dirty_quadrant_list.remove(&q.dirty_list); + if (navigation) { + for(Map::Element *E=q.navpoly_ids.front();E;E=E->next()) { + + navigation->navpoly_remove(E->get().id); + } + q.navpoly_ids.clear(); + } + + for(Map::Element *E=q.occluder_instances.front();E;E=E->next()) { + VS::get_singleton()->free(E->get().id); + } + q.occluder_instances.clear(); + quadrant_map.erase(Q); rect_cache_dirty=true; } @@ -397,7 +584,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bo if (!E && p_tile==INVALID_CELL) return; //nothing to do - PosKey qk(p_x/quadrant_size,p_y/quadrant_size); + PosKey qk(p_x/_get_quadrant_size(),p_y/_get_quadrant_size()); if (p_tile==INVALID_CELL) { //erase existing tile_map.erase(pk); @@ -495,7 +682,7 @@ void TileMap::_recreate_quadrants() { for (Map::Element *E=tile_map.front();E;E=E->next()) { - PosKey qk(E->key().x/quadrant_size,E->key().y/quadrant_size); + PosKey qk(E->key().x/_get_quadrant_size(),E->key().y/_get_quadrant_size()); Map::Element *Q=quadrant_map.find(qk); if (!Q) { @@ -511,6 +698,7 @@ void TileMap::_recreate_quadrants() { } + void TileMap::_clear_quadrants() { while (quadrant_map.size()) { @@ -678,6 +866,20 @@ void TileMap::set_half_offset(HalfOffset p_half_offset) { emit_signal("settings_changed"); } +void TileMap::set_tile_origin(TileOrigin p_tile_origin) { + + _clear_quadrants(); + tile_origin=p_tile_origin; + _recreate_quadrants(); + emit_signal("settings_changed"); +} + +TileMap::TileOrigin TileMap::get_tile_origin() const{ + + return tile_origin; +} + + Vector2 TileMap::get_cell_draw_offset() const { switch(mode) { @@ -804,6 +1006,21 @@ Vector2 TileMap::world_to_map(const Vector2& p_pos) const{ return ret.floor(); } +void TileMap::set_y_sort_mode(bool p_enable) { + + _clear_quadrants(); + y_sort_mode=p_enable; + VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(),y_sort_mode); + _recreate_quadrants(); + emit_signal("settings_changed"); + +} + +bool TileMap::is_y_sort_mode_enabled() const { + + return y_sort_mode; +} + void TileMap::_bind_methods() { @@ -829,12 +1046,18 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_quadrant_size","size"),&TileMap::set_quadrant_size); ObjectTypeDB::bind_method(_MD("get_quadrant_size"),&TileMap::get_quadrant_size); + ObjectTypeDB::bind_method(_MD("set_tile_origin","origin"),&TileMap::set_tile_origin); + ObjectTypeDB::bind_method(_MD("get_tile_origin"),&TileMap::get_tile_origin); + ObjectTypeDB::bind_method(_MD("set_center_x","enable"),&TileMap::set_center_x); ObjectTypeDB::bind_method(_MD("get_center_x"),&TileMap::get_center_x); ObjectTypeDB::bind_method(_MD("set_center_y","enable"),&TileMap::set_center_y); ObjectTypeDB::bind_method(_MD("get_center_y"),&TileMap::get_center_y); + ObjectTypeDB::bind_method(_MD("set_y_sort_mode","enable"),&TileMap::set_y_sort_mode); + ObjectTypeDB::bind_method(_MD("is_y_sort_mode_enabled"),&TileMap::is_y_sort_mode_enabled); + ObjectTypeDB::bind_method(_MD("set_collision_use_kinematic","use_kinematic"),&TileMap::set_collision_use_kinematic); ObjectTypeDB::bind_method(_MD("get_collision_use_kinematic"),&TileMap::get_collision_use_kinematic); @@ -871,6 +1094,8 @@ void TileMap::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size")); ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"cell/custom_transform"),_SCS("set_custom_transform"),_SCS("get_custom_transform")); ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/half_offset",PROPERTY_HINT_ENUM,"Offset X,Offset Y,Disabled"),_SCS("set_half_offset"),_SCS("get_half_offset")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/tile_origin",PROPERTY_HINT_ENUM,"Top Left,Center"),_SCS("set_tile_origin"),_SCS("get_tile_origin")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"cell/y_sort"),_SCS("set_y_sort_mode"),_SCS("is_y_sort_mode_enabled")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collision/use_kinematic",PROPERTY_HINT_NONE,""),_SCS("set_collision_use_kinematic"),_SCS("get_collision_use_kinematic")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_bounce"),_SCS("get_collision_bounce")); @@ -886,6 +1111,8 @@ void TileMap::_bind_methods() { BIND_CONSTANT( HALF_OFFSET_X ); BIND_CONSTANT( HALF_OFFSET_Y ); BIND_CONSTANT( HALF_OFFSET_DISABLED ); + BIND_CONSTANT( TILE_ORIGIN_TOP_LEFT ); + BIND_CONSTANT( TILE_ORIGIN_CENTER ); } @@ -906,9 +1133,12 @@ TileMap::TileMap() { mode=MODE_SQUARE; half_offset=HALF_OFFSET_DISABLED; use_kinematic=false; + navigation=NULL; + y_sort_mode=false; fp_adjust=0.01; fp_adjust=0.01; + tile_origin=TILE_ORIGIN_TOP_LEFT; } TileMap::~TileMap() { diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index fe1067fc1d..3facc9e8b7 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -30,6 +30,7 @@ #define TILE_MAP_H #include "scene/2d/node_2d.h" +#include "scene/2d/navigation2d.h" #include "scene/resources/tile_set.h" #include "self_list.h" #include "vset.h" @@ -51,6 +52,12 @@ public: HALF_OFFSET_DISABLED, }; + enum TileOrigin { + TILE_ORIGIN_TOP_LEFT, + TILE_ORIGIN_CENTER + }; + + private: Ref tile_set; @@ -61,6 +68,7 @@ private: Matrix32 custom_transform; HalfOffset half_offset; bool use_kinematic; + Navigation2D *navigation; union PosKey { @@ -98,15 +106,29 @@ private: struct Quadrant { Vector2 pos; - RID canvas_item; + List canvas_items; RID body; SelfList dirty_list; + struct NavPoly { + int id; + Matrix32 xform; + }; + + struct Occluder { + RID id; + Matrix32 xform; + }; + + + Map navpoly_ids; + Map occluder_instances; + VSet cells; - void operator=(const Quadrant& q) { pos=q.pos; canvas_item=q.canvas_item; body=q.body; cells=q.cells; } - Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_item=q.canvas_item; body=q.body; cells=q.cells;} + void operator=(const Quadrant& q) { pos=q.pos; canvas_items=q.canvas_items; body=q.body; cells=q.cells; navpoly_ids=q.navpoly_ids; occluder_instances=q.occluder_instances; } + Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_items=q.canvas_items; body=q.body; cells=q.cells; occluder_instances=q.occluder_instances; navpoly_ids=q.navpoly_ids;} Quadrant() : dirty_list(this) {} }; @@ -119,11 +141,14 @@ private: Rect2 rect_cache; bool rect_cache_dirty; bool quadrant_order_dirty; + bool y_sort_mode; float fp_adjust; float friction; float bounce; uint32_t collision_layer; + TileOrigin tile_origin; + void _fix_cell_transform(Matrix32& xform, const Cell& c, Vector2 &offset, const Size2 &s); Map::Element *_create_quadrant(const PosKey& p_qk); void _erase_quadrant(Map::Element *Q); @@ -135,6 +160,9 @@ private: void _update_quadrant_transform(); void _recompute_rect_cache(); + _FORCE_INLINE_ int _get_quadrant_size() const; + + void _set_tile_data(const DVector& p_data); DVector _get_tile_data() const; @@ -195,6 +223,9 @@ public: void set_half_offset(HalfOffset p_half_offset); HalfOffset get_half_offset() const; + void set_tile_origin(TileOrigin p_tile_origin); + TileOrigin get_tile_origin() const; + void set_custom_transform(const Matrix32& p_xform); Matrix32 get_custom_transform() const; @@ -204,6 +235,9 @@ public: Vector2 map_to_world(const Vector2& p_pos, bool p_ignore_ofs=false) const; Vector2 world_to_map(const Vector2& p_pos) const; + void set_y_sort_mode(bool p_enable); + bool is_y_sort_mode_enabled() const; + void clear(); TileMap(); @@ -212,5 +246,6 @@ public: VARIANT_ENUM_CAST(TileMap::Mode); VARIANT_ENUM_CAST(TileMap::HalfOffset); +VARIANT_ENUM_CAST(TileMap::TileOrigin); #endif // TILE_MAP_H diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 22534eeb0e..cd3c788b65 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -32,6 +32,7 @@ #include "scene/2d/physics_body_2d.h" #include "scene/animation/animation_player.h" #include "scene/scene_string_names.h" +#include "particles_2d.h" void VisibilityNotifier2D::_enter_viewport(Viewport* p_viewport) { @@ -188,6 +189,15 @@ void VisibilityEnabler2D::_find_nodes(Node* p_node) { } + if (enabler[ENABLER_PAUSE_PARTICLES]) { + + Particles2D *ps = p_node->cast_to(); + if (ps) { + add=true; + } + + } + if (add) { p_node->connect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); @@ -271,6 +281,15 @@ void VisibilityEnabler2D::_change_node_state(Node* p_node,bool p_enabled) { } } + { + Particles2D *ps=p_node->cast_to(); + + if (ps) { + + ps->set_emitting(p_enabled); + } + } + } @@ -292,9 +311,11 @@ void VisibilityEnabler2D::_bind_methods(){ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animations"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS ); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/freeze_bodies"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_particles"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_PARTICLES); BIND_CONSTANT( ENABLER_FREEZE_BODIES ); BIND_CONSTANT( ENABLER_PAUSE_ANIMATIONS ); + BIND_CONSTANT( ENABLER_PAUSE_PARTICLES ); BIND_CONSTANT( ENABLER_MAX); } @@ -320,3 +341,4 @@ VisibilityEnabler2D::VisibilityEnabler2D() { } + diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index cdf52ecb27..621c470d5d 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -73,6 +73,7 @@ public: enum Enabler { ENABLER_PAUSE_ANIMATIONS, ENABLER_FREEZE_BODIES, + ENABLER_PAUSE_PARTICLES, ENABLER_MAX }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index a8070be91d..86f442fd8c 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -940,67 +940,67 @@ void Control::_window_input_event(InputEvent p_event) { case InputEvent::MOUSE_BUTTON: { - window->key_event_accepted=false; + window->key_event_accepted=false; - Point2 mpos =(get_canvas_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y)); - if (p_event.mouse_button.pressed) { + Point2 mpos =(get_canvas_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y)); + if (p_event.mouse_button.pressed) { - Size2 pos = mpos; - if (window->mouse_focus && p_event.mouse_button.button_index!=window->mouse_focus_button) { + Size2 pos = mpos; + if (window->mouse_focus && p_event.mouse_button.button_index!=window->mouse_focus_button) { - //do not steal mouse focus and stuff + //do not steal mouse focus and stuff - } else { + } else { - _window_sort_modal_stack(); - while (!window->modal_stack.empty()) { + _window_sort_modal_stack(); + while (!window->modal_stack.empty()) { - Control *top = window->modal_stack.back()->get(); - if (!top->has_point(top->get_global_transform().affine_inverse().xform(pos))) { + Control *top = window->modal_stack.back()->get(); + if (!top->has_point(top->get_global_transform().affine_inverse().xform(pos))) { - if (top->data.modal_exclusive) { - //cancel event, sorry, modal exclusive EATS UP ALL - get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); - get_tree()->set_input_as_handled(); - return; // no one gets the event if exclusive NO ONE - } + if (top->data.modal_exclusive) { + //cancel event, sorry, modal exclusive EATS UP ALL + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->set_input_as_handled(); + return; // no one gets the event if exclusive NO ONE + } - top->notification(NOTIFICATION_MODAL_CLOSE); - top->_modal_stack_remove(); - top->hide(); - } else { - break; + top->notification(NOTIFICATION_MODAL_CLOSE); + top->_modal_stack_remove(); + top->hide(); + } else { + break; + } } - } - Matrix32 parent_xform; + Matrix32 parent_xform; - if (data.parent_canvas_item) - parent_xform=data.parent_canvas_item->get_global_transform(); + if (data.parent_canvas_item) + parent_xform=data.parent_canvas_item->get_global_transform(); - window->mouse_focus = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform); - //print_line("has mf "+itos(window->mouse_focus!=NULL)); - window->mouse_focus_button=p_event.mouse_button.button_index; + window->mouse_focus = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform); + //print_line("has mf "+itos(window->mouse_focus!=NULL)); + window->mouse_focus_button=p_event.mouse_button.button_index; - if (!window->mouse_focus) { - break; - } + if (!window->mouse_focus) { + break; + } - if (p_event.mouse_button.button_index==BUTTON_LEFT) { - window->drag_accum=Vector2(); - window->drag_attempted=false; - window->drag_data=Variant(); - } + if (p_event.mouse_button.button_index==BUTTON_LEFT) { + window->drag_accum=Vector2(); + window->drag_attempted=false; + window->drag_data=Variant(); + } - } + } p_event.mouse_button.global_x = pos.x; p_event.mouse_button.global_y = pos.y; @@ -1020,8 +1020,8 @@ void Control::_window_input_event(InputEvent p_event) { /*if (bool(GLOBAL_DEF("debug/print_clicked_control",false))) { - print_line(String(window->mouse_focus->get_path())+" - "+pos); - }*/ + print_line(String(window->mouse_focus->get_path())+" - "+pos); + }*/ #endif if (window->mouse_focus->get_focus_mode()!=FOCUS_NONE && window->mouse_focus!=window->key_focus && p_event.mouse_button.button_index==BUTTON_LEFT) { @@ -1033,10 +1033,12 @@ void Control::_window_input_event(InputEvent p_event) { if (window->mouse_focus->can_process()) { _window_call_input(window->mouse_focus,p_event); } - + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); get_tree()->set_input_as_handled(); + window->tooltip_popup->hide(); + } else { if (window->drag_preview && p_event.mouse_button.button_index==BUTTON_LEFT) { diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 208ba5bb66..338804e0e1 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -46,6 +46,8 @@ bool TileSet::_set(const StringName& p_name, const Variant& p_value) { tile_set_texture(id,p_value); else if (what=="tex_offset") tile_set_texture_offset(id,p_value); + else if (what=="material") + tile_set_material(id,p_value); else if (what=="shape_offset") tile_set_shape_offset(id,p_value); else if (what=="region") @@ -54,6 +56,14 @@ bool TileSet::_set(const StringName& p_name, const Variant& p_value) { tile_set_shape(id,p_value); else if (what=="shapes") _tile_set_shapes(id,p_value); + else if (what=="occluder") + tile_set_light_occluder(id,p_value); + else if (what=="occluder_offset") + tile_set_occluder_offset(id,p_value); + else if (what=="navigation") + tile_set_navigation_polygon(id,p_value); + else if (what=="navigation_offset") + tile_set_navigation_polygon_offset(id,p_value); else return false; @@ -79,6 +89,8 @@ bool TileSet::_get(const StringName& p_name,Variant &r_ret) const{ r_ret=tile_get_texture(id); else if (what=="tex_offset") r_ret=tile_get_texture_offset(id); + else if (what=="material") + r_ret=tile_get_material(id); else if (what=="shape_offset") r_ret=tile_get_shape_offset(id); else if (what=="region") @@ -87,6 +99,14 @@ bool TileSet::_get(const StringName& p_name,Variant &r_ret) const{ r_ret=tile_get_shape(id); else if (what=="shapes") r_ret=_tile_get_shapes(id); + else if (what=="occluder") + r_ret=tile_get_light_occluder(id); + else if (what=="occluder_offset") + r_ret=tile_get_occluder_offset(id); + else if (what=="navigation") + r_ret=tile_get_navigation_polygon(id); + else if (what=="navigation_offset") + r_ret=tile_get_navigation_polygon_offset(id); else return false; @@ -103,8 +123,13 @@ void TileSet::_get_property_list( List *p_list) const{ p_list->push_back(PropertyInfo(Variant::STRING,pre+"name")); p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture")); p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"tex_offset")); - p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"shape_offset")); + p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"material",PROPERTY_HINT_RESOURCE_TYPE,"CanvasItemMaterial")); p_list->push_back(PropertyInfo(Variant::RECT2,pre+"region")); + p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"occluder_offset")); + p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D")); + p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"navigation_offset")); + p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"navigation",PROPERTY_HINT_RESOURCE_TYPE,"NavigationPolygon")); + p_list->push_back(PropertyInfo(Variant::VECTOR2,pre+"shape_offset")); p_list->push_back(PropertyInfo(Variant::OBJECT,pre+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::ARRAY,pre+"shapes",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR)); } @@ -134,6 +159,22 @@ Ref TileSet::tile_get_texture(int p_id) const { } + +void TileSet::tile_set_material(int p_id,const Ref &p_material) { + + ERR_FAIL_COND(!tile_map.has(p_id)); + tile_map[p_id].material=p_material; + emit_changed(); + +} + +Ref TileSet::tile_get_material(int p_id) const{ + + ERR_FAIL_COND_V(!tile_map.has(p_id),Ref()); + return tile_map[p_id].material; +} + + void TileSet::tile_set_texture_offset(int p_id,const Vector2 &p_offset) { ERR_FAIL_COND(!tile_map.has(p_id)); @@ -210,6 +251,58 @@ Ref TileSet::tile_get_shape(int p_id) const { } +void TileSet::tile_set_light_occluder(int p_id,const Ref &p_light_occluder) { + + ERR_FAIL_COND(!tile_map.has(p_id)); + tile_map[p_id].occluder=p_light_occluder; + +} + +Ref TileSet::tile_get_light_occluder(int p_id) const{ + + ERR_FAIL_COND_V(!tile_map.has(p_id),Ref()); + return tile_map[p_id].occluder; + +} + +void TileSet::tile_set_navigation_polygon_offset(int p_id,const Vector2& p_offset) { + + ERR_FAIL_COND(!tile_map.has(p_id)); + tile_map[p_id].navigation_polygon_offset=p_offset; + +} + +Vector2 TileSet::tile_get_navigation_polygon_offset(int p_id) const{ + ERR_FAIL_COND_V(!tile_map.has(p_id),Vector2()); + return tile_map[p_id].navigation_polygon_offset; +} + +void TileSet::tile_set_navigation_polygon(int p_id,const Ref &p_navigation_polygon) { + + ERR_FAIL_COND(!tile_map.has(p_id)); + tile_map[p_id].navigation_polygon=p_navigation_polygon; + +} + +Ref TileSet::tile_get_navigation_polygon(int p_id) const { + + ERR_FAIL_COND_V(!tile_map.has(p_id),Ref()); + return tile_map[p_id].navigation_polygon; + +} + +void TileSet::tile_set_occluder_offset(int p_id,const Vector2& p_offset) { + + ERR_FAIL_COND(!tile_map.has(p_id)); + tile_map[p_id].occluder_offset=p_offset; + +} + +Vector2 TileSet::tile_get_occluder_offset(int p_id) const{ + ERR_FAIL_COND_V(!tile_map.has(p_id),Vector2()); + return tile_map[p_id].occluder_offset; +} + void TileSet::tile_set_shapes(int p_id,const Vector > &p_shapes) { ERR_FAIL_COND(!tile_map.has(p_id)); @@ -319,6 +412,8 @@ void TileSet::_bind_methods() { ObjectTypeDB::bind_method(_MD("tile_get_name","id"),&TileSet::tile_get_name); ObjectTypeDB::bind_method(_MD("tile_set_texture","id","texture:Texture"),&TileSet::tile_set_texture); ObjectTypeDB::bind_method(_MD("tile_get_texture:Texture","id"),&TileSet::tile_get_texture); + ObjectTypeDB::bind_method(_MD("tile_set_material","id","material:CanvasItemMaterial"),&TileSet::tile_set_material); + ObjectTypeDB::bind_method(_MD("tile_get_material:CanvasItemMaterial","id"),&TileSet::tile_get_material); ObjectTypeDB::bind_method(_MD("tile_set_texture_offset","id","texture_offset"),&TileSet::tile_set_texture_offset); ObjectTypeDB::bind_method(_MD("tile_get_texture_offset","id"),&TileSet::tile_get_texture_offset); ObjectTypeDB::bind_method(_MD("tile_set_shape_offset","id","shape_offset"),&TileSet::tile_set_shape_offset); @@ -329,6 +424,15 @@ void TileSet::_bind_methods() { ObjectTypeDB::bind_method(_MD("tile_get_shape:Shape2D","id"),&TileSet::tile_get_shape); ObjectTypeDB::bind_method(_MD("tile_set_shapes","id","shapes"),&TileSet::_tile_set_shapes); ObjectTypeDB::bind_method(_MD("tile_get_shapes","id"),&TileSet::_tile_get_shapes); + ObjectTypeDB::bind_method(_MD("tile_set_navigation_polygon","id","navigation_polygon:NavigationPolygon"),&TileSet::tile_set_navigation_polygon); + ObjectTypeDB::bind_method(_MD("tile_get_navigation_polygon:NavigationPolygon","id"),&TileSet::tile_get_navigation_polygon); + ObjectTypeDB::bind_method(_MD("tile_set_navigation_polygon_offset","id","navigation_polygon_offset"),&TileSet::tile_set_navigation_polygon_offset); + ObjectTypeDB::bind_method(_MD("tile_get_navigation_polygon_offset","id"),&TileSet::tile_get_navigation_polygon_offset); + ObjectTypeDB::bind_method(_MD("tile_set_light_occluder","id","light_occluder:OccluderPolygon2D"),&TileSet::tile_set_light_occluder); + ObjectTypeDB::bind_method(_MD("tile_get_light_occluder:OccluderPolygon2D","id"),&TileSet::tile_get_light_occluder); + ObjectTypeDB::bind_method(_MD("tile_set_occluder_offset","id","occluder_offset"),&TileSet::tile_set_occluder_offset); + ObjectTypeDB::bind_method(_MD("tile_get_occluder_offset","id"),&TileSet::tile_get_occluder_offset); + ObjectTypeDB::bind_method(_MD("remove_tile","id"),&TileSet::remove_tile); ObjectTypeDB::bind_method(_MD("clear"),&TileSet::clear); ObjectTypeDB::bind_method(_MD("get_last_unused_tile_id"),&TileSet::get_last_unused_tile_id); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index ddbb1b59a6..0234755a53 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -32,6 +32,8 @@ #include "resource.h" #include "scene/resources/shape_2d.h" #include "scene/resources/texture.h" +#include "scene/2d/light_occluder_2d.h" +#include "scene/2d/navigation_polygon.h" class TileSet : public Resource { @@ -45,6 +47,11 @@ class TileSet : public Resource { Vector2 shape_offset; Rect2i region; Vector > shapes; + Vector2 occluder_offset; + Ref occluder; + Vector2 navigation_polygon_offset; + Ref navigation_polygon; + Ref material; }; Map tile_map; @@ -84,6 +91,21 @@ public: void tile_set_shape(int p_id,const Ref &p_shape); Ref tile_get_shape(int p_id) const; + void tile_set_material(int p_id,const Ref &p_material); + Ref tile_get_material(int p_id) const; + + void tile_set_occluder_offset(int p_id,const Vector2& p_offset); + Vector2 tile_get_occluder_offset(int p_id) const; + + void tile_set_light_occluder(int p_id,const Ref &p_light_occluder); + Ref tile_get_light_occluder(int p_id) const; + + void tile_set_navigation_polygon_offset(int p_id,const Vector2& p_offset); + Vector2 tile_get_navigation_polygon_offset(int p_id) const; + + void tile_set_navigation_polygon(int p_id,const Ref &p_navigation_polygon); + Ref tile_get_navigation_polygon(int p_id) const; + void tile_set_shapes(int p_id,const Vector > &p_shapes); Vector > tile_get_shapes(int p_id) const; -- cgit v1.2.3