summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/canvas_item.cpp21
-rw-r--r--scene/2d/line_2d.cpp3
-rw-r--r--scene/2d/particles_2d.cpp30
-rw-r--r--scene/2d/particles_2d.h4
-rw-r--r--scene/2d/sprite.cpp2
-rw-r--r--scene/2d/tile_map.cpp19
-rw-r--r--scene/3d/particles.cpp29
-rw-r--r--scene/3d/particles.h5
-rw-r--r--scene/3d/physics_body.cpp2
-rw-r--r--scene/3d/sprite_3d.cpp4
-rw-r--r--scene/animation/tween.cpp2
-rw-r--r--scene/gui/graph_node.cpp2
-rw-r--r--scene/gui/tree.cpp153
-rw-r--r--scene/gui/tree.h22
-rw-r--r--scene/resources/curve.cpp4
-rw-r--r--scene/resources/material.cpp12
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/texture.cpp2
-rw-r--r--scene/resources/tile_set.cpp210
-rw-r--r--scene/resources/tile_set.h48
20 files changed, 452 insertions, 124 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 189dd66a26..4a80aba355 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "canvas_item.h"
-#include "core/method_bind_ext.inc"
+#include "core/method_bind_ext.gen.inc"
#include "message_queue.h"
#include "os/input.h"
#include "scene/main/canvas_layer.h"
@@ -96,8 +96,8 @@ void CanvasItemMaterial::_update_shader() {
switch (light_mode) {
case LIGHT_MODE_NORMAL: break;
- case LIGHT_MODE_UNSHADED: code += "unshaded"; break;
- case LIGHT_MODE_LIGHT_ONLY: code += "light_only"; break;
+ case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
+ case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
}
code += ";\n"; //thats it.
@@ -367,7 +367,9 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const {
}
Transform2D CanvasItem::get_global_transform() const {
-
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
+#endif
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
@@ -765,8 +767,9 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const
void CanvasItem::_notify_transform(CanvasItem *p_node) {
- if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid)
+ if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
return; //nothing to do
+ }
p_node->global_invalid = true;
@@ -1067,7 +1070,15 @@ bool CanvasItem::is_local_transform_notification_enabled() const {
}
void CanvasItem::set_notify_transform(bool p_enable) {
+ if (notify_transform == p_enable)
+ return;
+
notify_transform = p_enable;
+
+ if (notify_transform && is_inside_tree()) {
+ //this ensures that invalid globals get resolved, so notifications can be received
+ get_global_transform();
+ }
}
bool CanvasItem::is_transform_notification_enabled() const {
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 1a57d24342..5438557d0b 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -310,12 +310,15 @@ void Line2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color");
+ ADD_GROUP("Fill", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile"), "set_texture_mode", "get_texture_mode");
+ ADD_GROUP("Capping", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode");
+ ADD_GROUP("Border", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "sharp_limit"), "set_sharp_limit", "get_sharp_limit");
ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision");
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index beff247264..aa9258c7b4 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -50,6 +50,12 @@ void Particles2D::set_lifetime(float p_lifetime) {
lifetime = p_lifetime;
VS::get_singleton()->particles_set_lifetime(particles, lifetime);
}
+
+void Particles2D::set_one_shot(bool p_enable) {
+
+ one_shot = p_enable;
+ VS::get_singleton()->particles_set_one_shot(particles, one_shot);
+}
void Particles2D::set_pre_process_time(float p_time) {
pre_process_time = p_time;
@@ -84,7 +90,7 @@ void Particles2D::set_use_local_coordinates(bool p_enable) {
local_coords = p_enable;
VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
set_notify_transform(!p_enable);
- if (!p_enable) {
+ if (!p_enable && is_inside_tree()) {
_update_particle_emission_transform();
}
}
@@ -135,6 +141,11 @@ float Particles2D::get_lifetime() const {
return lifetime;
}
+
+bool Particles2D::get_one_shot() const {
+
+ return one_shot;
+}
float Particles2D::get_pre_process_time() const {
return pre_process_time;
@@ -264,6 +275,10 @@ int Particles2D::get_h_frames() const {
return h_frames;
}
+void Particles2D::restart() {
+ VS::get_singleton()->particles_restart(particles);
+}
+
void Particles2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
@@ -295,6 +310,7 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot);
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
@@ -308,6 +324,7 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot);
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
@@ -335,18 +352,22 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames);
ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
- ADD_GROUP("Parameters", "");
+ ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
- ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
ADD_GROUP("Process Material", "process_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
@@ -365,6 +386,7 @@ Particles2D::Particles2D() {
particles = VS::get_singleton()->particles_create();
set_emitting(true);
+ set_one_shot(false);
set_amount(8);
set_lifetime(1);
set_fixed_fps(0);
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index ab7dcb1464..23278ce746 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -48,6 +48,7 @@ private:
RID particles;
bool emitting;
+ bool one_shot;
int amount;
float lifetime;
float pre_process_time;
@@ -79,6 +80,7 @@ public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
void set_lifetime(float p_lifetime);
+ void set_one_shot(bool p_enabled);
void set_pre_process_time(float p_time);
void set_explosiveness_ratio(float p_ratio);
void set_randomness_ratio(float p_ratio);
@@ -90,6 +92,7 @@ public:
bool is_emitting() const;
int get_amount() const;
float get_lifetime() const;
+ bool get_one_shot() const;
float get_pre_process_time() const;
float get_explosiveness_ratio() const;
float get_randomness_ratio() const;
@@ -121,6 +124,7 @@ public:
void set_h_frames(int p_count);
int get_h_frames() const;
+ void restart();
Rect2 capture_rect() const;
Particles2D();
~Particles2D();
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index ff574a6bd6..450f8e2474 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -351,10 +351,12 @@ void Sprite::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+ ADD_GROUP("Offset", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
+ ADD_GROUP("Animation", "");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 4f892a31fc..57e25ec609 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "tile_map.h"
#include "io/marshalls.h"
-#include "method_bind_ext.inc"
+#include "method_bind_ext.gen.inc"
#include "os/os.h"
#include "servers/physics_2d_server.h"
@@ -441,35 +441,36 @@ void TileMap::_update_dirty_quadrants() {
rect.position.y -= center.y;
}
+ Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id);
Color modulate = tile_set->tile_get_modulate(c.id);
Color self_modulate = get_self_modulate();
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()) {
- tex->draw_rect(canvas_item, rect, false, modulate, c.transpose);
+ tex->draw_rect(canvas_item, rect, false, modulate, c.transpose, normal_map);
} else {
- tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose);
+ tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map);
}
- Vector<Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
+ Vector<TileSet::ShapeData> shapes = tile_set->tile_get_shapes(c.id);
for (int i = 0; i < shapes.size(); i++) {
- Ref<Shape2D> shape = shapes[i];
+ Ref<Shape2D> shape = shapes[i].shape;
if (shape.is_valid()) {
-
- Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id);
Transform2D xform;
xform.set_origin(offset.floor());
- _fix_cell_transform(xform, c, shape_ofs + center_ofs, s);
+ _fix_cell_transform(xform, c, shapes[i].shape_offset + center_ofs, s);
if (debug_canvas_item.is_valid()) {
vs->canvas_item_add_set_transform(debug_canvas_item, xform);
shape->draw(debug_canvas_item, debug_collision_color);
}
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));
+ shape_idx++;
+ ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[i].one_way_collision);
+ ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
}
}
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 722b698b75..c291aa33ed 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -58,6 +58,13 @@ void Particles::set_lifetime(float p_lifetime) {
lifetime = p_lifetime;
VS::get_singleton()->particles_set_lifetime(particles, lifetime);
}
+
+void Particles::set_one_shot(bool p_one_shot) {
+
+ one_shot = p_one_shot;
+ VS::get_singleton()->particles_set_one_shot(particles, one_shot);
+}
+
void Particles::set_pre_process_time(float p_time) {
pre_process_time = p_time;
@@ -114,6 +121,11 @@ float Particles::get_lifetime() const {
return lifetime;
}
+bool Particles::get_one_shot() const {
+
+ return one_shot;
+}
+
float Particles::get_pre_process_time() const {
return pre_process_time;
@@ -233,6 +245,11 @@ String Particles::get_configuration_warning() const {
return warnings;
}
+void Particles::restart() {
+
+ VisualServer::get_singleton()->particles_restart(particles);
+}
+
Rect3 Particles::capture_aabb() const {
return VS::get_singleton()->particles_get_current_aabb(particles);
@@ -254,6 +271,7 @@ void Particles::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount);
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Particles::set_one_shot);
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time);
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio);
@@ -267,6 +285,7 @@ void Particles::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount);
ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles::get_one_shot);
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time);
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio);
@@ -287,20 +306,23 @@ void Particles::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes);
ClassDB::bind_method(D_METHOD("get_draw_pass_mesh:Mesh", "pass"), &Particles::get_draw_pass_mesh);
+ ClassDB::bind_method(D_METHOD("restart"), &Particles::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
- ADD_GROUP("Parameters", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
- ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
@@ -322,6 +344,7 @@ Particles::Particles() {
particles = VS::get_singleton()->particles_create();
set_base(particles);
set_emitting(true);
+ set_one_shot(false);
set_amount(8);
set_lifetime(1);
set_fixed_fps(0);
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index dad8ed4585..0549eb4c09 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -58,6 +58,7 @@ private:
RID particles;
bool emitting;
+ bool one_shot;
int amount;
float lifetime;
float pre_process_time;
@@ -86,6 +87,7 @@ public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
void set_lifetime(float p_lifetime);
+ void set_one_shot(bool p_enabled);
void set_pre_process_time(float p_time);
void set_explosiveness_ratio(float p_ratio);
void set_randomness_ratio(float p_ratio);
@@ -97,6 +99,7 @@ public:
bool is_emitting() const;
int get_amount() const;
float get_lifetime() const;
+ bool get_one_shot() const;
float get_pre_process_time() const;
float get_explosiveness_ratio() const;
float get_randomness_ratio() const;
@@ -122,6 +125,8 @@ public:
virtual String get_configuration_warning() const;
+ void restart();
+
Rect3 capture_aabb() const;
Particles();
~Particles();
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 3a55a2bc32..2a7a804470 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "physics_body.h"
-#include "method_bind_ext.inc"
+#include "method_bind_ext.gen.inc"
#include "scene/scene_string_names.h"
void PhysicsBody::_notification(int p_what) {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index b6c59ba277..78e8e92afc 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -581,10 +581,12 @@ void Sprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_GROUP("Animation", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region"), "set_region", "is_region");
+ ADD_GROUP("Region", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_SIGNAL(MethodInfo("frame_changed"));
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 67920d177e..ad0b0fbfb2 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "tween.h"
-#include "method_bind_ext.inc"
+#include "method_bind_ext.gen.inc"
void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8, const Variant &p_arg9, const Variant &p_arg10) {
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 95f65f31d6..538dd846e4 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "graph_node.h"
-#include "method_bind_ext.inc"
+#include "method_bind_ext.gen.inc"
bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index d864d9fce7..d8788b4eca 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -622,6 +622,40 @@ bool TreeItem::is_custom_set_as_button(int p_column) const {
return cells[p_column].custom_button;
}
+void TreeItem::set_text_align(int p_column, TextAlign p_align) {
+ ERR_FAIL_INDEX(p_column, cells.size());
+ cells[p_column].text_align = p_align;
+ _changed_notify(p_column);
+}
+
+TreeItem::TextAlign TreeItem::get_text_align(int p_column) const {
+ ERR_FAIL_INDEX_V(p_column, cells.size(), ALIGN_LEFT);
+ return cells[p_column].text_align;
+}
+
+void TreeItem::set_expand_right(int p_column, bool p_enable) {
+
+ ERR_FAIL_INDEX(p_column, cells.size());
+ cells[p_column].expand_right = p_enable;
+ _changed_notify(p_column);
+}
+
+bool TreeItem::get_expand_right(int p_column) const {
+
+ ERR_FAIL_INDEX_V(p_column, cells.size(), false);
+ return cells[p_column].expand_right;
+}
+
+void TreeItem::set_disable_folding(bool p_disable) {
+
+ disable_folding = p_disable;
+ _changed_notify(0);
+}
+
+bool TreeItem::is_folding_disabled() const {
+ return disable_folding;
+}
+
void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell_mode", "column", "mode"), &TreeItem::set_cell_mode);
@@ -692,12 +726,19 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button);
ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
+ ClassDB::bind_method(D_METHOD("set_expand_right", "column", "enable"), &TreeItem::set_expand_right);
+ ClassDB::bind_method(D_METHOD("get_expand_right", "column"), &TreeItem::get_expand_right);
+
ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip);
ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip);
-
+ ClassDB::bind_method(D_METHOD("set_text_align", "column", "text_align"), &TreeItem::set_text_align);
+ ClassDB::bind_method(D_METHOD("get_text_align", "column"), &TreeItem::get_text_align);
ClassDB::bind_method(D_METHOD("move_to_top"), &TreeItem::move_to_top);
ClassDB::bind_method(D_METHOD("move_to_bottom"), &TreeItem::move_to_bottom);
+ ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
+ ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
+
BIND_CONSTANT(CELL_MODE_STRING);
BIND_CONSTANT(CELL_MODE_CHECK);
BIND_CONSTANT(CELL_MODE_RANGE);
@@ -724,6 +765,7 @@ TreeItem::TreeItem(Tree *p_tree) {
tree = p_tree;
collapsed = false;
+ disable_folding = false;
parent = 0; // parent item
next = 0; // next in list
@@ -894,6 +936,32 @@ int Tree::get_item_height(TreeItem *p_item) const {
void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color) {
Rect2i rect = p_rect;
+ Ref<Font> font = cache.font;
+ String text = p_cell.text;
+ if (p_cell.suffix != String())
+ text += " " + p_cell.suffix;
+
+ int w = 0;
+ if (!p_cell.icon.is_null()) {
+ Size2i bmsize = p_cell.get_icon_size();
+
+ if (p_cell.icon_max_w > 0 && bmsize.width > p_cell.icon_max_w) {
+ bmsize.width = p_cell.icon_max_w;
+ }
+ w += bmsize.width + cache.hseparation;
+ }
+ w += font->get_string_size(text).width;
+
+ switch (p_cell.text_align) {
+ case TreeItem::ALIGN_LEFT:
+ break; //do none
+ case TreeItem::ALIGN_CENTER:
+ rect.position.x = MAX(0, (rect.size.width - w) / 2);
+ break; //do none
+ case TreeItem::ALIGN_RIGHT:
+ rect.position.x = MAX(0, (rect.size.width - w));
+ break; //do none
+ }
RID ci = get_canvas_item();
if (!p_cell.icon.is_null()) {
@@ -914,12 +982,6 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co
rect.size.x-=Math::floor(rect.size.y/2);
*/
- Ref<Font> font = cache.font;
-
- String text = p_cell.text;
- if (p_cell.suffix != String())
- text += " " + p_cell.suffix;
-
rect.position.y += Math::floor((rect.size.y - font->get_height()) / 2.0) + font->get_ascent();
font->draw(ci, rect.position, text, p_color, rect.size.x);
}
@@ -970,20 +1032,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (!skip && (p_pos.y + label_h - cache.offset.y) > 0) {
- if (!hide_folding && p_item->childs) { //has childs, draw the guide box
-
- Ref<Texture> arrow;
-
- if (p_item->collapsed) {
-
- arrow = cache.arrow_collapsed;
- } else {
- arrow = cache.arrow;
- }
-
- arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset);
- }
-
//draw separation.
//if (p_item->get_parent()!=root || !hide_root)
@@ -991,9 +1039,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int font_ascent = font->get_ascent();
- int ofs = p_pos.x + (hide_folding ? cache.hseparation : cache.item_margin);
+ int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
+ int skip = 0;
for (int i = 0; i < columns.size(); i++) {
+ if (skip) {
+ skip--;
+ continue;
+ }
+
int w = get_column_width(i);
if (i == 0) {
@@ -1011,6 +1065,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
w -= cache.hseparation;
}
+ if (p_item->cells[i].expand_right) {
+
+ int plus = 1;
+ while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) {
+ w += get_column_width(i + plus);
+ plus++;
+ skip++;
+ }
+ }
+
int bw = 0;
for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) {
Ref<Texture> b = p_item->cells[i].buttons[j].texture;
@@ -1076,8 +1140,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (p_item->cells[i].custom_bg_color) {
Rect2 r = cell_rect;
- r.position.x -= cache.hseparation;
- r.size.x += cache.hseparation;
+ if (i == 0) {
+ r.position.x = p_draw_ofs.x;
+ r.size.x = w + ofs;
+ } else {
+ r.position.x -= cache.hseparation;
+ r.size.x += cache.hseparation;
+ }
if (p_item->cells[i].custom_bg_outline) {
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), p_item->cells[i].bg_color);
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y - 1, r.size.x, 1), p_item->cells[i].bg_color);
@@ -1274,6 +1343,19 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
+ if (!p_item->disable_folding && !hide_folding && p_item->childs) { //has childs, draw the guide box
+
+ Ref<Texture> arrow;
+
+ if (p_item->collapsed) {
+
+ arrow = cache.arrow_collapsed;
+ } else {
+ arrow = cache.arrow;
+ }
+
+ arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset);
+ }
//separator
//get_painter()->draw_fill_rect( Point2i(0,pos.y),Size2i(get_size().width,1),color( COLOR_TREE_GRID) );
@@ -1295,8 +1377,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
while (c) {
if (cache.draw_relationship_lines == 1) {
- int root_ofs = children_pos.x + (hide_folding ? cache.hseparation : cache.item_margin);
- int parent_ofs = p_pos.x + (hide_folding ? cache.hseparation : cache.item_margin);
+ int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
+ int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
if (c->get_children() != NULL)
root_pos -= Point2i(cache.arrow->get_width(), 0);
@@ -1488,7 +1570,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
return -1;
}
- if (!hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
+ if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
if (p_item->childs)
p_item->set_collapsed(!p_item->is_collapsed());
@@ -1504,6 +1586,18 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
for (int i = 0; i < columns.size(); i++) {
col_width = get_column_width(i);
+
+ if (p_item->cells[i].expand_right) {
+
+ int plus = 1;
+ while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) {
+ plus++;
+ col_width += cache.hseparation;
+ col_width += get_column_width(i + plus);
+ plus++;
+ }
+ }
+
if (x > col_width) {
col_ofs += col_width;
x -= col_width;
@@ -1528,6 +1622,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
x -= cache.hseparation;
}
+ if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_children()) {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ return -1; //collapse/uncollapse because nothing can be done with item
+ }
+
TreeItem::Cell &c = p_item->cells[col];
bool already_selected = c.selected;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 097e0110e8..59e35bb230 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -58,6 +58,12 @@ public:
CELL_MODE_CUSTOM, ///< Contains a custom value, show a string, and an edit button
};
+ enum TextAlign {
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT
+ };
+
private:
friend class Tree;
@@ -82,6 +88,9 @@ private:
bool custom_bg_outline;
Color bg_color;
bool custom_button;
+ bool expand_right;
+
+ TextAlign text_align;
Variant meta;
String tooltip;
@@ -122,6 +131,8 @@ private:
custom_bg_color = false;
expr = false;
icon_max_w = 0;
+ text_align = ALIGN_LEFT;
+ expand_right = false;
}
Size2 get_icon_size() const;
@@ -131,6 +142,7 @@ private:
Vector<Cell> cells;
bool collapsed; // wont show childs
+ bool disable_folding;
TreeItem *parent; // parent item
TreeItem *next; // next in list
@@ -248,13 +260,23 @@ public:
void clear_children();
+ void set_text_align(int p_column, TextAlign p_align);
+ TextAlign get_text_align(int p_column) const;
+
+ void set_expand_right(int p_column, bool p_enable);
+ bool get_expand_right(int p_column) const;
+
void move_to_top();
void move_to_bottom();
+ void set_disable_folding(bool p_disable);
+ bool is_folding_disabled() const;
+
~TreeItem();
};
VARIANT_ENUM_CAST(TreeItem::TreeCellMode);
+VARIANT_ENUM_CAST(TreeItem::TextAlign);
class Tree : public Control {
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 006e7de562..3957923c6a 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -720,8 +720,8 @@ void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points);
ClassDB::bind_method(D_METHOD("get_point_pos", "index"), &Curve::get_point_pos);
- ClassDB::bind_method(D_METHOD("set_point_value", "index, y"), &Curve::set_point_value);
- ClassDB::bind_method(D_METHOD("set_point_offset", "index, offset"), &Curve::set_point_value);
+ ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value);
+ ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_value);
ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate);
ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked);
ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index ce88325539..0912c70144 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -1232,17 +1232,17 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "albedo_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ALBEDO);
ADD_GROUP("Metallic", "metallic_");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_metallic", "get_metallic");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_metallic", "get_metallic");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular", "get_specular");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "metallic_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_METALLIC);
ADD_GROUP("Roughness", "roughness_");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "roughness_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_roughness", "get_roughness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "roughness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_roughness", "get_roughness");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "roughness_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ROUGHNESS);
ADD_GROUP("Emission", "emission_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION);
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_emission_energy", "get_emission_energy");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION);
@@ -1253,19 +1253,19 @@ void SpatialMaterial::_bind_methods() {
ADD_GROUP("Rim", "rim_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "rim_enabled"), "set_feature", "get_feature", FEATURE_RIM);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "rim_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim", "get_rim");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rim", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim", "get_rim");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "rim_tint", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim_tint", "get_rim_tint");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "rim_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_RIM);
ADD_GROUP("Clearcoat", "clearcoat_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "clearcoat_enabled"), "set_feature", "get_feature", FEATURE_CLEARCOAT);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "clearcoat_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat", "get_clearcoat");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "clearcoat", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat", "get_clearcoat");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "clearcoat_gloss", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat_gloss", "get_clearcoat_gloss");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "clearcoat_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_CLEARCOAT);
ADD_GROUP("Anisotropy", "anisotropy_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anisotropy_enabled"), "set_feature", "get_feature", FEATURE_ANISOTROPY);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy_anisotropy", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy", "get_anisotropy");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy", "get_anisotropy");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anisotropy_flowmap", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_FLOWMAP);
ADD_GROUP("Ambient Occlusion", "ao_");
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 60fb97c792..b2822ca0c4 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "surface_tool.h"
-#include "method_bind_ext.inc"
+#include "method_bind_ext.gen.inc"
#define _VERTEX_SNAP 0.0001
#define EQ_VERTEX_DIST 0.00001
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 5049c0a1d6..0bd8c41228 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "texture.h"
-#include "core/method_bind_ext.inc"
+#include "core/method_bind_ext.gen.inc"
#include "core/os/os.h"
#include "core_string_names.h"
#include "io/image_loader.h"
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 76bb1daf94..b9d2c503e1 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -45,18 +45,22 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
tile_set_name(id, p_value);
else if (what == "texture")
tile_set_texture(id, p_value);
+ else if (what == "normal_map")
+ tile_set_normal_map(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 == "modulate")
tile_set_modulate(id, p_value);
- else if (what == "shape_offset")
- tile_set_shape_offset(id, p_value);
else if (what == "region")
tile_set_region(id, p_value);
else if (what == "shape")
- tile_set_shape(id, p_value);
+ tile_set_shape(id, 0, p_value);
+ else if (what == "shape_offset")
+ tile_set_shape_offset(id, 0, p_value);
+ else if (what == "shape_one_way")
+ tile_set_shape_one_way(id, 0, p_value);
else if (what == "shapes")
_tile_set_shapes(id, p_value);
else if (what == "occluder")
@@ -89,18 +93,22 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = tile_get_name(id);
else if (what == "texture")
r_ret = tile_get_texture(id);
+ else if (what == "normal_map")
+ r_ret = tile_get_normal_map(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 == "modulate")
r_ret = tile_get_modulate(id);
- else if (what == "shape_offset")
- r_ret = tile_get_shape_offset(id);
else if (what == "region")
r_ret = tile_get_region(id);
else if (what == "shape")
- r_ret = tile_get_shape(id);
+ r_ret = tile_get_shape(id, 0);
+ else if (what == "shape_offset")
+ r_ret = tile_get_shape_offset(id, 0);
+ else if (what == "shape_one_way")
+ r_ret = tile_get_shape_one_way(id, 0);
else if (what == "shapes")
r_ret = _tile_get_shapes(id);
else if (what == "occluder")
@@ -119,12 +127,13 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
- for (Map<int, Data>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
int id = E->key();
String pre = itos(id) + "/";
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::OBJECT, pre + "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "tex_offset"));
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"));
p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate"));
@@ -133,8 +142,9 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
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::VECTOR2, pre + "shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::BOOL, pre + "shape_one_way", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "shapes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
}
@@ -142,7 +152,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
void TileSet::create_tile(int p_id) {
ERR_FAIL_COND(tile_map.has(p_id));
- tile_map[p_id] = Data();
+ tile_map[p_id] = TileData();
_change_notify("");
emit_changed();
}
@@ -160,6 +170,19 @@ Ref<Texture> TileSet::tile_get_texture(int p_id) const {
return tile_map[p_id].texture;
}
+void TileSet::tile_set_normal_map(int p_id, const Ref<Texture> &p_normal_map) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].normal_map = p_normal_map;
+ emit_changed();
+}
+
+Ref<Texture> TileSet::tile_get_normal_map(int p_id) const {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Texture>());
+ return tile_map[p_id].normal_map;
+}
+
void TileSet::tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -199,19 +222,6 @@ Vector2 TileSet::tile_get_texture_offset(int p_id) const {
return tile_map[p_id].offset;
}
-void TileSet::tile_set_shape_offset(int p_id, const Vector2 &p_offset) {
-
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].shape_offset = p_offset;
- emit_changed();
-}
-
-Vector2 TileSet::tile_get_shape_offset(int p_id) const {
-
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
- return tile_map[p_id].shape_offset;
-}
-
void TileSet::tile_set_region(int p_id, const Rect2 &p_region) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -238,23 +248,82 @@ String TileSet::tile_get_name(int p_id) const {
return tile_map[p_id].name;
}
-void TileSet::tile_set_shape(int p_id, const Ref<Shape2D> &p_shape) {
+void TileSet::tile_clear_shapes(int p_id) {
+ tile_map[p_id].shapes_data.clear();
+}
+
+void TileSet::tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Vector2 &p_offset, bool p_one_way) {
ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].shapes.resize(1);
- tile_map[p_id].shapes[0] = p_shape;
+
+ ShapeData new_data = ShapeData();
+ new_data.shape = p_shape;
+ new_data.shape_offset = p_offset;
+ new_data.one_way_collision = p_one_way;
+
+ tile_map[p_id].shapes_data.push_back(new_data);
+};
+int TileSet::tile_get_shape_count(int p_id) const {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
+
+ return tile_map[p_id].shapes_data.size();
+};
+
+void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ if (tile_map[p_id].shapes_data.size() <= p_shape_id)
+ tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+ tile_map[p_id].shapes_data[p_shape_id].shape = p_shape;
emit_changed();
}
-Ref<Shape2D> TileSet::tile_get_shape(int p_id) const {
+Ref<Shape2D> TileSet::tile_get_shape(int p_id, int p_shape_id) const {
ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Shape2D>());
- if (tile_map[p_id].shapes.size() > 0)
- return tile_map[p_id].shapes[0];
+ if (tile_map[p_id].shapes_data.size() > p_shape_id)
+ return tile_map[p_id].shapes_data[p_shape_id].shape;
return Ref<Shape2D>();
}
+void TileSet::tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ if (tile_map[p_id].shapes_data.size() <= p_shape_id)
+ tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+ tile_map[p_id].shapes_data[p_shape_id].shape_offset = p_offset;
+ emit_changed();
+}
+
+Vector2 TileSet::tile_get_shape_offset(int p_id, int p_shape_id) const {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
+ if (tile_map[p_id].shapes_data.size() > p_shape_id)
+ return tile_map[p_id].shapes_data[p_shape_id].shape_offset;
+
+ return Vector2();
+}
+
+void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_way) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ if (tile_map[p_id].shapes_data.size() <= p_shape_id)
+ tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+ tile_map[p_id].shapes_data[p_shape_id].one_way_collision = p_one_way;
+ emit_changed();
+}
+
+bool TileSet::tile_get_shape_one_way(int p_id, int p_shape_id) const {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id), false);
+ if (tile_map[p_id].shapes_data.size() > p_shape_id)
+ return tile_map[p_id].shapes_data[p_shape_id].one_way_collision;
+
+ return false;
+}
+
void TileSet::tile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -301,31 +370,63 @@ Vector2 TileSet::tile_get_occluder_offset(int p_id) const {
return tile_map[p_id].occluder_offset;
}
-void TileSet::tile_set_shapes(int p_id, const Vector<Ref<Shape2D> > &p_shapes) {
+void TileSet::tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes) {
ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].shapes = p_shapes;
+ tile_map[p_id].shapes_data = p_shapes;
emit_changed();
}
-Vector<Ref<Shape2D> > TileSet::tile_get_shapes(int p_id) const {
+Vector<TileSet::ShapeData> TileSet::tile_get_shapes(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector<Ref<Shape2D> >());
- return tile_map[p_id].shapes;
+ ERR_FAIL_COND_V(!tile_map.has(p_id), Vector<ShapeData>());
+
+ return tile_map[p_id].shapes_data;
}
void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) {
ERR_FAIL_COND(!tile_map.has(p_id));
- Vector<Ref<Shape2D> > shapes;
+ Vector<ShapeData> shapes_data;
+ Vector2 default_offset = tile_get_shape_offset(p_id, 0);
+ bool default_one_way = tile_get_shape_one_way(p_id, 0);
for (int i = 0; i < p_shapes.size(); i++) {
-
- Ref<Shape2D> s = p_shapes[i];
- if (s.is_valid())
- shapes.push_back(s);
+ ShapeData s = ShapeData();
+
+ if (p_shapes[i].get_type() == Variant::OBJECT) {
+ Ref<Shape2D> shape = p_shapes[i];
+ if (shape.is_null()) continue;
+
+ s.shape = shape;
+ s.shape_offset = default_offset;
+ s.one_way_collision = default_one_way;
+ } else if (p_shapes[i].get_type() == Variant::DICTIONARY) {
+ Dictionary d = p_shapes[i];
+
+ if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT)
+ s.shape = d["shape"];
+ else
+ continue;
+
+ if (d.has("shape_offset") && d["shape_offset"].get_type() == Variant::VECTOR2)
+ s.shape_offset = d["shape_offset"];
+ else
+ s.shape_offset = default_offset;
+
+ if (d.has("one_way") && d["one_way"].get_type() == Variant::BOOL)
+ s.one_way_collision = d["one_way"];
+ else
+ s.one_way_collision = default_one_way;
+
+ } else {
+ ERR_EXPLAIN("Expected an array of objects or dictionaries for tile_set_shapes");
+ ERR_CONTINUE(true);
+ }
+
+ shapes_data.push_back(s);
}
- tile_set_shapes(p_id, shapes);
+ tile_map[p_id].shapes_data = shapes_data;
}
Array TileSet::_tile_get_shapes(int p_id) const {
@@ -333,9 +434,14 @@ Array TileSet::_tile_get_shapes(int p_id) const {
ERR_FAIL_COND_V(!tile_map.has(p_id), Array());
Array arr;
- Vector<Ref<Shape2D> > shp = tile_map[p_id].shapes;
- for (int i = 0; i < shp.size(); i++)
- arr.push_back(shp[i]);
+ Vector<ShapeData> data = tile_map[p_id].shapes_data;
+ for (int i = 0; i < data.size(); i++) {
+ Dictionary shape_data;
+ shape_data["shape"] = data[i].shape;
+ shape_data["shape_offset"] = data[i].shape_offset;
+ shape_data["one_way"] = data[i].one_way_collision;
+ arr.push_back(shape_data);
+ }
return arr;
}
@@ -344,7 +450,7 @@ Array TileSet::_get_tiles_ids() const {
Array arr;
- for (Map<int, Data>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
arr.push_back(E->key());
}
@@ -353,7 +459,7 @@ Array TileSet::_get_tiles_ids() const {
void TileSet::get_tile_list(List<int> *p_tiles) const {
- for (Map<int, Data>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
p_tiles->push_back(E->key());
}
@@ -382,7 +488,7 @@ int TileSet::get_last_unused_tile_id() const {
int TileSet::find_tile_by_name(const String &p_name) const {
- for (Map<int, Data>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
if (p_name == E->get().name)
return E->key();
@@ -404,16 +510,22 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name);
ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture:Texture"), &TileSet::tile_set_texture);
ClassDB::bind_method(D_METHOD("tile_get_texture:Texture", "id"), &TileSet::tile_get_texture);
+ ClassDB::bind_method(D_METHOD("tile_set_normal_map", "id", "normal_map:Texture"), &TileSet::tile_set_normal_map);
+ ClassDB::bind_method(D_METHOD("tile_get_normal_map:Texture", "id"), &TileSet::tile_get_normal_map);
ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material:ShaderMaterial"), &TileSet::tile_set_material);
ClassDB::bind_method(D_METHOD("tile_get_material:ShaderMaterial", "id"), &TileSet::tile_get_material);
ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset);
ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset);
- ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_offset"), &TileSet::tile_set_shape_offset);
- ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id"), &TileSet::tile_get_shape_offset);
ClassDB::bind_method(D_METHOD("tile_set_region", "id", "region"), &TileSet::tile_set_region);
ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region);
- ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape:Shape2D"), &TileSet::tile_set_shape);
- ClassDB::bind_method(D_METHOD("tile_get_shape:Shape2D", "id"), &TileSet::tile_get_shape);
+ ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape:Shape2D"), &TileSet::tile_set_shape);
+ ClassDB::bind_method(D_METHOD("tile_get_shape:Shape2D", "id", "shape_id"), &TileSet::tile_get_shape);
+ ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset);
+ ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset);
+ ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way);
+ ClassDB::bind_method(D_METHOD("tile_get_shape_one_way", "id", "shape_id"), &TileSet::tile_get_shape_one_way);
+ ClassDB::bind_method(D_METHOD("tile_add_shape", "id", "shape:Shape2D", "shape_offset", "one_way"), &TileSet::tile_add_shape, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("tile_get_shape_count", "id"), &TileSet::tile_get_shape_count);
ClassDB::bind_method(D_METHOD("tile_set_shapes", "id", "shapes"), &TileSet::_tile_set_shapes);
ClassDB::bind_method(D_METHOD("tile_get_shapes", "id"), &TileSet::_tile_get_shapes);
ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon", "id", "navigation_polygon:NavigationPolygon"), &TileSet::tile_set_navigation_polygon);
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 448444d34a..c07d82c75a 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -40,14 +40,26 @@ class TileSet : public Resource {
GDCLASS(TileSet, Resource);
- struct Data {
+public:
+ struct ShapeData {
+ Ref<Shape2D> shape;
+ Vector2 shape_offset;
+ bool one_way_collision;
+
+ ShapeData() {
+ one_way_collision = false;
+ }
+ };
+
+private:
+ struct TileData {
String name;
Ref<Texture> texture;
+ Ref<Texture> normal_map;
Vector2 offset;
- Vector2 shape_offset;
Rect2i region;
- Vector<Ref<Shape2D> > shapes;
+ Vector<ShapeData> shapes_data;
Vector2 occluder_offset;
Ref<OccluderPolygon2D> occluder;
Vector2 navigation_polygon_offset;
@@ -56,11 +68,11 @@ class TileSet : public Resource {
Color modulate;
// Default modulate for back-compat
- explicit Data()
+ explicit TileData()
: modulate(1, 1, 1) {}
};
- Map<int, Data> tile_map;
+ Map<int, TileData> tile_map;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -81,17 +93,30 @@ public:
void tile_set_texture(int p_id, const Ref<Texture> &p_texture);
Ref<Texture> tile_get_texture(int p_id) const;
+ void tile_set_normal_map(int p_id, const Ref<Texture> &p_normal_map);
+ Ref<Texture> tile_get_normal_map(int p_id) const;
+
void tile_set_texture_offset(int p_id, const Vector2 &p_offset);
Vector2 tile_get_texture_offset(int p_id) const;
- void tile_set_shape_offset(int p_id, const Vector2 &p_offset);
- Vector2 tile_get_shape_offset(int p_id) const;
-
void tile_set_region(int p_id, const Rect2 &p_region);
Rect2 tile_get_region(int p_id) const;
- void tile_set_shape(int p_id, const Ref<Shape2D> &p_shape);
- Ref<Shape2D> tile_get_shape(int p_id) const;
+ void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape);
+ Ref<Shape2D> tile_get_shape(int p_id, int p_shape_id) const;
+
+ void tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset);
+ Vector2 tile_get_shape_offset(int p_id, int p_shape_id) const;
+
+ void tile_set_shape_one_way(int p_id, int p_shape_id, bool p_one_way);
+ bool tile_get_shape_one_way(int p_id, int p_shape_id) const;
+
+ void tile_clear_shapes(int p_id);
+ void tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Vector2 &p_offset, bool p_one_way = false);
+ int tile_get_shape_count(int p_id) const;
+
+ void tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes);
+ Vector<ShapeData> tile_get_shapes(int p_id) const;
void tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material);
Ref<ShaderMaterial> tile_get_material(int p_id) const;
@@ -111,9 +136,6 @@ public:
void tile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon);
Ref<NavigationPolygon> tile_get_navigation_polygon(int p_id) const;
- void tile_set_shapes(int p_id, const Vector<Ref<Shape2D> > &p_shapes);
- Vector<Ref<Shape2D> > tile_get_shapes(int p_id) const;
-
void remove_tile(int p_id);
bool has_tile(int p_id) const;