diff options
Diffstat (limited to 'scene')
41 files changed, 820 insertions, 176 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 768d5185d7..82123d12ac 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -623,6 +623,29 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased); } + +void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + Vector<Color> colors; + colors.push_back(p_color); + VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width, p_antialiased); +} + +void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width, p_antialiased); +} + void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) { if (!drawing) { @@ -979,6 +1002,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width", "antialiased"), &CanvasItem::draw_multiline, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle); ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index ccbb528d6f..2384c0f370 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -268,6 +268,8 @@ public: void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); + void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); + void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true); void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index e1c7331393..4029ef137b 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -107,34 +107,56 @@ void PathFollow2D::_update_transform() { if (!c.is_valid()) return; - if (delta_offset == 0) { - return; - } - - float o = offset; + float path_length = c->get_baked_length(); + float bounded_offset = offset; if (loop) - o = Math::fposmod(o, c->get_baked_length()); - - Vector2 pos = c->interpolate_baked(o, cubic); + bounded_offset = Math::fposmod(bounded_offset, path_length); + else + bounded_offset = CLAMP(bounded_offset, 0, path_length); - Vector2 displacement_offset = Vector2(h_offset, v_offset); + Vector2 pos = c->interpolate_baked(bounded_offset, cubic); if (rotate) { + float ahead = bounded_offset + lookahead; + + if (loop && ahead >= path_length) { + // If our lookahead will loop, we need to check if the path is closed. + int point_count = c->get_point_count(); + if (point_count > 0) { + Vector2 start_point = c->get_point_position(0); + Vector2 end_point = c->get_point_position(point_count - 1); + if (start_point == end_point) { + // Since the path is closed we want to 'smooth off' + // the corner at the start/end. + // So we wrap the lookahead back round. + ahead = Math::fmod(ahead, path_length); + } + } + } + + Vector2 ahead_pos = c->interpolate_baked(ahead, cubic); - Vector2 t_prev = (pos - c->interpolate_baked(o - delta_offset, cubic)).normalized(); - Vector2 t_next = (c->interpolate_baked(o + delta_offset, cubic) - pos).normalized(); + Vector2 tangent_to_curve; + if (ahead_pos == pos) { + // This will happen at the end of non-looping or non-closed paths. + // We'll try a look behind instead, in order to get a meaningful angle. + tangent_to_curve = + (pos - c->interpolate_baked(bounded_offset - lookahead, cubic)).normalized(); + } else { + tangent_to_curve = (ahead_pos - pos).normalized(); + } - float angle = t_prev.angle_to(t_next); + Vector2 normal_of_curve = -tangent_to_curve.tangent(); - set_rotation(get_rotation() + angle); + pos += tangent_to_curve * h_offset; + pos += normal_of_curve * v_offset; - Vector2 n = t_next; - Vector2 t = -n.tangent(); - pos += n * h_offset + t * v_offset; + set_rotation(tangent_to_curve.angle()); } else { - pos += displacement_offset; + pos.x += h_offset; + pos.y += v_offset; } set_position(pos); @@ -185,6 +207,8 @@ bool PathFollow2D::_set(const StringName &p_name, const Variant &p_value) { set_cubic_interpolation(p_value); } else if (String(p_name) == "loop") { set_loop(p_value); + } else if (String(p_name) == "lookahead") { + set_lookahead(p_value); } else return false; @@ -207,6 +231,8 @@ bool PathFollow2D::_get(const StringName &p_name, Variant &r_ret) const { r_ret = cubic; } else if (String(p_name) == "loop") { r_ret = loop; + } else if (String(p_name) == "lookahead") { + r_ret = lookahead; } else return false; @@ -224,6 +250,7 @@ void PathFollow2D::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, "rotate")); p_list->push_back(PropertyInfo(Variant::BOOL, "cubic_interp")); p_list->push_back(PropertyInfo(Variant::BOOL, "loop")); + p_list->push_back(PropertyInfo(Variant::REAL, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001")); } String PathFollow2D::get_configuration_warning() const { @@ -263,7 +290,7 @@ void PathFollow2D::_bind_methods() { } void PathFollow2D::set_offset(float p_offset) { - delta_offset = p_offset - offset; + offset = p_offset; if (path) _update_transform(); @@ -314,6 +341,16 @@ float PathFollow2D::get_unit_offset() const { return 0; } +void PathFollow2D::set_lookahead(float p_lookahead) { + + lookahead = p_lookahead; +} + +float PathFollow2D::get_lookahead() const { + + return lookahead; +} + void PathFollow2D::set_rotate(bool p_rotate) { rotate = p_rotate; @@ -338,11 +375,11 @@ bool PathFollow2D::has_loop() const { PathFollow2D::PathFollow2D() { offset = 0; - delta_offset = 0; h_offset = 0; v_offset = 0; path = NULL; rotate = true; cubic = true; loop = true; + lookahead = 4; } diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index f5ba3a3d32..88a0abdea9 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -60,9 +60,9 @@ public: private: Path2D *path; real_t offset; - real_t delta_offset; // change in offset since last _update_transform real_t h_offset; real_t v_offset; + real_t lookahead; bool cubic; bool loop; bool rotate; @@ -90,6 +90,9 @@ public: void set_unit_offset(float p_unit_offset); float get_unit_offset() const; + void set_lookahead(float p_lookahead); + float get_lookahead() const; + void set_loop(bool p_loop); bool has_loop() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index c0d0a6e011..1e34372d1e 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "tile_map.h" + #include "io/marshalls.h" #include "method_bind_ext.gen.inc" #include "os/os.h" @@ -169,10 +170,12 @@ void TileMap::set_cell_size(Size2 p_size) { _recreate_quadrants(); emit_signal("settings_changed"); } + Size2 TileMap::get_cell_size() const { return cell_size; } + void TileMap::set_quadrant_size(int p_size) { ERR_FAIL_COND(p_size < 1); @@ -182,32 +185,12 @@ void TileMap::set_quadrant_size(int p_size) { _recreate_quadrants(); emit_signal("settings_changed"); } + int TileMap::get_quadrant_size() const { return quadrant_size; } -void TileMap::set_center_x(bool p_enable) { - - center_x = p_enable; - _recreate_quadrants(); - emit_signal("settings_changed"); -} -bool TileMap::get_center_x() const { - - return center_x; -} -void TileMap::set_center_y(bool p_enable) { - - center_y = p_enable; - _recreate_quadrants(); - emit_signal("settings_changed"); -} -bool TileMap::get_center_y() const { - - return center_y; -} - void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc) { Size2 s = p_sc; @@ -513,16 +496,13 @@ void TileMap::_update_dirty_quadrants() { } Ref<OccluderPolygon2D> occluder; - Vector2 occluder_ofs; if (tile_set->tile_get_is_autotile(c.id)) { occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); - occluder_ofs = tile_set->tile_get_occluder_offset(c.id); } else { occluder = tile_set->tile_get_light_occluder(c.id); - occluder_ofs = Vector2(); } if (occluder.is_valid()) { - + Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); Transform2D xform; xform.set_origin(offset.floor() + q.pos); _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s); @@ -968,14 +948,14 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { int c = p_data.size(); PoolVector<int>::Read r = p_data.read(); - int offset = (format == FORMAT_2_1_5) ? 3 : 2; + int offset = (format == FORMAT_2) ? 3 : 2; clear(); for (int i = 0; i < c; i += offset) { const uint8_t *ptr = (const uint8_t *)&r[i]; uint8_t local[12]; - for (int j = 0; j < ((format == FORMAT_2_1_5) ? 12 : 8); j++) + for (int j = 0; j < ((format == FORMAT_2) ? 12 : 8); j++) local[j] = ptr[j]; #ifdef BIG_ENDIAN_ENABLED @@ -985,7 +965,7 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { SWAP(local[4], local[7]); SWAP(local[5], local[6]); //TODO: ask someone to check this... - if (FORMAT == FORMAT_2_1_5) { + if (FORMAT == FORMAT_2) { SWAP(local[8], local[11]); SWAP(local[9], local[10]); } @@ -1000,7 +980,7 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { v &= (1 << 29) - 1; int16_t coord_x; int16_t coord_y; - if (format == FORMAT_2_1_5) { + if (format == FORMAT_2) { coord_x = decode_uint16(&local[8]); coord_y = decode_uint16(&local[10]); } @@ -1018,6 +998,8 @@ PoolVector<int> TileMap::_get_tile_data() const { data.resize(tile_map.size() * 3); PoolVector<int>::Write w = data.write(); + format = FORMAT_2; + int idx = 0; for (const Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) { uint8_t *ptr = (uint8_t *)&w[idx]; @@ -1298,7 +1280,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "format") { - r_ret = FORMAT_2_1_5; + r_ret = FORMAT_2; return true; } else if (p_name == "tile_data") { r_ret = _get_tile_data(); @@ -1474,12 +1456,6 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tile_origin", "origin"), &TileMap::set_tile_origin); ClassDB::bind_method(D_METHOD("get_tile_origin"), &TileMap::get_tile_origin); - ClassDB::bind_method(D_METHOD("set_center_x", "enable"), &TileMap::set_center_x); - ClassDB::bind_method(D_METHOD("get_center_x"), &TileMap::get_center_x); - - ClassDB::bind_method(D_METHOD("set_center_y", "enable"), &TileMap::set_center_y); - ClassDB::bind_method(D_METHOD("get_center_y"), &TileMap::get_center_y); - ClassDB::bind_method(D_METHOD("set_clip_uv", "enable"), &TileMap::set_clip_uv); ClassDB::bind_method(D_METHOD("get_clip_uv"), &TileMap::get_clip_uv); @@ -1581,8 +1557,6 @@ TileMap::TileMap() { quadrant_order_dirty = false; quadrant_size = 16; cell_size = Size2(64, 64); - center_x = false; - center_y = false; collision_layer = 1; collision_mask = 1; friction = 1; @@ -1594,7 +1568,7 @@ TileMap::TileMap() { y_sort_mode = false; occluder_light_mask = 1; clip_uv = false; - format = FORMAT_2_1_4; //Always initialize with the lowest format + format = FORMAT_1; //Always initialize with the lowest format fp_adjust = 0.00001; tile_origin = TILE_ORIGIN_TOP_LEFT; diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index edc9de0543..e5608884c4 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -61,14 +61,13 @@ public: private: enum DataFormat { - FORMAT_2_1_4 = 0, - FORMAT_2_1_5 + FORMAT_1 = 0, + FORMAT_2 }; Ref<TileSet> tile_set; Size2i cell_size; int quadrant_size; - bool center_x, center_y; Mode mode; Transform2D custom_transform; HalfOffset half_offset; @@ -178,7 +177,7 @@ private: float bounce; uint32_t collision_layer; uint32_t collision_mask; - DataFormat format; + mutable DataFormat format; TileOrigin tile_origin; @@ -231,11 +230,6 @@ public: void set_quadrant_size(int p_size); int get_quadrant_size() const; - void set_center_x(bool p_enable); - bool get_center_x() const; - void set_center_y(bool p_enable); - bool get_center_y() const; - void set_cell(int p_x, int p_y, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false, Vector2 p_autotile_coord = Vector2()); int get_cell(int p_x, int p_y) const; bool is_cell_x_flipped(int p_x, int p_y) const; diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 8e2f87738a..1f2b43165e 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -1284,8 +1284,11 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { _create_debug_mesh(&baker); } else { - Ref<GIProbeData> probe_data; - probe_data.instance(); + Ref<GIProbeData> probe_data = get_probe_data(); + + if (probe_data.is_null()) + probe_data.instance(); + probe_data->set_bounds(AABB(-extents, extents * 2.0)); probe_data->set_cell_size(baker.po2_bounds.size[longest_axis] / baker.axis_cell_size[longest_axis]); probe_data->set_dynamic_data(data); diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index c137b7e8ff..821f1a5a78 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -1189,7 +1189,7 @@ void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enable; _queue_shader_change(); - if (p_flag==FLAG_DISABLE_Z) { + if (p_flag == FLAG_DISABLE_Z) { _change_notify(); } } @@ -1379,7 +1379,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { } if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { - property.usage=0; + property.usage = 0; } } diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index f2f00bb617..c5f817d317 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -734,15 +734,12 @@ bool RigidBody::is_contact_monitor_enabled() const { return contact_monitor != NULL; } -void RigidBody::set_axis_lock(AxisLock p_lock) { - - axis_lock = p_lock; - PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), PhysicsServer::BodyAxisLock(axis_lock)); +void RigidBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) { + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); } -RigidBody::AxisLock RigidBody::get_axis_lock() const { - - return axis_lock; +bool RigidBody::get_axis_lock(PhysicsServer::BodyAxis p_axis) const { + return PhysicsServer::get_singleton()->body_is_axis_locked(get_rid(), p_axis); } Array RigidBody::get_colliding_bodies() const { @@ -837,8 +834,8 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("_body_enter_tree"), &RigidBody::_body_enter_tree); ClassDB::bind_method(D_METHOD("_body_exit_tree"), &RigidBody::_body_exit_tree); - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis_lock"), &RigidBody::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock"), &RigidBody::get_axis_lock); + ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody::set_axis_lock); + ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody::get_axis_lock); ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody::get_colliding_bodies); @@ -856,7 +853,13 @@ void RigidBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_lock", PROPERTY_HINT_ENUM, "Disabled,Lock X,Lock Y,Lock Z"), "set_axis_lock", "get_axis_lock"); + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "-1,128,0.01"), "set_linear_damp", "get_linear_damp"); @@ -874,11 +877,6 @@ void RigidBody::_bind_methods() { BIND_ENUM_CONSTANT(MODE_STATIC); BIND_ENUM_CONSTANT(MODE_CHARACTER); BIND_ENUM_CONSTANT(MODE_KINEMATIC); - - BIND_ENUM_CONSTANT(AXIS_LOCK_DISABLED); - BIND_ENUM_CONSTANT(AXIS_LOCK_X); - BIND_ENUM_CONSTANT(AXIS_LOCK_Y); - BIND_ENUM_CONSTANT(AXIS_LOCK_Z); } RigidBody::RigidBody() : @@ -904,8 +902,6 @@ RigidBody::RigidBody() : contact_monitor = NULL; can_sleep = true; - axis_lock = AXIS_LOCK_DISABLED; - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); } @@ -952,6 +948,12 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli r_collision.local_shape = result.collision_local_shape; } + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + result.motion[i] = 0; + } + } + gt.origin += result.motion; set_global_transform(gt); @@ -960,9 +962,16 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { - Vector3 motion = (floor_velocity + p_linear_velocity) * get_physics_process_delta_time(); Vector3 lv = p_linear_velocity; + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + lv[i] = 0; + } + } + + Vector3 motion = (floor_velocity + lv) * get_physics_process_delta_time(); + on_floor = false; on_ceiling = false; on_wall = false; @@ -1008,6 +1017,12 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve motion = motion.slide(n); lv = lv.slide(n); + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + lv[i] = 0; + } + } + colliders.push_back(collision); } else { @@ -1047,6 +1062,14 @@ bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion) return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion); } +void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) { + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); +} + +bool KinematicBody::get_axis_lock(PhysicsServer::BodyAxis p_axis) const { + return PhysicsServer::get_singleton()->body_is_axis_locked(get_rid(), p_axis); +} + void KinematicBody::set_safe_margin(float p_margin) { margin = p_margin; @@ -1095,12 +1118,23 @@ void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody::is_on_wall); ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody::get_floor_velocity); + ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody::set_axis_lock); + ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &KinematicBody::get_axis_lock); + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody::get_safe_margin); ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count); ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision); + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); } @@ -1108,7 +1142,7 @@ KinematicBody::KinematicBody() : PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC) { margin = 0.001; - + locked_axis = 0; on_floor = false; on_ceiling = false; on_wall = false; diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index f88b3860dc..9d9feda0b2 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -114,13 +114,6 @@ public: MODE_KINEMATIC, }; - enum AxisLock { - AXIS_LOCK_DISABLED, - AXIS_LOCK_X, - AXIS_LOCK_Y, - AXIS_LOCK_Z, - }; - private: bool can_sleep; PhysicsDirectBodyState *state; @@ -139,8 +132,6 @@ private: bool sleeping; bool ccd; - AxisLock axis_lock; - int max_contacts_reported; bool custom_integrator; @@ -245,8 +236,8 @@ public: void set_use_continuous_collision_detection(bool p_enable); bool is_using_continuous_collision_detection() const; - void set_axis_lock(AxisLock p_lock); - AxisLock get_axis_lock() const; + void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock); + bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const; Array get_colliding_bodies() const; @@ -259,7 +250,6 @@ public: }; VARIANT_ENUM_CAST(RigidBody::Mode); -VARIANT_ENUM_CAST(RigidBody::AxisLock); class KinematicCollision; @@ -281,6 +271,8 @@ public: }; private: + uint16_t locked_axis; + float margin; Vector3 floor_velocity; @@ -303,6 +295,9 @@ public: bool move_and_collide(const Vector3 &p_motion, Collision &r_collision); bool test_move(const Transform &p_from, const Vector3 &p_motion); + void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock); + bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const; + void set_safe_margin(float p_margin); float get_safe_margin() const; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index f3e750d0da..e866e665d8 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -364,6 +364,9 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float if (!nc) // no node cache for this track, skip it continue; + if (!a->track_is_enabled(i)) + continue; // do nothing if the track is disabled + if (a->track_get_key_count(i) == 0) continue; // do nothing if track is empty @@ -1325,8 +1328,6 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false)); ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance); - ClassDB::bind_method(D_METHOD("get_anim_position"), &AnimationPlayer::get_current_animation_position); - ClassDB::bind_method(D_METHOD("get_anim_length"), &AnimationPlayer::get_current_animation_length); ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation); @@ -1335,6 +1336,9 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation_process_mode", "mode"), &AnimationPlayer::set_animation_process_mode); ClassDB::bind_method(D_METHOD("get_animation_process_mode"), &AnimationPlayer::get_animation_process_mode); + ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position); + ClassDB::bind_method(D_METHOD("get_current_animation_length"), &AnimationPlayer::get_current_animation_length); + ADD_GROUP("Playback Options", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); @@ -1343,7 +1347,7 @@ void AnimationPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "autoplay"), "set_autoplay", "get_autoplay"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_anim"), "set_current_anim", "get_current_anim"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_animation"), "set_current_animation", "get_current_animation"); ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 23eccec82f..32f82fe6b8 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -831,7 +831,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { for (List<AnimationNode::TrackRef>::Element *E = anim_list->tref.front(); E; E = E->next()) { AnimationNode::TrackRef &tr = E->get(); - if (tr.track == NULL || tr.local_track < 0 || tr.weight < CMP_EPSILON) + if (tr.track == NULL || tr.local_track < 0 || tr.weight < CMP_EPSILON || !a->track_is_enabled(tr.local_track)) continue; switch (a->track_get_type(tr.local_track)) { @@ -1796,6 +1796,10 @@ void AnimationTreePlayer::_bind_methods() { ADD_GROUP("Playback", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "master_player"), "set_master_player", "get_master_player"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "base_path"), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); + BIND_ENUM_CONSTANT(NODE_OUTPUT); BIND_ENUM_CONSTANT(NODE_ANIMATION); BIND_ENUM_CONSTANT(NODE_ONESHOT); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 1fa03f81f4..47977f0283 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -55,6 +55,10 @@ Size2 Button::get_minimum_size() const { return get_stylebox("normal")->get_minimum_size() + minsize; } +void Button::_set_internal_margin(Margin p_margin, float p_value) { + _internal_margin[p_margin] = p_value; +} + void Button::_notification(int p_what) { if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { @@ -136,11 +140,11 @@ void Button::_notification(int p_what) { Point2 icon_ofs = (!_icon.is_null()) ? Point2(_icon->get_width() + get_constant("hseparation"), 0) : Point2(); int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; - Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text)) / 2.0; + Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0; switch (align) { case ALIGN_LEFT: { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x; + text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); text_ofs.y += style->get_offset().y; } break; case ALIGN_CENTER: { @@ -150,7 +154,11 @@ void Button::_notification(int p_what) { text_ofs += style->get_offset(); } break; case ALIGN_RIGHT: { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x; + if (_internal_margin[MARGIN_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation"); + } else { + text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x; + } text_ofs.y += style->get_offset().y; } break; } @@ -162,7 +170,11 @@ void Button::_notification(int p_what) { int valign = size.height - style->get_minimum_size().y; if (is_disabled()) color_icon.a = 0.4; - _icon->draw(ci, style->get_offset() + Point2(0, Math::floor((valign - _icon->get_height()) / 2.0)), color_icon); + if (_internal_margin[MARGIN_LEFT] > 0) { + _icon->draw(ci, style->get_offset() + Point2(_internal_margin[MARGIN_LEFT] + get_constant("hseparation"), Math::floor((valign - _icon->get_height()) / 2.0)), color_icon); + } else { + _icon->draw(ci, style->get_offset() + Point2(0, Math::floor((valign - _icon->get_height()) / 2.0)), color_icon); + } } } } @@ -253,7 +265,7 @@ void Button::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_button_icon", "get_button_icon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); - ADD_PROPERTYNO(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align"); } Button::Button(const String &p_text) { @@ -263,6 +275,10 @@ Button::Button(const String &p_text) { set_mouse_filter(MOUSE_FILTER_STOP); set_text(p_text); align = ALIGN_CENTER; + + for (int i = 0; i < 4; i++) { + _internal_margin[i] = 0; + } } Button::~Button() { diff --git a/scene/gui/button.h b/scene/gui/button.h index dd6e730b86..35488582de 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -53,9 +53,11 @@ private: Ref<Texture> icon; bool clip_text; TextAlign align; + float _internal_margin[4]; protected: virtual Size2 get_minimum_size() const; + void _set_internal_margin(Margin p_margin, float p_value); void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 00f6153062..bf8156b92b 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -31,18 +31,54 @@ #include "servers/visual_server.h" +Size2 CheckBox::get_icon_size() const { + Ref<Texture> checked = Control::get_icon("checked"); + Ref<Texture> unchecked = Control::get_icon("unchecked"); + Ref<Texture> radio_checked = Control::get_icon("radio_checked"); + Ref<Texture> radio_unchecked = Control::get_icon("radio_unchecked"); + + Size2 tex_size = Size2(0, 0); + if (!checked.is_null()) + tex_size = Size2(checked->get_width(), checked->get_height()); + if (!unchecked.is_null()) + tex_size = Size2(MAX(tex_size.width, unchecked->get_width()), MAX(tex_size.height, unchecked->get_height())); + if (!radio_checked.is_null()) + tex_size = Size2(MAX(tex_size.width, radio_checked->get_width()), MAX(tex_size.height, radio_checked->get_height())); + if (!radio_unchecked.is_null()) + tex_size = Size2(MAX(tex_size.width, radio_unchecked->get_width()), MAX(tex_size.height, radio_unchecked->get_height())); + return tex_size; +} + +Size2 CheckBox::get_minimum_size() const { + + Size2 minsize = Button::get_minimum_size(); + Size2 tex_size = get_icon_size(); + minsize.width += tex_size.width; + if (get_text().length() > 0) { + minsize.width += get_constant("hseparation"); + } + Ref<StyleBox> sb = get_stylebox("normal"); + minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); + + return minsize; +} + void CheckBox::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { + if (p_what == NOTIFICATION_THEME_CHANGED) { + + _set_internal_margin(MARGIN_LEFT, get_icon_size().width); + } else if (p_what == NOTIFICATION_DRAW) { RID ci = get_canvas_item(); Ref<Texture> on = Control::get_icon(is_radio() ? "radio_checked" : "checked"); Ref<Texture> off = Control::get_icon(is_radio() ? "radio_unchecked" : "unchecked"); + Ref<StyleBox> sb = get_stylebox("normal"); Vector2 ofs; - ofs.x = 0; - ofs.y = int((get_size().height - on->get_height()) / 2); + ofs.x = sb->get_margin(MARGIN_LEFT); + ofs.y = int((get_size().height - get_icon_size().height) / 2); if (is_pressed()) on->draw(ci, ofs); @@ -60,6 +96,7 @@ CheckBox::CheckBox(const String &p_text) : Button(p_text) { set_toggle_mode(true); set_text_align(ALIGN_LEFT); + _set_internal_margin(MARGIN_LEFT, get_icon_size().width); } CheckBox::~CheckBox() { diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h index 4da06be8d1..3d3f170e8c 100644 --- a/scene/gui/check_box.h +++ b/scene/gui/check_box.h @@ -39,6 +39,8 @@ class CheckBox : public Button { GDCLASS(CheckBox, Button); protected: + Size2 get_icon_size() const; + Size2 get_minimum_size() const; void _notification(int p_what); bool is_radio(); diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index 77fdedd5e5..641d2d4f01 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -32,10 +32,7 @@ #include "print_string.h" #include "servers/visual_server.h" -Size2 CheckButton::get_minimum_size() const { - - Size2 minsize = Button::get_minimum_size(); - +Size2 CheckButton::get_icon_size() const { Ref<Texture> on = Control::get_icon("on"); Ref<Texture> off = Control::get_icon("off"); Size2 tex_size = Size2(0, 0); @@ -43,15 +40,29 @@ Size2 CheckButton::get_minimum_size() const { tex_size = Size2(on->get_width(), on->get_height()); if (!off.is_null()) tex_size = Size2(MAX(tex_size.width, off->get_width()), MAX(tex_size.height, off->get_height())); - minsize += Size2(tex_size.width + get_constant("hseparation"), 0); - minsize.height = MAX(minsize.height, tex_size.height); + return tex_size; +} + +Size2 CheckButton::get_minimum_size() const { - return get_stylebox("normal")->get_minimum_size() + minsize; + Size2 minsize = Button::get_minimum_size(); + Size2 tex_size = get_icon_size(); + minsize.width += tex_size.width; + if (get_text().length() > 0) { + minsize.width += get_constant("hseparation"); + } + Ref<StyleBox> sb = get_stylebox("normal"); + minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); + + return minsize; } void CheckButton::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { + if (p_what == NOTIFICATION_THEME_CHANGED) { + + _set_internal_margin(MARGIN_RIGHT, get_icon_size().width); + } else if (p_what == NOTIFICATION_DRAW) { RID ci = get_canvas_item(); @@ -59,10 +70,11 @@ void CheckButton::_notification(int p_what) { Ref<Texture> off = Control::get_icon("off"); Ref<StyleBox> sb = get_stylebox("normal"); - Size2 sb_ofs = Size2(sb->get_margin(MARGIN_RIGHT), sb->get_margin(MARGIN_TOP)); Vector2 ofs; - ofs.x = get_minimum_size().width - (on->get_width() + sb_ofs.width); - ofs.y = sb_ofs.height; + Size2 tex_size = get_icon_size(); + + ofs.x = get_size().width - (tex_size.width + sb->get_margin(MARGIN_RIGHT)); + ofs.y = (get_size().height - tex_size.height) / 2; if (is_pressed()) on->draw(ci, ofs); @@ -75,6 +87,8 @@ CheckButton::CheckButton() { set_toggle_mode(true); set_text_align(ALIGN_LEFT); + + _set_internal_margin(MARGIN_RIGHT, get_icon_size().width); } CheckButton::~CheckButton() { diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h index eb68943fe7..3103a40d3c 100644 --- a/scene/gui/check_button.h +++ b/scene/gui/check_button.h @@ -39,6 +39,7 @@ class CheckButton : public Button { GDCLASS(CheckButton, Button); protected: + Size2 get_icon_size() const; virtual Size2 get_minimum_size() const; void _notification(int p_what); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index adca78d1d4..81d2b6731f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2470,6 +2470,16 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } +void Control::set_pass_on_modal_close_click(bool p_pass_on) { + + data.pass_on_modal_close_click = p_pass_on; +} + +bool Control::pass_on_modal_close_click() const { + + return data.pass_on_modal_close_click; +} + Control *Control::get_focus_owner() const { ERR_FAIL_COND_V(!is_inside_tree(), NULL); @@ -2934,6 +2944,7 @@ Control::Control() { data.parent = NULL; data.mouse_filter = MOUSE_FILTER_STOP; + data.pass_on_modal_close_click = true; data.SI = NULL; data.MI = NULL; diff --git a/scene/gui/control.h b/scene/gui/control.h index 92d1c969fc..9ac0eb0be3 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -165,6 +165,8 @@ private: bool pending_min_size_update; Point2 custom_minimum_size; + bool pass_on_modal_close_click; + MouseFilter mouse_filter; bool clip_contents; @@ -401,6 +403,9 @@ public: void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; + void set_pass_on_modal_close_click(bool p_pass_on); + bool pass_on_modal_close_click() const; + /* SKINNING */ void add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 8af499fd96..6af869c503 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -603,6 +603,14 @@ void FileDialog::set_current_path(const String &p_path) { } } +void FileDialog::set_mode_overrides_title(bool p_override) { + mode_overrides_title = p_override; +} + +bool FileDialog::is_mode_overriding_title() const { + return mode_overrides_title; +} + void FileDialog::set_mode(Mode p_mode) { mode = p_mode; @@ -610,27 +618,32 @@ void FileDialog::set_mode(Mode p_mode) { case MODE_OPEN_FILE: get_ok()->set_text(RTR("Open")); - set_title(RTR("Open a File")); + if (mode_overrides_title) + set_title(RTR("Open a File")); makedir->hide(); break; case MODE_OPEN_FILES: get_ok()->set_text(RTR("Open")); - set_title(RTR("Open File(s)")); + if (mode_overrides_title) + set_title(RTR("Open File(s)")); makedir->hide(); break; case MODE_OPEN_DIR: get_ok()->set_text(RTR("Select Current Folder")); - set_title(RTR("Open a Directory")); + if (mode_overrides_title) + set_title(RTR("Open a Directory")); makedir->show(); break; case MODE_OPEN_ANY: get_ok()->set_text(RTR("Open")); - set_title(RTR("Open a File or Directory")); + if (mode_overrides_title) + set_title(RTR("Open a File or Directory")); makedir->show(); break; case MODE_SAVE_FILE: get_ok()->set_text(RTR("Save")); - set_title(RTR("Save a File")); + if (mode_overrides_title) + set_title(RTR("Save a File")); makedir->show(); break; } @@ -760,6 +773,8 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current_dir", "dir"), &FileDialog::set_current_dir); ClassDB::bind_method(D_METHOD("set_current_file", "file"), &FileDialog::set_current_file); ClassDB::bind_method(D_METHOD("set_current_path", "path"), &FileDialog::set_current_path); + ClassDB::bind_method(D_METHOD("set_mode_overrides_title", "override"), &FileDialog::set_mode_overrides_title); + ClassDB::bind_method(D_METHOD("is_mode_overriding_title"), &FileDialog::is_mode_overriding_title); ClassDB::bind_method(D_METHOD("set_mode", "mode"), &FileDialog::set_mode); ClassDB::bind_method(D_METHOD("get_mode"), &FileDialog::get_mode); ClassDB::bind_method(D_METHOD("get_vbox"), &FileDialog::get_vbox); @@ -791,6 +806,7 @@ void FileDialog::_bind_methods() { BIND_ENUM_CONSTANT(ACCESS_USERDATA); BIND_ENUM_CONSTANT(ACCESS_FILESYSTEM); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "filters"), "set_filters", "get_filters"); @@ -814,6 +830,8 @@ FileDialog::FileDialog() { show_hidden_files = default_show_hidden_files; + mode_overrides_title = true; + VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index ca3d9f54b2..c8c1f23105 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -92,6 +92,8 @@ private: Vector<String> filters; + bool mode_overrides_title; + static bool default_show_hidden_files; bool show_hidden_files; @@ -143,6 +145,9 @@ public: void set_current_file(const String &p_file); void set_current_path(const String &p_path); + void set_mode_overrides_title(bool p_override); + bool is_mode_overriding_title() const; + void set_mode(Mode p_mode); Mode get_mode() const; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index ac450616d6..d850553957 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -111,6 +111,7 @@ MenuButton::MenuButton() { popup->hide(); add_child(popup); popup->set_as_toplevel(true); + popup->set_pass_on_modal_close_click(false); connect("button_up", popup, "call_deferred", make_binds("grab_click_focus")); set_process_unhandled_key_input(true); set_action_mode(ACTION_MODE_BUTTON_PRESS); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index b4d0799945..70f3d9ca83 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -323,6 +323,7 @@ OptionButton::OptionButton() { popup = memnew(PopupMenu); popup->hide(); popup->set_as_toplevel(true); + popup->set_pass_on_modal_close_click(false); add_child(popup); popup->connect("id_pressed", this, "_selected"); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 4ee6f93c9a..e37cdd5cc9 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -624,6 +624,20 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo update(); } +void PopupMenu::add_statable_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) { + + Item item; + item.text = p_label; + item.xl_text = tr(p_label); + item.accel = p_accel; + item.ID = p_ID; + item.checkable = false; + item.max_states = p_max_states; + item.state = p_default_state; + items.push_back(item); + update(); +} + void PopupMenu::set_item_text(int p_idx, const String &p_text) { ERR_FAIL_INDEX(p_idx, items.size()); @@ -772,6 +786,11 @@ Ref<ShortCut> PopupMenu::get_item_shortcut(int p_idx) const { return items[p_idx].shortcut; } +int PopupMenu::get_item_state(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, items.size(), -1); + return items[p_idx].state; +} + void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx, items.size()); @@ -820,6 +839,27 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { update(); } +void PopupMenu::set_item_statable(int p_idx, int p_state) { + + ERR_FAIL_INDEX(p_idx, items.size()); + items[p_idx].state = p_state; + update(); +} + +void PopupMenu::toggle_item_statable(int p_idx) { + + ERR_FAIL_INDEX(p_idx, items.size()); + if (0 >= items[p_idx].max_states) { + return; + } + + ++items[p_idx].state; + if (items[p_idx].max_states <= items[p_idx].state) + items[p_idx].state = 0; + + update(); +} + bool PopupMenu::is_item_checkable(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, items.size(), false); return items[p_idx].checkable; @@ -895,21 +935,34 @@ void PopupMenu::activate_item(int p_item) { while (pop) { // We close all parents that are chained together, // with hide_on_item_selection enabled - if ((items[p_item].checkable && hide_on_checkable_item_selection && pop->is_hide_on_checkable_item_selection()) || (!items[p_item].checkable && hide_on_item_selection && pop->is_hide_on_item_selection())) { - pop->hide(); - next = next->get_parent(); - pop = Object::cast_to<PopupMenu>(next); - } else { - // Break out of loop when the next parent has - // hide_on_item_selection disabled + + if (items[p_item].checkable) { + if (!hide_on_checkable_item_selection || !pop->is_hide_on_checkable_item_selection()) + break; + } else if (0 < items[p_item].max_states) { + if (!hide_on_statable_item_selection || !pop->is_hide_on_statable_item_selection()) + break; + } else if (!hide_on_item_selection || !pop->is_hide_on_item_selection()) break; - } + + pop->hide(); + next = next->get_parent(); + pop = Object::cast_to<PopupMenu>(next); } + // Hides popup by default; unless otherwise specified // by using set_hide_on_item_selection and set_hide_on_checkable_item_selection - if ((items[p_item].checkable && hide_on_checkable_item_selection) || (!items[p_item].checkable && hide_on_item_selection)) { - hide(); - } + + if (items[p_item].checkable) { + if (!hide_on_checkable_item_selection) + return; + } else if (0 < items[p_item].max_states) { + if (!hide_on_statable_item_selection) + return; + } else if (!hide_on_item_selection) + return; + + hide(); } void PopupMenu::remove_item(int p_idx) { @@ -1025,7 +1078,7 @@ void PopupMenu::set_hide_on_item_selection(bool p_enabled) { hide_on_item_selection = p_enabled; } -bool PopupMenu::is_hide_on_item_selection() { +bool PopupMenu::is_hide_on_item_selection() const { return hide_on_item_selection; } @@ -1035,11 +1088,21 @@ void PopupMenu::set_hide_on_checkable_item_selection(bool p_enabled) { hide_on_checkable_item_selection = p_enabled; } -bool PopupMenu::is_hide_on_checkable_item_selection() { +bool PopupMenu::is_hide_on_checkable_item_selection() const { return hide_on_checkable_item_selection; } +void PopupMenu::set_hide_on_statable_item_selection(bool p_enabled) { + + hide_on_statable_item_selection = p_enabled; +} + +bool PopupMenu::is_hide_on_statable_item_selection() const { + + return hide_on_statable_item_selection; +} + String PopupMenu::get_tooltip(const Point2 &p_pos) const { int over = _get_mouse_over(p_pos); @@ -1098,8 +1161,10 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_as_checkable", "idx", "enable"), &PopupMenu::set_item_as_checkable); ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &PopupMenu::set_item_tooltip); ClassDB::bind_method(D_METHOD("set_item_shortcut", "idx", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_item_statable", "idx", "state"), &PopupMenu::set_item_statable); ClassDB::bind_method(D_METHOD("toggle_item_checked", "idx"), &PopupMenu::toggle_item_checked); + ClassDB::bind_method(D_METHOD("toggle_item_statable", "idx"), &PopupMenu::toggle_item_statable); ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &PopupMenu::get_item_text); ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &PopupMenu::get_item_icon); @@ -1131,6 +1196,9 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_checkable_item_selection", "enable"), &PopupMenu::set_hide_on_checkable_item_selection); ClassDB::bind_method(D_METHOD("is_hide_on_checkable_item_selection"), &PopupMenu::is_hide_on_checkable_item_selection); + ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_statable_item_selection); + ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_statable_item_selection); + ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items"); @@ -1154,6 +1222,7 @@ PopupMenu::PopupMenu() { set_as_toplevel(true); set_hide_on_item_selection(true); set_hide_on_checkable_item_selection(true); + set_hide_on_statable_item_selection(false); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index c9e9c8e311..5a10bf0765 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -46,6 +46,8 @@ class PopupMenu : public Popup { String xl_text; bool checked; bool checkable; + int max_states; + int state; bool separator; bool disabled; int ID; @@ -62,6 +64,8 @@ class PopupMenu : public Popup { checked = false; checkable = false; separator = false; + max_states = 0; + state = 0; accel = 0; disabled = false; _ofs_cache = 0; @@ -86,6 +90,7 @@ class PopupMenu : public Popup { bool invalidated_click; bool hide_on_item_selection; bool hide_on_checkable_item_selection; + bool hide_on_statable_item_selection; Vector2 moved; Array _get_items() const; @@ -115,6 +120,8 @@ public: void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); + void add_statable_item(const String &p_label, int p_max_states, int p_default_state, int p_ID = -1, uint32_t p_accel = 0); + void set_item_text(int p_idx, const String &p_text); void set_item_icon(int p_idx, const Ref<Texture> &p_icon); void set_item_checked(int p_idx, bool p_checked); @@ -128,6 +135,8 @@ public: void set_item_tooltip(int p_idx, const String &p_tooltip); void set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global = false); void set_item_h_offset(int p_idx, int p_offset); + void set_item_statable(int p_idx, int p_state); + void toggle_item_statable(int p_idx); void toggle_item_checked(int p_idx); @@ -145,6 +154,7 @@ public: bool is_item_checkable(int p_idx) const; String get_item_tooltip(int p_idx) const; Ref<ShortCut> get_item_shortcut(int p_idx) const; + int get_item_state(int p_idx) const; int get_item_count() const; @@ -168,10 +178,13 @@ public: void set_invalidate_click_until_motion(); void set_hide_on_item_selection(bool p_enabled); - bool is_hide_on_item_selection(); + bool is_hide_on_item_selection() const; void set_hide_on_checkable_item_selection(bool p_enabled); - bool is_hide_on_checkable_item_selection(); + bool is_hide_on_checkable_item_selection() const; + + void set_hide_on_statable_item_selection(bool p_enabled); + bool is_hide_on_statable_item_selection() const; PopupMenu(); ~PopupMenu(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 9cf4c105b4..45188c3a52 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1822,7 +1822,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection) { void RichTextLabel::selection_copy() { - if (!selection.enabled) + if (!selection.active || !selection.enabled) return; String text; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 1096e3f650..b9a719dd10 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -256,8 +256,8 @@ private: Item *to; int to_char; - bool active; - bool enabled; + bool active; // anything selected? i.e. from, to, etc. valid? + bool enabled; // allow selections? }; Selection selection; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 7ff85716a5..e5169089f2 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4646,6 +4646,16 @@ void TextEdit::unfold_line(int p_line) { update(); } +void TextEdit::toggle_fold_line(int p_line) { + + ERR_FAIL_INDEX(p_line, text.size()); + + if (!is_folded(p_line)) + fold_line(p_line); + else + unfold_line(p_line); +} + int TextEdit::get_line_count() const { return text.size(); @@ -5461,6 +5471,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line); + ClassDB::bind_method(D_METHOD("toggle_fold_line", "line"), &TextEdit::toggle_fold_line); ClassDB::bind_method(D_METHOD("can_fold", "line"), &TextEdit::can_fold); ClassDB::bind_method(D_METHOD("is_folded", "line"), &TextEdit::is_folded); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index e5dc2da7c7..dd305d5822 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -436,6 +436,7 @@ public: bool is_folded(int p_line) const; void fold_line(int p_line); void unfold_line(int p_line); + void toggle_fold_line(int p_line); String get_text(); String get_line(int line) const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index a785abbc65..4635de81e8 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1269,12 +1269,9 @@ Transform2D Viewport::_get_input_pre_xform() const { Vector2 Viewport::_get_window_offset() const { - /* - if (parent_control) { - return (parent_control->get_viewport()->get_final_transform() * parent_control->get_global_transform_with_canvas()).get_origin(); + if (get_parent() && get_parent()->has_method("get_global_position")) { + return get_parent()->call("get_global_position"); } - */ - return Vector2(); } @@ -1649,6 +1646,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } else { + bool is_handled = false; + _gui_sort_modal_stack(); while (!gui.modal_stack.empty()) { @@ -1666,11 +1665,20 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { top->notification(Control::NOTIFICATION_MODAL_CLOSE); top->_modal_stack_remove(); top->hide(); + + if (!top->pass_on_modal_close_click()) { + is_handled = true; + } } else { break; } } + if (is_handled) { + get_tree()->set_input_as_handled(); + return; + } + //Matrix32 parent_xform; /* diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index ebbd2d35c3..4544549f94 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -77,6 +77,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { track_set_interpolation_loop_wrap(track, p_value); else if (what == "imported") track_set_imported(track, p_value); + else if (what == "enabled") + track_set_enabled(track, p_value); else if (what == "keys" || what == "key_values") { if (track_get_type(track) == TYPE_TRANSFORM) { @@ -247,6 +249,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = track_get_interpolation_loop_wrap(track); else if (what == "imported") r_ret = track_is_imported(track); + else if (what == "enabled") + r_ret = track_is_enabled(track); else if (what == "keys") { if (track_get_type(track) == TYPE_TRANSFORM) { @@ -391,6 +395,7 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "tracks/" + itos(i) + "/interp", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/loop_wrap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/imported", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::ARRAY, "tracks/" + itos(i) + "/keys", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } } @@ -1575,6 +1580,19 @@ bool Animation::track_is_imported(int p_track) const { return tracks[p_track]->imported; } +void Animation::track_set_enabled(int p_track, bool p_enabled) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + tracks[p_track]->enabled = p_enabled; + emit_changed(); +} + +bool Animation::track_is_enabled(int p_track) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), false); + return tracks[p_track]->enabled; +} + void Animation::track_move_down(int p_track) { if (p_track > 0 && p_track < tracks.size()) { @@ -1603,6 +1621,7 @@ void Animation::copy_track(int src_track, Ref<Animation> p_to_animation) { p_to_animation->track_set_path(dst_track, track_get_path(src_track)); p_to_animation->track_set_imported(dst_track, track_is_imported(src_track)); + p_to_animation->track_set_enabled(dst_track, track_is_enabled(src_track)); p_to_animation->track_set_interpolation_type(dst_track, track_get_interpolation_type(src_track)); p_to_animation->track_set_interpolation_loop_wrap(dst_track, track_get_interpolation_loop_wrap(src_track)); for (int i = 0; i < track_get_key_count(src_track); i++) { @@ -1626,6 +1645,9 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported); ClassDB::bind_method(D_METHOD("track_is_imported", "idx"), &Animation::track_is_imported); + ClassDB::bind_method(D_METHOD("track_set_enabled", "idx", "enabled"), &Animation::track_set_enabled); + ClassDB::bind_method(D_METHOD("track_is_enabled", "idx"), &Animation::track_is_enabled); + ClassDB::bind_method(D_METHOD("transform_track_insert_key", "idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key); ClassDB::bind_method(D_METHOD("track_insert_key", "idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1)); ClassDB::bind_method(D_METHOD("track_remove_key", "idx", "key_idx"), &Animation::track_remove_key); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index c96beeb01f..1f468b29b5 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -67,10 +67,12 @@ private: bool loop_wrap; NodePath path; // path to something bool imported; + bool enabled; Track() { interpolation = INTERPOLATION_LINEAR; imported = false; loop_wrap = true; + enabled = true; } virtual ~Track() {} }; @@ -239,6 +241,9 @@ public: void track_set_imported(int p_track, bool p_imported); bool track_is_imported(int p_track) const; + void track_set_enabled(int p_track, bool p_enabled); + bool track_is_enabled(int p_track) const; + int transform_track_insert_key(int p_track, float p_time, const Vector3 p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3()); void track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition = 1); void track_set_key_transition(int p_track, int p_key_idx, float p_transition); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index bb2c8750e3..f4e6c5e247 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -350,15 +350,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CheckBox Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty); - cbx_empty->set_default_margin(MARGIN_LEFT, 22 * scale); + cbx_empty->set_default_margin(MARGIN_LEFT, 4 * scale); cbx_empty->set_default_margin(MARGIN_RIGHT, 4 * scale); cbx_empty->set_default_margin(MARGIN_TOP, 4 * scale); - cbx_empty->set_default_margin(MARGIN_BOTTOM, 5 * scale); + cbx_empty->set_default_margin(MARGIN_BOTTOM, 4 * scale); Ref<StyleBox> cbx_focus = focus; cbx_focus->set_default_margin(MARGIN_LEFT, 4 * scale); - cbx_focus->set_default_margin(MARGIN_RIGHT, 22 * scale); + cbx_focus->set_default_margin(MARGIN_RIGHT, 4 * scale); cbx_focus->set_default_margin(MARGIN_TOP, 4 * scale); - cbx_focus->set_default_margin(MARGIN_BOTTOM, 5 * scale); + cbx_focus->set_default_margin(MARGIN_BOTTOM, 4 * scale); theme->set_stylebox("normal", "CheckBox", cbx_empty); theme->set_stylebox("pressed", "CheckBox", cbx_empty); @@ -385,7 +385,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); cb_empty->set_default_margin(MARGIN_LEFT, 6 * scale); - cb_empty->set_default_margin(MARGIN_RIGHT, 70 * scale); + cb_empty->set_default_margin(MARGIN_RIGHT, 6 * scale); cb_empty->set_default_margin(MARGIN_TOP, 4 * scale); cb_empty->set_default_margin(MARGIN_BOTTOM, 4 * scale); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 0a886c25b1..0b352efca2 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -28,10 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "mesh.h" + +#include "pair.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" #include "surface_tool.h" +#include <stdlib.h> + void Mesh::_clear_triangle_mesh() const { triangle_mesh.unref(); @@ -413,8 +417,21 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const { return newmesh; } +void Mesh::set_lightmap_size_hint(const Vector2 &p_size) { + lightmap_size_hint = p_size; +} + +Size2 Mesh::get_lightmap_size_hint() const { + return lightmap_size_hint; +} + void Mesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint); + ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint); + + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint"); + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); @@ -1035,6 +1052,200 @@ void ArrayMesh::regen_normalmaps() { } } +//dirty hack +bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL; + +struct ArrayMeshLightmapSurface { + + Ref<Material> material; + Vector<SurfaceTool::Vertex> vertices; + Mesh::PrimitiveType primitive; + uint32_t format; +}; + +Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { + + ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); + ERR_EXPLAIN("Can't unwrap mesh with blend shapes"); + ERR_FAIL_COND_V(blend_shapes.size() != 0, ERR_UNAVAILABLE); + + Vector<float> vertices; + Vector<float> normals; + Vector<int> indices; + Vector<int> face_materials; + Vector<float> uv; + Vector<Pair<int, int> > uv_index; + + Vector<ArrayMeshLightmapSurface> surfaces; + for (int i = 0; i < get_surface_count(); i++) { + ArrayMeshLightmapSurface s; + s.primitive = surface_get_primitive_type(i); + + if (s.primitive != Mesh::PRIMITIVE_TRIANGLES) { + ERR_EXPLAIN("Only triangles are supported for lightmap unwrap"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + s.format = surface_get_format(i); + if (!(s.format & ARRAY_FORMAT_NORMAL)) { + ERR_EXPLAIN("Normals are required for lightmap unwrap"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + + Array arrays = surface_get_arrays(i); + s.material = surface_get_material(i); + s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays); + + PoolVector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; + int vc = rvertices.size(); + PoolVector<Vector3>::Read r = rvertices.read(); + + PoolVector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL]; + PoolVector<Vector3>::Read rn = rnormals.read(); + + int vertex_ofs = vertices.size() / 3; + + vertices.resize((vertex_ofs + vc) * 3); + normals.resize((vertex_ofs + vc) * 3); + uv_index.resize(vertex_ofs + vc); + + for (int j = 0; j < vc; j++) { + + Vector3 v = p_base_transform.xform(r[j]); + + vertices[(j + vertex_ofs) * 3 + 0] = v.x; + vertices[(j + vertex_ofs) * 3 + 1] = v.y; + vertices[(j + vertex_ofs) * 3 + 2] = v.z; + normals[(j + vertex_ofs) * 3 + 0] = rn[j].x; + normals[(j + vertex_ofs) * 3 + 1] = rn[j].y; + normals[(j + vertex_ofs) * 3 + 2] = rn[j].z; + uv_index[j + vertex_ofs] = Pair<int, int>(i, j); + } + + PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX]; + int ic = rindices.size(); + int index_ofs = indices.size(); + + if (ic == 0) { + indices.resize(index_ofs + vc); + face_materials.resize((index_ofs + vc) / 3); + for (int j = 0; j < vc; j++) { + indices[index_ofs + j] = vertex_ofs + j; + } + for (int j = 0; j < vc / 3; j++) { + face_materials[(index_ofs / 3) + j] = i; + } + + } else { + PoolVector<int>::Read ri = rindices.read(); + indices.resize(index_ofs + ic); + face_materials.resize((index_ofs + ic) / 3); + for (int j = 0; j < ic; j++) { + indices[index_ofs + j] = vertex_ofs + ri[j]; + } + for (int j = 0; j < ic / 3; j++) { + face_materials[(index_ofs / 3) + j] = i; + } + } + + surfaces.push_back(s); + } + + //unwrap + + float *gen_uvs; + int *gen_vertices; + int *gen_indices; + int gen_vertex_count; + int gen_index_count; + int size_x; + int size_y; + + bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), face_materials.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y); + + if (!ok) { + return ERR_CANT_CREATE; + } + + //remove surfaces + while (get_surface_count()) { + surface_remove(0); + } + + //create surfacetools for each surface.. + Vector<Ref<SurfaceTool> > surfaces_tools; + + for (int i = 0; i < surfaces.size(); i++) { + Ref<SurfaceTool> st; + st.instance(); + st->begin(Mesh::PRIMITIVE_TRIANGLES); + st->set_material(surfaces[i].material); + surfaces_tools.push_back(st); //stay there + } + + print_line("gen indices: " + itos(gen_index_count)); + //go through all indices + for (int i = 0; i < gen_index_count; i += 3) { + + ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_index.size(), ERR_BUG); + ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_index.size(), ERR_BUG); + ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_index.size(), ERR_BUG); + + ERR_FAIL_COND_V(uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 1]]].first || uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG); + + int surface = uv_index[gen_vertices[gen_indices[i + 0]]].first; + + for (int j = 0; j < 3; j++) { + + int vertex_idx = gen_vertices[gen_indices[i + j]]; + + SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second]; + + if (surfaces[surface].format & ARRAY_FORMAT_COLOR) { + surfaces_tools[surface]->add_color(v.color); + } + if (surfaces[surface].format & ARRAY_FORMAT_TEX_UV) { + surfaces_tools[surface]->add_uv(v.uv); + } + if (surfaces[surface].format & ARRAY_FORMAT_NORMAL) { + surfaces_tools[surface]->add_normal(v.normal); + } + if (surfaces[surface].format & ARRAY_FORMAT_TANGENT) { + Plane t; + t.normal = v.tangent; + t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1; + surfaces_tools[surface]->add_tangent(t); + } + if (surfaces[surface].format & ARRAY_FORMAT_BONES) { + surfaces_tools[surface]->add_bones(v.bones); + } + if (surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) { + surfaces_tools[surface]->add_weights(v.weights); + } + + Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); + surfaces_tools[surface]->add_uv2(uv2); + + surfaces_tools[surface]->add_vertex(v.vertex); + } + } + + //free stuff + ::free(gen_vertices); + ::free(gen_indices); + ::free(gen_uvs); + + //generate surfaces + + for (int i = 0; i < surfaces_tools.size(); i++) { + surfaces_tools[i]->index(); + surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format); + } + + set_lightmap_size_hint(Size2(size_x, size_y)); + + return OK; +} + void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index b85a6a84af..ea38ebf2ff 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -43,6 +43,8 @@ class Mesh : public Resource { GDCLASS(Mesh, Resource); mutable Ref<TriangleMesh> triangle_mesh; //cached + Size2 lightmap_size_hint; + protected: void _clear_triangle_mesh() const; @@ -138,6 +140,9 @@ public: virtual AABB get_aabb() const = 0; + void set_lightmap_size_hint(const Vector2 &p_size); + Size2 get_lightmap_size_hint() const; + Mesh(); }; @@ -216,6 +221,8 @@ public: void center_geometry(); void regen_normalmaps(); + Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); + virtual void reload_from_file(); ArrayMesh(); diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp index 2ef20f67f5..a2c3f1f111 100644 --- a/scene/resources/sky_box.cpp +++ b/scene/resources/sky_box.cpp @@ -180,7 +180,7 @@ Ref<Image> ProceduralSky::_generate_sky() { normal.normalize(); - float v_angle = Math::acos(normal.y); + float v_angle = Math::acos(CLAMP(normal.y, -1.0, 1.0)); Color color; @@ -193,7 +193,7 @@ Ref<Image> ProceduralSky::_generate_sky() { float c = v_angle / (Math_PI * 0.5); color = sky_horizon_linear.linear_interpolate(sky_top_linear, Math::ease(1.0 - c, sky_curve)); - float sun_angle = Math::rad2deg(Math::acos(sun.dot(normal))); + float sun_angle = Math::rad2deg(Math::acos(CLAMP(sun.dot(normal), -1.0, 1.0))); if (sun_angle < sun_angle_min) { color = color.blend(sun_color); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index bf89e704bc..d8600e041d 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -101,6 +101,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { vtx.color = last_color; vtx.normal = last_normal; vtx.uv = last_uv; + vtx.uv2 = last_uv2; vtx.weights = last_weights; vtx.bones = last_bones; vtx.tangent = last_tangent.normal; @@ -401,7 +402,7 @@ Array SurfaceTool::commit_to_arrays() { return a; } -Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) { +Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) { Ref<ArrayMesh> mesh; if (p_existing.is_valid()) @@ -418,7 +419,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) { Array a = commit_to_arrays(); - mesh->add_surface_from_arrays(primitive, a); + mesh->add_surface_from_arrays(primitive, a, Array(), p_flags); if (material.is_valid()) mesh->surface_set_material(surface, material); @@ -482,6 +483,113 @@ void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List< _create_list_from_arrays(arr, r_vertex, r_index, lformat); } +Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays) { + + Vector<SurfaceTool::Vertex> ret; + + PoolVector<Vector3> varr = p_arrays[VS::ARRAY_VERTEX]; + PoolVector<Vector3> narr = p_arrays[VS::ARRAY_NORMAL]; + PoolVector<float> tarr = p_arrays[VS::ARRAY_TANGENT]; + PoolVector<Color> carr = p_arrays[VS::ARRAY_COLOR]; + PoolVector<Vector2> uvarr = p_arrays[VS::ARRAY_TEX_UV]; + PoolVector<Vector2> uv2arr = p_arrays[VS::ARRAY_TEX_UV2]; + PoolVector<int> barr = p_arrays[VS::ARRAY_BONES]; + PoolVector<float> warr = p_arrays[VS::ARRAY_WEIGHTS]; + + int vc = varr.size(); + + if (vc == 0) + return ret; + int lformat = 0; + + PoolVector<Vector3>::Read rv; + if (varr.size()) { + lformat |= VS::ARRAY_FORMAT_VERTEX; + rv = varr.read(); + } + PoolVector<Vector3>::Read rn; + if (narr.size()) { + lformat |= VS::ARRAY_FORMAT_NORMAL; + rn = narr.read(); + } + PoolVector<float>::Read rt; + if (tarr.size()) { + lformat |= VS::ARRAY_FORMAT_TANGENT; + rt = tarr.read(); + } + PoolVector<Color>::Read rc; + if (carr.size()) { + lformat |= VS::ARRAY_FORMAT_COLOR; + rc = carr.read(); + } + + PoolVector<Vector2>::Read ruv; + if (uvarr.size()) { + lformat |= VS::ARRAY_FORMAT_TEX_UV; + ruv = uvarr.read(); + } + + PoolVector<Vector2>::Read ruv2; + if (uv2arr.size()) { + lformat |= VS::ARRAY_FORMAT_TEX_UV2; + ruv2 = uv2arr.read(); + } + + PoolVector<int>::Read rb; + if (barr.size()) { + lformat |= VS::ARRAY_FORMAT_BONES; + rb = barr.read(); + } + + PoolVector<float>::Read rw; + if (warr.size()) { + lformat |= VS::ARRAY_FORMAT_WEIGHTS; + rw = warr.read(); + } + + for (int i = 0; i < vc; i++) { + + Vertex v; + if (lformat & VS::ARRAY_FORMAT_VERTEX) + v.vertex = varr[i]; + if (lformat & VS::ARRAY_FORMAT_NORMAL) + v.normal = narr[i]; + if (lformat & VS::ARRAY_FORMAT_TANGENT) { + Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]); + v.tangent = p.normal; + v.binormal = p.normal.cross(v.tangent).normalized() * p.d; + } + if (lformat & VS::ARRAY_FORMAT_COLOR) + v.color = carr[i]; + if (lformat & VS::ARRAY_FORMAT_TEX_UV) + v.uv = uvarr[i]; + if (lformat & VS::ARRAY_FORMAT_TEX_UV2) + v.uv2 = uv2arr[i]; + if (lformat & VS::ARRAY_FORMAT_BONES) { + Vector<int> b; + b.resize(4); + b[0] = barr[i * 4 + 0]; + b[1] = barr[i * 4 + 1]; + b[2] = barr[i * 4 + 2]; + b[3] = barr[i * 4 + 3]; + v.bones = b; + } + if (lformat & VS::ARRAY_FORMAT_WEIGHTS) { + Vector<float> w; + w.resize(4); + w[0] = warr[i * 4 + 0]; + w[1] = warr[i * 4 + 1]; + w[2] = warr[i * 4 + 2]; + w[3] = warr[i * 4 + 3]; + v.weights = w; + } + + ret.push_back(v); + } + + return ret; +} + void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) { PoolVector<Vector3> varr = arr[VS::ARRAY_VERTEX]; @@ -882,7 +990,7 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from); ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from); - ClassDB::bind_method(D_METHOD("commit", "existing"), &SurfaceTool::commit, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT)); } SurfaceTool::SurfaceTool() { diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index cdaac643de..b180ffe260 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -127,10 +127,11 @@ public: List<Vertex> &get_vertex_array() { return vertex_array; } void create_from_triangle_arrays(const Array &p_arrays); + static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays); Array commit_to_arrays(); void create_from(const Ref<Mesh> &p_existing, int p_surface); void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform); - Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>()); + Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT); SurfaceTool(); }; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 6fab597d2b..bd6b917d4e 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -83,7 +83,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { } } } else if (what == "occluder_map") { - tile_map[id].autotile_data.ocludder_map.clear(); + tile_map[id].autotile_data.occluder_map.clear(); Array p = p_value; Vector2 last_coord; while (p.size() > 0) { @@ -194,7 +194,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = p; } else if (what == "occluder_map") { Array p; - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = tile_map[id].autotile_data.ocludder_map.front(); E; E = E->next()) { + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = tile_map[id].autotile_data.occluder_map.front(); E; E = E->next()) { p.push_back(E->key()); p.push_back(E->value()); } @@ -643,20 +643,20 @@ Ref<OccluderPolygon2D> TileSet::tile_get_light_occluder(int p_id) const { void TileSet::autotile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder, const Vector2 &p_coord) { ERR_FAIL_COND(!tile_map.has(p_id)); if (p_light_occluder.is_null()) { - if (tile_map[p_id].autotile_data.ocludder_map.has(p_coord)) { - tile_map[p_id].autotile_data.ocludder_map.erase(p_coord); + if (tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { + tile_map[p_id].autotile_data.occluder_map.erase(p_coord); } } else { - tile_map[p_id].autotile_data.ocludder_map[p_coord] = p_light_occluder; + tile_map[p_id].autotile_data.occluder_map[p_coord] = p_light_occluder; } } Ref<OccluderPolygon2D> TileSet::autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const { ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<OccluderPolygon2D>()); - if (!tile_map[p_id].autotile_data.ocludder_map.has(p_coord)) { + if (!tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { return Ref<OccluderPolygon2D>(); } else { - return tile_map[p_id].autotile_data.ocludder_map[p_coord]; + return tile_map[p_id].autotile_data.occluder_map[p_coord]; } } @@ -688,7 +688,7 @@ const Map<Vector2, Ref<OccluderPolygon2D> > &TileSet::autotile_get_light_oclusio static Map<Vector2, Ref<OccluderPolygon2D> > dummy; ERR_FAIL_COND_V(!tile_map.has(p_id), dummy); - return tile_map[p_id].autotile_data.ocludder_map; + return tile_map[p_id].autotile_data.occluder_map; } void TileSet::autotile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon, const Vector2 &p_coord) { @@ -932,8 +932,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("find_tile_by_name", "name"), &TileSet::find_tile_by_name); ClassDB::bind_method(D_METHOD("get_tiles_ids"), &TileSet::_get_tiles_ids); - BIND_VMETHOD(MethodInfo("_is_tile_bound", PropertyInfo(Variant::INT, "drawn_id"), PropertyInfo(Variant::INT, "neighbor_id"))); - BIND_VMETHOD(MethodInfo("_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_tile_bound", PropertyInfo(Variant::INT, "drawn_id"), PropertyInfo(Variant::INT, "neighbor_id"))); + BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); BIND_ENUM_CONSTANT(BITMASK_2X2); BIND_ENUM_CONSTANT(BITMASK_3X3); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 4d2b02f54b..deac583f62 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -76,7 +76,7 @@ public: Size2 size; Vector2 icon_coord; Map<Vector2, uint16_t> flags; - Map<Vector2, Ref<OccluderPolygon2D> > ocludder_map; + Map<Vector2, Ref<OccluderPolygon2D> > occluder_map; Map<Vector2, Ref<NavigationPolygon> > navpoly_map; Map<Vector2, int> priority_map; |