diff options
Diffstat (limited to 'scene')
41 files changed, 732 insertions, 128 deletions
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index d4481583fb..c9e5d0f1bc 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -107,12 +107,12 @@ OccluderPolygon2D::~OccluderPolygon2D() { VS::get_singleton()->free(occ_polygon); } -#ifdef DEBUG_ENABLED void LightOccluder2D::_poly_changed() { +#ifdef DEBUG_ENABLED update(); -} #endif +} void LightOccluder2D::_notification(int p_what) { @@ -221,9 +221,7 @@ void LightOccluder2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &LightOccluder2D::set_occluder_light_mask); ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &LightOccluder2D::get_occluder_light_mask); -#ifdef DEBUG_ENABLED ClassDB::bind_method("_poly_changed", &LightOccluder2D::_poly_changed); -#endif ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"), "set_occluder_polygon", "get_occluder_polygon"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask"); diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index 5e16351a6f..d59c9100b0 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -78,9 +78,7 @@ class LightOccluder2D : public Node2D { int mask; Ref<OccluderPolygon2D> occluder_polygon; -#ifdef DEBUG_ENABLED void _poly_changed(); -#endif protected: void _notification(int p_what); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 229c2c6fe8..3e61dd05f4 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -270,7 +270,8 @@ void Line2D::_draw() { lb.indices, lb.vertices, lb.colors, - lb.uvs, + lb.uvs, Vector<int>(), Vector<float>(), + texture_rid); // DEBUG diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index f8cec72400..3813bd96fe 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -451,7 +451,7 @@ void Node2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_rotation_degrees", PROPERTY_HINT_NONE, "", 0), "set_global_rotation_degrees", "get_global_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); ADD_GROUP("Z Index", ""); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index bf5bf29b2e..4d6ebc81c3 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -30,7 +30,7 @@ #include "polygon_2d.h" #include "core/math/geometry.h" - +#include "skeleton_2d.h" Dictionary Polygon2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -91,8 +91,20 @@ void Polygon2D::_notification(int p_what) { if (polygon.size() < 3) return; + Skeleton2D *skeleton_node = NULL; + if (has_node(skeleton)) { + skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton)); + } + + if (skeleton_node) + VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); + else + VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); + Vector<Vector2> points; Vector<Vector2> uvs; + Vector<int> bones; + Vector<float> weights; points.resize(polygon.size()); @@ -180,6 +192,70 @@ void Polygon2D::_notification(int p_what) { } } + if (!invert && bone_weights.size()) { + //a skeleton is set! fill indices and weights + int vc = points.size(); + bones.resize(vc * 4); + weights.resize(vc * 4); + + int *bonesw = bones.ptrw(); + float *weightsw = weights.ptrw(); + + for (int i = 0; i < vc * 4; i++) { + bonesw[i] = 0; + weightsw[i] = 0; + } + + for (int i = 0; i < bone_weights.size(); i++) { + if (bone_weights[i].weights.size() != points.size()) { + continue; //different number of vertices, sorry not using. + } + if (!skeleton_node->has_node(bone_weights[i].path)) { + continue; //node does not exist + } + Bone2D *bone = Object::cast_to<Bone2D>(skeleton_node->get_node(bone_weights[i].path)); + if (!bone) { + continue; + } + + int bone_index = bone->get_index_in_skeleton(); + PoolVector<float>::Read r = bone_weights[i].weights.read(); + for (int j = 0; j < vc; j++) { + if (r[j] == 0.0) + continue; //weight is unpainted, skip + //find an index with a weight + for (int k = 0; k < 4; k++) { + if (weightsw[j * 4 + k] < r[j]) { + //this is less than this weight, insert weight! + for (int l = 3; l > k; l--) { + weightsw[j * 4 + l] = weightsw[j * 4 + l - 1]; + bonesw[j * 4 + l] = bonesw[j * 4 + l - 1]; + } + weightsw[j * 4 + k] = r[j]; + bonesw[j * 4 + k] = bone_index; + break; + } + } + } + } + + //normalize the weights + for (int i = 0; i < vc; i++) { + float tw = 0; + for (int j = 0; j < 4; j++) { + tw += weightsw[i * 4 + j]; + } + if (tw == 0) + continue; //unpainted, do nothing + + //normalize + for (int j = 0; j < 4; j++) { + weightsw[i * 4 + j] /= tw; + // print_line("point " + itos(i) + " idx " + itos(j) + " index: " + itos(bonesw[i * 4 + j]) + " weight: " + rtos(weightsw[i * 4 + j])); + } + } + } + Vector<Color> colors; int color_len = vertex_colors.size(); colors.resize(len); @@ -197,7 +273,8 @@ void Polygon2D::_notification(int p_what) { // VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); if (invert || splits.size() == 0) { - VS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID(), RID(), antialiased); + Vector<int> indices = Geometry::triangulate_polygon(points); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } else { //use splits Vector<int> loop; @@ -268,7 +345,7 @@ void Polygon2D::_notification(int p_what) { //print_line("loops: " + itos(loops.size()) + " indices: " + itos(indices.size())); - VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } } break; @@ -430,6 +507,74 @@ Vector2 Polygon2D::get_offset() const { return offset; } +void Polygon2D::add_bone(const NodePath &p_path, const PoolVector<float> &p_weights) { + + Bone bone; + bone.path = p_path; + bone.weights = p_weights; + bone_weights.push_back(bone); +} +int Polygon2D::get_bone_count() const { + return bone_weights.size(); +} +NodePath Polygon2D::get_bone_path(int p_index) const { + ERR_FAIL_INDEX_V(p_index, bone_weights.size(), NodePath()); + return bone_weights[p_index].path; +} +PoolVector<float> Polygon2D::get_bone_weights(int p_index) const { + + ERR_FAIL_INDEX_V(p_index, bone_weights.size(), PoolVector<float>()); + return bone_weights[p_index].weights; +} +void Polygon2D::erase_bone(int p_idx) { + + ERR_FAIL_INDEX(p_idx, bone_weights.size()); + bone_weights.remove(p_idx); +} + +void Polygon2D::clear_bones() { + bone_weights.clear(); +} + +void Polygon2D::set_bone_weights(int p_index, const PoolVector<float> &p_weights) { + ERR_FAIL_INDEX(p_index, bone_weights.size()); + bone_weights[p_index].weights = p_weights; + update(); +} +void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) { + ERR_FAIL_INDEX(p_index, bone_weights.size()); + bone_weights[p_index].path = p_path; + update(); +} + +Array Polygon2D::_get_bones() const { + Array bones; + for (int i = 0; i < get_bone_count(); i++) { + bones.push_back(get_bone_path(i)); + bones.push_back(get_bone_weights(i)); + } + return bones; +} +void Polygon2D::_set_bones(const Array &p_bones) { + + ERR_FAIL_COND(p_bones.size() & 1); + clear_bones(); + for (int i = 0; i < p_bones.size(); i += 2) { + add_bone(p_bones[i], p_bones[i + 1]); + } +} + +void Polygon2D::set_skeleton(const NodePath &p_skeleton) { + if (skeleton == p_skeleton) + return; + skeleton = p_skeleton; + update(); +} + +NodePath Polygon2D::get_skeleton() const { + return skeleton; +} + void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &Polygon2D::set_polygon); @@ -474,6 +619,21 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Polygon2D::set_offset); ClassDB::bind_method(D_METHOD("get_offset"), &Polygon2D::get_offset); + ClassDB::bind_method(D_METHOD("add_bone", "path", "weights"), &Polygon2D::add_bone); + ClassDB::bind_method(D_METHOD("get_bone_count"), &Polygon2D::get_bone_count); + ClassDB::bind_method(D_METHOD("get_bone_path", "index"), &Polygon2D::get_bone_path); + ClassDB::bind_method(D_METHOD("get_bone_weights", "index"), &Polygon2D::get_bone_weights); + ClassDB::bind_method(D_METHOD("erase_bone", "index"), &Polygon2D::erase_bone); + ClassDB::bind_method(D_METHOD("clear_bones"), &Polygon2D::clear_bones); + ClassDB::bind_method(D_METHOD("set_bone_path", "index", "path"), &Polygon2D::set_bone_path); + ClassDB::bind_method(D_METHOD("set_bone_weights", "index", "weights"), &Polygon2D::set_bone_weights); + + ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &Polygon2D::set_skeleton); + ClassDB::bind_method(D_METHOD("get_skeleton"), &Polygon2D::get_skeleton); + + ClassDB::bind_method(D_METHOD("_set_bones", "bones"), &Polygon2D::_set_bones); + ClassDB::bind_method(D_METHOD("_get_bones"), &Polygon2D::_get_bones); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv"); ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "splits"), "set_splits", "get_splits"); @@ -488,10 +648,14 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation"); + ADD_GROUP("Skeleton", ""); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton", "get_skeleton"); ADD_GROUP("Invert", "invert_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1"), "set_invert_border", "get_invert_border"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_bones", "_get_bones"); } Polygon2D::Polygon2D() { diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index 262208f2f1..575f71d74a 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -42,6 +42,13 @@ class Polygon2D : public Node2D { PoolVector<Color> vertex_colors; PoolVector<int> splits; + struct Bone { + NodePath path; + PoolVector<float> weights; + }; + + Vector<Bone> bone_weights; + Color color; Ref<Texture> texture; Size2 tex_scale; @@ -56,6 +63,11 @@ class Polygon2D : public Node2D { mutable bool rect_cache_dirty; mutable Rect2 item_rect; + NodePath skeleton; + + Array _get_bones() const; + void _set_bones(const Array &p_bones); + protected: void _notification(int p_what); static void _bind_methods(); @@ -114,6 +126,18 @@ public: void set_offset(const Vector2 &p_offset); Vector2 get_offset() const; + void add_bone(const NodePath &p_path = NodePath(), const PoolVector<float> &p_weights = PoolVector<float>()); + int get_bone_count() const; + NodePath get_bone_path(int p_index) const; + PoolVector<float> get_bone_weights(int p_index) const; + void erase_bone(int p_idx); + void clear_bones(); + void set_bone_weights(int p_index, const PoolVector<float> &p_weights); + void set_bone_path(int p_index, const NodePath &p_path); + + void set_skeleton(const NodePath &p_skeleton); + NodePath get_skeleton() const; + Polygon2D(); }; diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 705e82bcbb..2363c791fa 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -12,6 +12,8 @@ void Bone2D::_notification(int p_what) { break; if (!Object::cast_to<Bone2D>(parent)) break; //skeletons must be chained to Bone2Ds. + + parent = parent->get_parent(); } if (skeleton) { @@ -26,6 +28,11 @@ void Bone2D::_notification(int p_what) { skeleton->_make_transform_dirty(); } } + if (p_what == NOTIFICATION_MOVED_IN_PARENT) { + if (skeleton) { + skeleton->_make_bone_setup_dirty(); + } + } if (p_what == NOTIFICATION_EXIT_TREE) { if (skeleton) { @@ -46,12 +53,22 @@ void Bone2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest); ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest); ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest); + ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest); + ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton); + + ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length); + ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D,"rest"),"set_rest","get_rest"); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"default_length",PROPERTY_HINT_RANGE,"1,1024,1"),"set_default_length","get_default_length"); } void Bone2D::set_rest(const Transform2D &p_rest) { rest = p_rest; if (skeleton) skeleton->_make_bone_setup_dirty(); + + update_configuration_warning(); } Transform2D Bone2D::get_rest() const { @@ -71,22 +88,56 @@ void Bone2D::apply_rest() { set_transform(rest); } +void Bone2D::set_default_length(float p_length) { + + default_length=p_length; + +} + +float Bone2D::get_default_length() const { + return default_length; +} + +int Bone2D::get_index_in_skeleton() const { + ERR_FAIL_COND_V(!skeleton,-1); + skeleton->_update_bone_setup(); + return skeleton_index; +} String Bone2D::get_configuration_warning() const { + + String warning = Node2D::get_configuration_warning(); if (!skeleton) { + if (warning!=String()) { + warning+="\n"; + } if (parent_bone) { - return TTR("This Bone2D chain should end at a Skeleton2D node."); + warning+=TTR("This Bone2D chain should end at a Skeleton2D node."); } else { - return TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); + warning+=TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); + } + } + + if (rest==Transform2D(0,0,0,0,0,0)) { + if (warning!=String()) { + warning+="\n"; } + warning+=TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."); + } - return Node2D::get_configuration_warning(); + return warning; } Bone2D::Bone2D() { skeleton = NULL; parent_bone = NULL; + skeleton_index=-1; + default_length=16; set_notify_local_transform(true); + //this is a clever hack so the bone knows no rest has been set yet, allowing to show an error. + for(int i=0;i<3;i++) { + rest[i]=Vector2(0,0); + } } ////////////////////////////////////// @@ -112,7 +163,14 @@ void Skeleton2D::_update_bone_setup() { bones.sort(); //sorty so they are always in the same order/index for (int i = 0; i < bones.size(); i++) { - bones[i].rest_inverse = bones[i].bone->get_skeleton_rest(); //bind pose + bones[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose + bones[i].bone->skeleton_index=i; + Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent()); + if (parent_bone) { + bones[i].parent_index=parent_bone->skeleton_index; + } else { + bones[i].parent_index=-1; + } } transform_dirty = true; @@ -140,13 +198,20 @@ void Skeleton2D::_update_transform() { transform_dirty = false; - Transform2D global_xform = get_global_transform(); - Transform2D global_xform_inverse = global_xform.affine_inverse(); + for (int i = 0; i < bones.size(); i++) { + + ERR_CONTINUE(bones[i].parent_index>=i); + if (bones[i].parent_index>=0) { + bones[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform(); + } else { + bones[i].accum_transform = bones[i].bone->get_transform(); + } + } for (int i = 0; i < bones.size(); i++) { - Transform2D final_xform = bones[i].rest_inverse * bones[i].bone->get_relative_transform_to_parent(this); - VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, global_xform * (final_xform * global_xform_inverse)); + Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse; + VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform); } } @@ -177,10 +242,12 @@ void Skeleton2D::_notification(int p_what) { _update_bone_setup(); if (transform_dirty) _update_transform(); + + request_ready(); } if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - _make_transform_dirty(); + VS::get_singleton()->skeleton_set_base_transform_2d(skeleton,get_global_transform()); } } @@ -201,6 +268,7 @@ void Skeleton2D::_bind_methods() { Skeleton2D::Skeleton2D() { bone_setup_dirty = true; transform_dirty = true; + skeleton = VS::get_singleton()->skeleton_create(); } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 49199f684f..cd270dac85 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -11,6 +11,10 @@ class Bone2D : public Node2D { Bone2D *parent_bone; Skeleton2D *skeleton; Transform2D rest; + float default_length; + +friend class Skeleton2D; + int skeleton_index; protected: void _notification(int p_what); @@ -24,6 +28,11 @@ public: String get_configuration_warning() const; + void set_default_length(float p_length); + float get_default_length() const; + + int get_index_in_skeleton() const; + Bone2D(); }; @@ -37,6 +46,8 @@ class Skeleton2D : public Node2D { return p_bone.bone->is_greater_than(bone); } Bone2D *bone; + int parent_index; + Transform2D accum_transform; Transform2D rest_inverse; }; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 14eb26b1ec..3d3f43d5c6 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -304,6 +304,7 @@ void TileMap::_update_dirty_quadrants() { } q.occluder_instances.clear(); Ref<ShaderMaterial> prev_material; + int prev_z_index; RID prev_canvas_item; RID prev_debug_canvas_item; @@ -324,11 +325,12 @@ void TileMap::_update_dirty_quadrants() { continue; Ref<ShaderMaterial> mat = tile_set->tile_get_material(c.id); + int z_index = tile_set->tile_get_z_index(c.id); RID canvas_item; RID debug_canvas_item; - if (prev_canvas_item == RID() || prev_material != mat) { + if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) { canvas_item = vs->canvas_item_create(); if (mat.is_valid()) @@ -339,6 +341,7 @@ void TileMap::_update_dirty_quadrants() { xform.set_origin(q.pos); vs->canvas_item_set_transform(canvas_item, xform); vs->canvas_item_set_light_mask(canvas_item, get_light_mask()); + vs->canvas_item_set_z_index(canvas_item, z_index); q.canvas_items.push_back(canvas_item); @@ -354,6 +357,7 @@ void TileMap::_update_dirty_quadrants() { prev_canvas_item = canvas_item; prev_material = mat; + prev_z_index = z_index; } else { canvas_item = prev_canvas_item; diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 109bf3adc6..1b506e0c4f 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -132,9 +132,9 @@ public: virtual Transform get_camera_transform() const; - Vector3 project_ray_normal(const Point2 &p_pos) const; + virtual Vector3 project_ray_normal(const Point2 &p_pos) const; virtual Vector3 project_ray_origin(const Point2 &p_pos) const; - Vector3 project_local_ray_normal(const Point2 &p_pos) const; + virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; virtual Vector3 project_position(const Point2 &p_point) const; diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index 3a77360bc2..379dd21c39 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -173,6 +173,9 @@ String CollisionPolygon::get_configuration_warning() const { return String(); } +bool CollisionPolygon::_is_editable_3d_polygon() const { + return true; +} void CollisionPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth); @@ -184,6 +187,8 @@ void CollisionPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled); + ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h index 971c67f1ad..f1f137c9c5 100644 --- a/scene/3d/collision_polygon.h +++ b/scene/3d/collision_polygon.h @@ -53,6 +53,8 @@ protected: void _update_in_shape_owner(bool p_xform_only = false); + bool _is_editable_3d_polygon() const; + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 693b416f6d..a39ac5a8f5 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -1028,8 +1028,6 @@ void ParticlesMaterial::set_param(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value); } break; - case PARAM_MAX: { - }; } } float ParticlesMaterial::get_param(Parameter p_param) const { @@ -1082,8 +1080,6 @@ void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value); } break; - case PARAM_MAX: { - }; } } float ParticlesMaterial::get_param_randomness(Parameter p_param) const { @@ -1160,8 +1156,6 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); } break; - case PARAM_MAX: { - }; } _queue_shader_change(); @@ -1233,28 +1227,19 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) { emission_point_texture = p_points; - RID texture; - if (p_points.is_valid()) - texture = p_points->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points); } void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) { emission_normal_texture = p_normals; - RID texture; - if (p_normals.is_valid()) - texture = p_normals->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals); } void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) { emission_color_texture = p_colors; - RID texture; - if (p_colors.is_valid()) - texture = p_colors->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors); _queue_shader_change(); } @@ -1316,10 +1301,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail curve->ensure_default_setup(); } - RID texture; - if (p_trail_size_modifier.is_valid()) - texture = p_trail_size_modifier->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve); _queue_shader_change(); } @@ -1331,10 +1313,7 @@ Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { trail_color_modifier = p_trail_color_modifier; - RID texture; - if (p_trail_color_modifier.is_valid()) - texture = p_trail_color_modifier->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier); _queue_shader_change(); } diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index 7ac7f74bb0..57d79c960f 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -40,6 +40,9 @@ void Path::_curve_changed() { if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) update_gizmo(); + if (is_inside_tree()) { + emit_signal("curve_changed"); + } } void Path::set_curve(const Ref<Curve3D> &p_curve) { @@ -68,6 +71,8 @@ void Path::_bind_methods() { ClassDB::bind_method(D_METHOD("_curve_changed"), &Path::_curve_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve"); + + ADD_SIGNAL(MethodInfo("curve_changed")); } Path::Path() { diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index dab0e573d7..5deeb75c67 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -430,10 +430,9 @@ Ref<SpatialGizmo> Spatial::get_gizmo() const { #endif } -#ifdef TOOLS_ENABLED - void Spatial::_update_gizmo() { +#ifdef TOOLS_ENABLED if (!is_inside_world()) return; data.gizmo_dirty = false; @@ -445,8 +444,10 @@ void Spatial::_update_gizmo() { data.gizmo->clear(); } } +#endif } +#ifdef TOOLS_ENABLED void Spatial::set_disable_gizmo(bool p_enabled) { data.gizmo_disabled = p_enabled; @@ -726,9 +727,7 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel); ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world); -#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo); -#endif ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo); ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Spatial::set_gizmo); @@ -790,9 +789,7 @@ void Spatial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); ADD_GROUP("Visibility", ""); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); -#ifdef TOOLS_ENABLED ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo"); -#endif ADD_SIGNAL(MethodInfo("visibility_changed")); } diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 518bba9a51..ca35d85348 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -100,10 +100,8 @@ class Spatial : public Node { #endif } data; -#ifdef TOOLS_ENABLED void _update_gizmo(); -#endif void _notify_dirty(); void _propagate_transform_changed(Spatial *p_origin); diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index d389b69ef3..13700e0bd3 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -2338,9 +2338,9 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) { for (int k = 0; k < 3; k++) { if (i < 3) - face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); + face_points[j][(i + k) % 3] = v[k]; else - face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); + face_points[3 - j][(i + k) % 3] = -v[k]; } } diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 42fa20068b..afdb8b6f71 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -812,8 +812,6 @@ void AnimationTreePlayer::_process_animation(float p_delta) { t.value = t.object->get_indexed(t.subpath); t.value.zero(); - - t.skip = false; } /* STEP 2 PROCESS ANIMATIONS */ @@ -886,7 +884,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { Track &t = E->get(); - if (t.skip || !t.object) + if (!t.object) continue; if (t.subpath.size()) { // value track diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index 09d6f6fcb4..873ff8a9da 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -107,8 +107,6 @@ private: Vector3 scale; Variant value; - - bool skip; }; typedef Map<TrackKey, Track> TrackMap; diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index b401abd436..278e4123d7 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -36,6 +36,8 @@ void GridContainer::_notification(int p_what) { case NOTIFICATION_SORT_CHILDREN: { + int valid_controls_index; + Map<int, int> col_minw; // max of min_width of all controls in each col (indexed by col) Map<int, int> row_minh; // max of min_height of all controls in each row (indexed by row) Set<int> col_expanded; // columns which have the SIZE_EXPAND flag set @@ -47,13 +49,15 @@ void GridContainer::_notification(int p_what) { int max_row = get_child_count() / columns; // Compute the per-column/per-row data + valid_controls_index = 0; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); if (!c || !c->is_visible_in_tree()) continue; - int row = i / columns; - int col = i % columns; + int row = valid_controls_index / columns; + int col = valid_controls_index % columns; + valid_controls_index++; Size2i ms = c->get_combined_minimum_size(); if (col_minw.has(col)) @@ -136,12 +140,14 @@ void GridContainer::_notification(int p_what) { int col_ofs = 0; int row_ofs = 0; + valid_controls_index = 0; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); if (!c || !c->is_visible_in_tree()) continue; - int row = i / columns; - int col = i % columns; + int row = valid_controls_index / columns; + int col = valid_controls_index % columns; + valid_controls_index++; if (col == 0) { col_ofs = 0; @@ -178,6 +184,8 @@ void GridContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_columns", "columns"), &GridContainer::set_columns); ClassDB::bind_method(D_METHOD("get_columns"), &GridContainer::get_columns); + ClassDB::bind_method(D_METHOD("get_child_control_at_cell", "row", "column"), + &GridContainer::get_child_control_at_cell); ADD_PROPERTY(PropertyInfo(Variant::INT, "columns", PROPERTY_HINT_RANGE, "1,1024,1"), "set_columns", "get_columns"); } @@ -190,17 +198,19 @@ Size2 GridContainer::get_minimum_size() const { int hsep = get_constant("hseparation"); int vsep = get_constant("vseparation"); - int idx = 0; int max_row = 0; int max_col = 0; + int valid_controls_index = 0; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); if (!c || !c->is_visible_in_tree()) continue; - int row = idx / columns; - int col = idx % columns; + int row = valid_controls_index / columns; + int col = valid_controls_index % columns; + valid_controls_index++; + Size2i ms = c->get_combined_minimum_size(); if (col_minw.has(col)) col_minw[col] = MAX(col_minw[col], ms.width); @@ -213,7 +223,6 @@ Size2 GridContainer::get_minimum_size() const { row_minh[row] = ms.height; max_col = MAX(col, max_col); max_row = MAX(row, max_row); - idx++; } Size2 ms; @@ -232,6 +241,21 @@ Size2 GridContainer::get_minimum_size() const { return ms; } +Control *GridContainer::get_child_control_at_cell(int row, int column) { + Control *c; + int grid_index = row * columns + column; + for (int i = 0; i < get_child_count(); i++) { + c = Object::cast_to<Control>(get_child(i)); + if (!c || !c->is_visible_in_tree()) + continue; + + if (grid_index == i) { + break; + } + } + return c; +} + GridContainer::GridContainer() { set_mouse_filter(MOUSE_FILTER_PASS); diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h index 243d06f034..7e3470dc89 100644 --- a/scene/gui/grid_container.h +++ b/scene/gui/grid_container.h @@ -47,6 +47,7 @@ public: void set_columns(int p_columns); int get_columns() const; virtual Size2 get_minimum_size() const; + Control *get_child_control_at_cell(int row, int column); GridContainer(); }; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index fe5f3b769c..1ceb3f0a8b 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -215,6 +215,12 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case (KEY_A): { //Select All select(); } break; + case (KEY_LEFT): { // Go to start of text - like HOME key + set_cursor_position(0); + } break; + case (KEY_RIGHT): { // Go to end of text - like END key + set_cursor_position(text.length()); + } break; default: { handled = false; } } @@ -663,8 +669,8 @@ void LineEdit::_notification(int p_what) { if (ofs >= ime_text.length()) break; - CharType cchar = (pass && !text.empty()) ? '*' : ime_text[ofs]; - CharType next = (pass && !text.empty()) ? '*' : ime_text[ofs + 1]; + CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; + CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; int im_char_width = font->get_char_size(cchar, next).width; if ((x_ofs + im_char_width) > ofs_max) @@ -685,8 +691,8 @@ void LineEdit::_notification(int p_what) { } } - CharType cchar = (pass && !text.empty()) ? '*' : t[char_ofs]; - CharType next = (pass && !text.empty()) ? '*' : t[char_ofs + 1]; + CharType cchar = (pass && !text.empty()) ? secret_character[0] : t[char_ofs]; + CharType next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1]; int char_width = font->get_char_size(cchar, next).width; // end of widget, break! @@ -717,8 +723,8 @@ void LineEdit::_notification(int p_what) { if (ofs >= ime_text.length()) break; - CharType cchar = (pass && !text.empty()) ? '*' : ime_text[ofs]; - CharType next = (pass && !text.empty()) ? '*' : ime_text[ofs + 1]; + CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; + CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; int im_char_width = font->get_char_size(cchar, next).width; if ((x_ofs + im_char_width) > ofs_max) @@ -1137,7 +1143,6 @@ void LineEdit::clear_internal() { _clear_undo_stack(); cached_width = 0; - cached_placeholder_width = 0; cursor_pos = 0; window_pos = 0; undo_text = ""; @@ -1225,6 +1230,7 @@ void LineEdit::select_all() { selection.enabled = true; update(); } + void LineEdit::set_editable(bool p_editable) { editable = p_editable; @@ -1241,11 +1247,27 @@ void LineEdit::set_secret(bool p_secret) { pass = p_secret; update(); } + bool LineEdit::is_secret() const { return pass; } +void LineEdit::set_secret_character(const String &p_string) { + + // An empty string as the secret character would crash the engine + // It also wouldn't make sense to use multiple characters as the secret character + ERR_EXPLAIN("Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)"); + ERR_FAIL_COND(p_string.length() != 1); + + secret_character = p_string; + update(); +} + +String LineEdit::get_secret_character() const { + return secret_character; +} + void LineEdit::select(int p_from, int p_to) { if (p_from == 0 && p_to == 0) { @@ -1327,12 +1349,12 @@ PopupMenu *LineEdit::get_menu() const { return menu; } -#ifdef TOOLS_ENABLED void LineEdit::_editor_settings_changed() { +#ifdef TOOLS_ENABLED cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false)); cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65)); -} #endif +} void LineEdit::set_expand_to_text_length(bool p_enabled) { @@ -1401,9 +1423,7 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed); ClassDB::bind_method(D_METHOD("_toggle_draw_caret"), &LineEdit::_toggle_draw_caret); -#ifdef TOOLS_ENABLED ClassDB::bind_method("_editor_settings_changed", &LineEdit::_editor_settings_changed); -#endif ClassDB::bind_method(D_METHOD("set_align", "align"), &LineEdit::set_align); ClassDB::bind_method(D_METHOD("get_align"), &LineEdit::get_align); @@ -1434,6 +1454,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_editable"), &LineEdit::is_editable); ClassDB::bind_method(D_METHOD("set_secret", "enabled"), &LineEdit::set_secret); ClassDB::bind_method(D_METHOD("is_secret"), &LineEdit::is_secret); + ClassDB::bind_method(D_METHOD("set_secret_character", "character"), &LineEdit::set_secret_character); + ClassDB::bind_method(D_METHOD("get_secret_character"), &LineEdit::get_secret_character); ClassDB::bind_method(D_METHOD("menu_option", "option"), &LineEdit::menu_option); ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled); @@ -1461,6 +1483,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "max_length"), "set_max_length", "get_max_length"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret"); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length"); ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); @@ -1469,7 +1492,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha"); ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed"); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position"); } @@ -1485,6 +1508,7 @@ LineEdit::LineEdit() { window_has_focus = true; max_length = 0; pass = false; + secret_character = "*"; text_changed_dirty = false; placeholder_alpha = 0.6; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index c60ea36cc1..304faed9bd 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -72,6 +72,7 @@ private: String undo_text; String text; String placeholder; + String secret_character; float placeholder_alpha; String ime_text; Point2 ime_selection; @@ -134,9 +135,7 @@ private: void clear_internal(); void changed_internal(); -#ifdef TOOLS_ENABLED void _editor_settings_changed(); -#endif void _gui_input(Ref<InputEvent> p_event); void _notification(int p_what); @@ -194,6 +193,9 @@ public: void set_secret(bool p_secret); bool is_secret() const; + void set_secret_character(const String &p_string); + String get_secret_character() const; + virtual Size2 get_minimum_size() const; void set_expand_to_text_length(bool p_enabled); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 6bfc4d4dee..ffc8a72164 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -90,7 +90,7 @@ Rect2 RichTextLabel::_get_text_rect() { Ref<StyleBox> style = get_stylebox("normal"); return Rect2(style->get_offset(), get_size() - style->get_minimum_size()); } -int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) { +int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) { RID ci; if (r_outside) @@ -269,10 +269,12 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int descent = font->get_descent(); Color color; + Color font_color_shadow; bool underline = false; if (p_mode == PROCESS_DRAW) { color = _find_color(text, p_base_color); + font_color_shadow = _find_color(text, p_font_color_shadow); underline = _find_underline(text); if (_find_meta(text, &meta)) { @@ -284,7 +286,6 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & } rchar = 0; - while (*c) { int end = 0; @@ -297,7 +298,6 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; } - while (c[end] != 0 && !(end && c[end - 1] == ' ' && c[end] != ' ')) { int cw = font->get_char_size(c[end], c[end + 1]).width; @@ -314,7 +314,6 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & end++; } - CHECK_HEIGHT(fh); ENSURE_WIDTH(w); @@ -376,16 +375,30 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & if (c[i] == '\t') visible = false; - if (selected) { + if (visible) { + if (selected) { + cw = font->get_char_size(c[i], c[i + 1]).x; + draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg); + } - cw = font->get_char_size(c[i], c[i + 1]).x; - draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg); - if (visible) - font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), c[i], c[i + 1], override_selected_font_color ? selection_fg : color); + if (p_font_color_shadow.a > 0) { + float x_ofs_shadow = align_ofs + pofs; + float y_ofs_shadow = y + lh - line_descent; + float move = font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs, c[i], c[i + 1], p_font_color_shadow); + + if (p_shadow_as_outline) { + font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y), c[i], c[i + 1], p_font_color_shadow); + font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y), c[i], c[i + 1], p_font_color_shadow); + font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y), c[i], c[i + 1], p_font_color_shadow); + } + x_ofs_shadow += move; + } - } else { - if (visible) + if (selected) { + font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), c[i], c[i + 1], override_selected_font_color ? selection_fg : color); + } else { cw = font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), c[i], c[i + 1], color); + } } p_char_count++; @@ -464,6 +477,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int vseparation = get_constant("table_vseparation"); Color ccolor = _find_color(table, p_base_color); Vector2 draw_ofs = Point2(wofs, y); + Color font_color_shadow = get_color("font_color_shadow"); + bool use_outline = get_constant("shadow_as_outline"); + Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); if (p_mode == PROCESS_CACHE) { @@ -487,7 +503,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { - _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color()); + _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs); table->columns[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); table->columns[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width); } @@ -560,7 +576,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { int ly = 0; - _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color()); + _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs); frame->lines[i].height_cache = ly; //actual height frame->lines[i].height_accum_cache = ly; //actual height } @@ -593,9 +609,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & if (visible) { if (p_mode == PROCESS_DRAW) { - nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor); + nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs); } else if (p_mode == PROCESS_POINTER) { - _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, p_click_pos, r_click_item, r_click_char, r_outside); + _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs, p_click_pos, r_click_item, r_click_char, r_outside); if (r_click_item && *r_click_item) { RETURN; // exit early } @@ -767,12 +783,18 @@ void RichTextLabel::_notification(int p_what) { int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs; Ref<Font> base_font = get_font("normal_font"); Color base_color = get_color("default_color"); + Color font_color_shadow = get_color("font_color_shadow"); + bool use_outline = get_constant("shadow_as_outline"); + Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); + + float x_ofs = 0; visible_line_count = 0; while (y < size.height && from_line < main->lines.size()) { - visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, Point2i(), NULL, NULL, NULL, total_chars); + visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), NULL, NULL, NULL, total_chars); total_chars += main->lines[from_line].char_count; + from_line++; } } @@ -787,6 +809,9 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Size2 size = get_size(); Rect2 text_rect = _get_text_rect(); int ofs = vscroll->get_value(); + Color font_color_shadow = get_color("font_color_shadow"); + bool use_outline = get_constant("shadow_as_outline"); + Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); //todo, change to binary search int from_line = 0; @@ -807,7 +832,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) { - _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, p_click, r_click_item, r_click_char, r_outside); + _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, p_click, r_click_item, r_click_char, r_outside); if (r_click_item && *r_click_item) return; from_line++; @@ -867,9 +892,9 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { // Erase previous selection. if (selection.active) { selection.from = NULL; - selection.from_char = NULL; + selection.from_char = '\0'; selection.to = NULL; - selection.to_char = NULL; + selection.to_char = '\0'; selection.active = false; update(); @@ -1182,13 +1207,16 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { //validate invalid lines Size2 size = get_size(); Rect2 text_rect = _get_text_rect(); + Color font_color_shadow = get_color("font_color_shadow"); + bool use_outline = get_constant("shadow_as_outline"); + Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); Ref<Font> base_font = get_font("normal_font"); for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) { int y = 0; - _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color()); + _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color(), font_color_shadow, use_outline, shadow_ofs); p_frame->lines[i].height_cache = y; p_frame->lines[i].height_accum_cache = y; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 83938cff61..850638bff3 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -270,7 +270,7 @@ private: int visible_characters; float percent_visible; - int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Point2i &p_click_pos = Point2i(), Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL, int p_char_count = 0); + int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL, int p_char_count = 0); void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL); Ref<Font> _find_font(Item *p_item); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index ff0f5815d0..d451a6536e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2410,6 +2410,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_line(line); cursor_set_column(column); +#ifdef APPLE_STYLE_KEYS + } else if (k->get_command()) { + int cursor_current_column = cursor.column; + cursor.column = 0; + _remove_text(cursor.line, 0, cursor.line, cursor_current_column); +#endif } else { if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) unfold_line(cursor.line - 1); @@ -2684,7 +2690,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { next_line = line; next_column = column; - +#ifdef APPLE_STYLE_KEYS + } else if (k->get_command()) { + next_column = curline_len; + next_line = cursor.line; +#endif } else { next_column = cursor.column < curline_len ? (cursor.column + 1) : 0; } @@ -4978,6 +4988,11 @@ void TextEdit::set_indent_size(const int p_size) { update(); } +int TextEdit::get_indent_size() { + + return indent_size; +} + void TextEdit::set_draw_tabs(bool p_draw) { draw_tabs = p_draw; @@ -5644,7 +5659,7 @@ void TextEdit::_bind_methods() { ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed"); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret"); ADD_SIGNAL(MethodInfo("cursor_changed")); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 30e70bfd0b..60c6ab4929 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -557,6 +557,7 @@ public: void set_indent_using_spaces(const bool p_use_spaces); bool is_indent_using_spaces() const; void set_indent_size(const int p_size); + int get_indent_size(); void set_draw_tabs(bool p_draw); bool is_drawing_tabs() const; void set_override_selected_font_color(bool p_override_selected_font_color); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index fcf8768094..a1d79e7357 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -979,9 +979,23 @@ void Node::_set_name_nocheck(const StringName &p_name) { data.name = p_name; } +String Node::invalid_character = ". : @ / \""; + +bool Node::_validate_node_name(String &p_name) { + String name = p_name; + Vector<String> chars = Node::invalid_character.split(" "); + for (int i = 0; i < chars.size(); i++) { + name = name.replace(chars[i], ""); + } + bool is_valid = name == p_name; + p_name = name; + return is_valid; +} + void Node::set_name(const String &p_name) { - String name = p_name.replace(":", "").replace("/", "").replace("@", ""); + String name = p_name; + _validate_node_name(name); ERR_FAIL_COND(name == ""); data.name = name; @@ -2567,18 +2581,21 @@ Array Node::_get_children() const { return arr; } -#ifdef TOOLS_ENABLED void Node::set_import_path(const NodePath &p_import_path) { +#ifdef TOOLS_ENABLED data.import_path = p_import_path; +#endif } NodePath Node::get_import_path() const { +#ifdef TOOLS_ENABLED return data.import_path; -} - +#else + return NodePath(); #endif +} static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) { @@ -2737,13 +2754,10 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config); ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config); -#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path); ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path); ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path"); -#endif - { MethodInfo mi; diff --git a/scene/main/node.h b/scene/main/node.h index b9bafb1ed1..b5a956116d 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -190,6 +190,12 @@ private: void _set_tree(SceneTree *p_tree); +#ifdef TOOLS_ENABLED + friend class SceneTreeEditor; +#endif + static String invalid_character; + static bool _validate_node_name(String &p_name); + protected: void _block() { data.blocked++; } void _unblock() { data.blocked--; } @@ -374,10 +380,8 @@ public: void force_parent_owned() { data.parent_owned = true; } //hack to avoid duplicate nodes -#ifdef TOOLS_ENABLED void set_import_path(const NodePath &p_import_path); //path used when imported, used by scene editors to keep tracking NodePath get_import_path() const; -#endif bool is_owned_by_parent() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 4419dfe70f..011087b487 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "io/marshalls.h" #include "io/resource_loader.h" +#include "main/input_default.h" #include "message_queue.h" #include "node.h" #include "os/keyboard.h" @@ -620,6 +621,13 @@ void SceneTree::_notification(int p_notification) { case NOTIFICATION_WM_FOCUS_IN: case NOTIFICATION_WM_FOCUS_OUT: { + if (p_notification == NOTIFICATION_WM_FOCUS_IN) { + InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); + if (id) { + id->ensure_touch_mouse_raised(); + } + } + get_root()->propagate_notification(p_notification); } break; case NOTIFICATION_TRANSLATION_CHANGED: { @@ -1197,16 +1205,20 @@ void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, c _update_root_rect(); } -#ifdef TOOLS_ENABLED void SceneTree::set_edited_scene_root(Node *p_node) { +#ifdef TOOLS_ENABLED edited_scene_root = p_node; +#endif } Node *SceneTree::get_edited_scene_root() const { +#ifdef TOOLS_ENABLED return edited_scene_root; -} +#else + return NULL; #endif +} void SceneTree::set_current_scene(Node *p_scene) { @@ -1737,10 +1749,8 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint); ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint); -#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root); ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root); -#endif ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); @@ -1815,9 +1825,7 @@ void SceneTree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_font_oversampling"), "set_use_font_oversampling", "is_using_font_oversampling"); -#ifdef TOOLS_ENABLED ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root"); -#endif ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "", "get_root"); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 203c1d9c9c..9c06e4ded3 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -390,10 +390,8 @@ public: //void change_scene(const String& p_path); //Node *get_loaded_scene(); -#ifdef TOOLS_ENABLED void set_edited_scene_root(Node *p_node); Node *get_edited_scene_root() const; -#endif void set_current_scene(Node *p_scene); Node *get_current_scene() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 19d8f09ebe..d94b32afd7 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -58,6 +58,7 @@ #include "scene/2d/ray_cast_2d.h" #include "scene/2d/remote_transform_2d.h" #include "scene/2d/screen_button.h" +#include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" #include "scene/2d/tile_map.h" #include "scene/2d/visibility_notifier_2d.h" @@ -449,6 +450,8 @@ void register_scene_types() { ClassDB::register_class<VisibilityNotifier2D>(); ClassDB::register_class<VisibilityEnabler2D>(); ClassDB::register_class<Polygon2D>(); + ClassDB::register_class<Skeleton2D>(); + ClassDB::register_class<Bone2D>(); ClassDB::register_class<Light2D>(); ClassDB::register_class<LightOccluder2D>(); ClassDB::register_class<OccluderPolygon2D>(); diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 5fd6f6c74d..4ec1e8973d 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -806,6 +806,87 @@ float Curve2D::get_bake_interval() const { return bake_interval; } +Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const { + // Brute force method + + if (baked_cache_dirty) + _bake(); + + //validate// + int pc = baked_point_cache.size(); + if (pc == 0) { + ERR_EXPLAIN("No points in Curve2D"); + ERR_FAIL_COND_V(pc == 0, Vector2()); + } + + if (pc == 1) + return baked_point_cache.get(0); + + PoolVector2Array::Read r = baked_point_cache.read(); + + Vector2 nearest; + float nearest_dist = -1.0f; + + for (int i = 0; i < pc - 1; i++) { + Vector2 origin = r[i]; + Vector2 direction = (r[i + 1] - origin) / bake_interval; + + float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval); + Vector2 proj = origin + direction * d; + + float dist = proj.distance_squared_to(p_to_point); + + if (nearest_dist < 0.0f || dist < nearest_dist) { + nearest = proj; + nearest_dist = dist; + } + } + + return nearest; +} + +float Curve2D::get_closest_offset(const Vector2 &p_to_point) const { + // Brute force method + + if (baked_cache_dirty) + _bake(); + + //validate// + int pc = baked_point_cache.size(); + if (pc == 0) { + ERR_EXPLAIN("No points in Curve2D"); + ERR_FAIL_COND_V(pc == 0, 0.0f); + } + + if (pc == 1) + return 0.0f; + + PoolVector2Array::Read r = baked_point_cache.read(); + + float nearest = 0.0f; + float nearest_dist = -1.0f; + float offset = 0.0f; + + for (int i = 0; i < pc - 1; i++) { + Vector2 origin = r[i]; + Vector2 direction = (r[i + 1] - origin) / bake_interval; + + float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval); + Vector2 proj = origin + direction * d; + + float dist = proj.distance_squared_to(p_to_point); + + if (nearest_dist < 0.0f || dist < nearest_dist) { + nearest = offset + d; + nearest_dist = dist; + } + + offset += bake_interval; + } + + return nearest; +} + Dictionary Curve2D::_get_data() const { Dictionary dc; @@ -909,6 +990,8 @@ void Curve2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length); ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve2D::interpolate_baked, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points); + ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point); + ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset); ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve2D::tessellate, DEFVAL(5), DEFVAL(4)); ClassDB::bind_method(D_METHOD("_get_data"), &Curve2D::_get_data); @@ -1276,6 +1359,87 @@ PoolRealArray Curve3D::get_baked_tilts() const { return baked_tilt_cache; } +Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const { + // Brute force method + + if (baked_cache_dirty) + _bake(); + + //validate// + int pc = baked_point_cache.size(); + if (pc == 0) { + ERR_EXPLAIN("No points in Curve3D"); + ERR_FAIL_COND_V(pc == 0, Vector3()); + } + + if (pc == 1) + return baked_point_cache.get(0); + + PoolVector3Array::Read r = baked_point_cache.read(); + + Vector3 nearest; + float nearest_dist = -1.0f; + + for (int i = 0; i < pc - 1; i++) { + Vector3 origin = r[i]; + Vector3 direction = (r[i + 1] - origin) / bake_interval; + + float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval); + Vector3 proj = origin + direction * d; + + float dist = proj.distance_squared_to(p_to_point); + + if (nearest_dist < 0.0f || dist < nearest_dist) { + nearest = proj; + nearest_dist = dist; + } + } + + return nearest; +} + +float Curve3D::get_closest_offset(const Vector3 &p_to_point) const { + // Brute force method + + if (baked_cache_dirty) + _bake(); + + //validate// + int pc = baked_point_cache.size(); + if (pc == 0) { + ERR_EXPLAIN("No points in Curve3D"); + ERR_FAIL_COND_V(pc == 0, 0.0f); + } + + if (pc == 1) + return 0.0f; + + PoolVector3Array::Read r = baked_point_cache.read(); + + float nearest = 0.0f; + float nearest_dist = -1.0f; + float offset = 0.0f; + + for (int i = 0; i < pc - 1; i++) { + Vector3 origin = r[i]; + Vector3 direction = (r[i + 1] - origin) / bake_interval; + + float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval); + Vector3 proj = origin + direction * d; + + float dist = proj.distance_squared_to(p_to_point); + + if (nearest_dist < 0.0f || dist < nearest_dist) { + nearest = offset + d; + nearest_dist = dist; + } + + offset += bake_interval; + } + + return nearest; +} + void Curve3D::set_bake_interval(float p_tolerance) { bake_interval = p_tolerance; @@ -1404,6 +1568,8 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points); ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts); + ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve3D::get_closest_point); + ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve3D::get_closest_offset); ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4)); ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 4f55e4055c..492eb05d1e 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -199,6 +199,8 @@ public: float get_baked_length() const; Vector2 interpolate_baked(float p_offset, bool p_cubic = false) const; PoolVector2Array get_baked_points() const; //useful for going through + Vector2 get_closest_point(const Vector2 &p_to_point) const; + float get_closest_offset(const Vector2 &p_to_point) const; PoolVector2Array tessellate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display @@ -268,6 +270,8 @@ public: float interpolate_baked_tilt(float p_offset) const; PoolVector3Array get_baked_points() const; //useful for going through PoolRealArray get_baked_tilts() const; //useful for going through + Vector3 get_closest_point(const Vector3 &p_to_point) const; + float get_closest_offset(const Vector3 &p_to_point) const; PoolVector3Array tessellate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index ea70797530..2e652a00f9 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -818,6 +818,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color_selected", "RichTextLabel", font_color_selection); theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8)); + theme->set_color("font_color_shadow", "RichTextLabel", Color(0, 0, 0, 0)); + + theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * scale); + theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * scale); + theme->set_constant("shadow_as_outline", "RichTextLabel", 0 * scale); + theme->set_constant("line_separation", "RichTextLabel", 1 * scale); theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale); theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index b832ea1239..d87644381c 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -912,6 +912,7 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) VisualServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid()); _change_notify("material"); + emit_changed(); } void ArrayMesh::surface_set_name(int p_idx, const String &p_name) { @@ -919,6 +920,7 @@ void ArrayMesh::surface_set_name(int p_idx, const String &p_name) { ERR_FAIL_INDEX(p_idx, surfaces.size()); surfaces[p_idx].name = p_name; + emit_changed(); } String ArrayMesh::surface_get_name(int p_idx) const { @@ -931,6 +933,7 @@ void ArrayMesh::surface_update_region(int p_surface, int p_offset, const PoolVec ERR_FAIL_INDEX(p_surface, surfaces.size()); VS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data); + emit_changed(); } void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) { @@ -938,6 +941,7 @@ void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) { ERR_FAIL_INDEX(p_idx, surfaces.size()); surfaces[p_idx].aabb = p_aabb; // set custom aabb too? + emit_changed(); } Ref<Material> ArrayMesh::surface_get_material(int p_idx) const { @@ -986,6 +990,7 @@ void ArrayMesh::set_custom_aabb(const AABB &p_custom) { custom_aabb = p_custom; VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb); + emit_changed(); } AABB ArrayMesh::get_custom_aabb() const { diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 94c54c91d3..ad63422aad 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -65,6 +65,8 @@ void PrimitiveMesh::_update() const { pending_request = false; _clear_triangle_mesh(); + + const_cast<PrimitiveMesh *>(this)->emit_changed(); } void PrimitiveMesh::_request_update() { @@ -164,7 +166,11 @@ void PrimitiveMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mesh_arrays"), &PrimitiveMesh::get_mesh_arrays); + ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &PrimitiveMesh::set_custom_aabb); + ClassDB::bind_method(D_METHOD("get_custom_aabb"), &PrimitiveMesh::get_custom_aabb); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); } void PrimitiveMesh::set_material(const Ref<Material> &p_material) { @@ -185,6 +191,18 @@ Array PrimitiveMesh::get_mesh_arrays() const { return surface_get_arrays(0); } +void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) { + + custom_aabb = p_custom; + VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb); + emit_changed(); +} + +AABB PrimitiveMesh::get_custom_aabb() const { + + return custom_aabb; +} + PrimitiveMesh::PrimitiveMesh() { // defaults mesh = VisualServer::get_singleton()->mesh_create(); diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 94a7a055a3..23d1671d5c 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -48,6 +48,7 @@ class PrimitiveMesh : public Mesh { private: RID mesh; mutable AABB aabb; + AABB custom_aabb; Ref<Material> material; @@ -81,6 +82,9 @@ public: Array get_mesh_arrays() const; + void set_custom_aabb(const AABB &p_custom); + AABB get_custom_aabb() const; + PrimitiveMesh(); ~PrimitiveMesh(); }; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 626fda50df..ad5a0fd9ab 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -106,7 +106,11 @@ void StyleBoxTexture::set_texture(Ref<Texture> p_texture) { if (texture == p_texture) return; texture = p_texture; - region_rect = Rect2(Point2(), texture->get_size()); + if (p_texture.is_null()) { + region_rect = Rect2(0, 0, 0, 0); + } else { + region_rect = Rect2(Point2(), texture->get_size()); + } emit_signal("texture_changed"); emit_changed(); _change_notify("texture"); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index bebbf6e238..42d64376f5 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -142,6 +142,8 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_navigation_polygon(id, p_value); else if (what == "navigation_offset") tile_set_navigation_polygon_offset(id, p_value); + else if (what == "z_index") + tile_set_z_index(id, p_value); else return false; @@ -239,6 +241,8 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = tile_get_navigation_polygon(id); else if (what == "navigation_offset") r_ret = tile_get_navigation_polygon_offset(id); + else if (what == "z_index") + r_ret = tile_get_z_index(id); else return false; @@ -278,6 +282,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { 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)); + p_list->push_back(PropertyInfo(Variant::INT, pre + "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1")); } } @@ -748,6 +753,19 @@ Vector<TileSet::ShapeData> TileSet::tile_get_shapes(int p_id) const { return tile_map[p_id].shapes_data; } +int TileSet::tile_get_z_index(int p_id) const { + + ERR_FAIL_COND_V(!tile_map.has(p_id), 0); + return tile_map[p_id].z_index; +} + +void TileSet::tile_set_z_index(int p_id, int p_z_index) { + + ERR_FAIL_COND(!tile_map.has(p_id)); + tile_map[p_id].z_index = p_z_index; + emit_changed(); +} + void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { ERR_FAIL_COND(!tile_map.has(p_id)); @@ -929,6 +947,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_light_occluder", "id"), &TileSet::tile_get_light_occluder); ClassDB::bind_method(D_METHOD("tile_set_occluder_offset", "id", "occluder_offset"), &TileSet::tile_set_occluder_offset); ClassDB::bind_method(D_METHOD("tile_get_occluder_offset", "id"), &TileSet::tile_get_occluder_offset); + ClassDB::bind_method(D_METHOD("tile_set_z_index", "id", "z_index"), &TileSet::tile_set_z_index); + ClassDB::bind_method(D_METHOD("tile_get_z_index", "id"), &TileSet::tile_get_z_index); ClassDB::bind_method(D_METHOD("remove_tile", "id"), &TileSet::remove_tile); ClassDB::bind_method(D_METHOD("clear"), &TileSet::clear); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 706d04998f..d5704ac9a0 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -113,11 +113,13 @@ private: Color modulate; TileMode tile_mode; AutotileData autotile_data; + int z_index; // Default modulate for back-compat explicit TileData() : tile_mode(SINGLE_TILE), - modulate(1, 1, 1) {} + modulate(1, 1, 1), + z_index(0) {} }; Map<int, TileData> tile_map; @@ -220,6 +222,9 @@ public: Ref<NavigationPolygon> autotile_get_navigation_polygon(int p_id, const Vector2 &p_coord) const; const Map<Vector2, Ref<NavigationPolygon> > &autotile_get_navigation_map(int p_id) const; + void tile_set_z_index(int p_id, int p_z_index); + int tile_get_z_index(int p_id) const; + void remove_tile(int p_id); bool has_tile(int p_id) const; |