summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp17
-rw-r--r--scene/resources/bone_map.cpp172
-rw-r--r--scene/resources/bone_map.h69
-rw-r--r--scene/resources/canvas_item_material.h2
-rw-r--r--scene/resources/concave_polygon_shape_3d.h4
-rw-r--r--scene/resources/curve.cpp110
-rw-r--r--scene/resources/curve.h13
-rw-r--r--scene/resources/default_theme/default_theme.cpp56
-rw-r--r--scene/resources/font.cpp2310
-rw-r--r--scene/resources/font.h264
-rw-r--r--scene/resources/gradient.h12
-rw-r--r--scene/resources/importer_mesh.cpp11
-rw-r--r--scene/resources/material.cpp19
-rw-r--r--scene/resources/mesh.cpp11
-rw-r--r--scene/resources/navigation_mesh.cpp24
-rw-r--r--scene/resources/navigation_mesh.h8
-rw-r--r--scene/resources/packed_scene.cpp72
-rw-r--r--scene/resources/packed_scene.h14
-rw-r--r--scene/resources/particles_material.cpp6
-rw-r--r--scene/resources/particles_material.h2
-rw-r--r--scene/resources/primitive_meshes.cpp125
-rw-r--r--scene/resources/primitive_meshes.h35
-rw-r--r--scene/resources/resource_format_text.cpp79
-rw-r--r--scene/resources/scene_replication_config.cpp12
-rw-r--r--scene/resources/skeleton_profile.cpp514
-rw-r--r--scene/resources/skeleton_profile.h100
-rw-r--r--scene/resources/surface_tool.cpp66
-rw-r--r--scene/resources/surface_tool.h12
-rw-r--r--scene/resources/text_file.cpp2
-rw-r--r--scene/resources/text_line.cpp68
-rw-r--r--scene/resources/text_line.h23
-rw-r--r--scene/resources/text_paragraph.cpp123
-rw-r--r--scene/resources/text_paragraph.h25
-rw-r--r--scene/resources/texture.cpp12
-rw-r--r--scene/resources/tile_set.cpp357
-rw-r--r--scene/resources/tile_set.h60
-rw-r--r--scene/resources/visual_shader.cpp84
-rw-r--r--scene/resources/visual_shader.h10
-rw-r--r--scene/resources/world_2d.cpp4
-rw-r--r--scene/resources/world_3d.cpp5
40 files changed, 3063 insertions, 1849 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 8ae4872d14..7183accc66 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -3379,17 +3379,6 @@ Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) con
return bt->values[p_index].value.out_handle;
}
-static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, const Vector2 &control_1, const Vector2 &control_2, const Vector2 &end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
-
- return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
-}
-
real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
//this uses a different interpolation scheme
ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
@@ -3438,7 +3427,7 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
for (int i = 0; i < iterations; i++) {
real_t middle = (low + high) / 2;
- Vector2 interp = _bezier_interp(middle, start, start_out, end_in, end);
+ Vector2 interp = start.bezier_interpolate(start_out, end_in, end, middle);
if (interp.x < t) {
low = middle;
@@ -3448,8 +3437,8 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
}
//interpolate the result:
- Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end);
- Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end);
+ Vector2 low_pos = start.bezier_interpolate(start_out, end_in, end, low);
+ Vector2 high_pos = start.bezier_interpolate(start_out, end_in, end, high);
real_t c = (t - low_pos.x) / (high_pos.x - low_pos.x);
return low_pos.lerp(high_pos, c).y;
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
new file mode 100644
index 0000000000..ce030934fa
--- /dev/null
+++ b/scene/resources/bone_map.cpp
@@ -0,0 +1,172 @@
+/*************************************************************************/
+/* bone_map.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "bone_map.h"
+
+bool BoneMap::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+ if (path.begins_with("bone_map/")) {
+ String which = path.get_slicec('/', 1);
+ set_skeleton_bone_name(which, p_value);
+ return true;
+ }
+ return true;
+}
+
+bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+ if (path.begins_with("bone_map/")) {
+ String which = path.get_slicec('/', 1);
+ r_ret = get_skeleton_bone_name(which);
+ return true;
+ }
+ return true;
+}
+
+Ref<SkeletonProfile> BoneMap::get_profile() const {
+ return profile;
+}
+
+void BoneMap::set_profile(const Ref<SkeletonProfile> &p_profile) {
+ bool is_changed = profile != p_profile;
+ if (is_changed) {
+ if (!profile.is_null() && profile->is_connected("profile_updated", callable_mp(this, &BoneMap::_update_profile))) {
+ profile->disconnect("profile_updated", callable_mp(this, &BoneMap::_update_profile));
+ }
+ profile = p_profile;
+ if (!profile.is_null()) {
+ profile->connect("profile_updated", callable_mp(this, &BoneMap::_update_profile));
+ }
+ _update_profile();
+ }
+ notify_property_list_changed();
+}
+
+StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const {
+ ERR_FAIL_COND_V(!bone_map.has(p_profile_bone_name), StringName());
+ return bone_map.get(p_profile_bone_name);
+}
+
+void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+ ERR_FAIL_COND(!bone_map.has(p_profile_bone_name));
+ bone_map.insert(p_profile_bone_name, p_skeleton_bone_name);
+ emit_signal("bone_map_updated");
+}
+
+StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) const {
+ StringName profile_bone_name = StringName();
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ if (E->value == p_skeleton_bone_name) {
+ profile_bone_name = E->key;
+ break;
+ }
+ ++E;
+ }
+ return profile_bone_name;
+}
+
+int BoneMap::get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const {
+ int count = 0;
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ if (E->value == p_skeleton_bone_name) {
+ ++count;
+ }
+ ++E;
+ }
+ return count;
+}
+
+void BoneMap::_update_profile() {
+ _validate_bone_map();
+ emit_signal("profile_updated");
+}
+
+void BoneMap::_validate_bone_map() {
+ Ref<SkeletonProfile> current_profile = get_profile();
+ if (current_profile.is_valid()) {
+ // Insert missing profile bones into bone map.
+ int len = current_profile->get_bone_size();
+ StringName profile_bone_name;
+ for (int i = 0; i < len; i++) {
+ profile_bone_name = current_profile->get_bone_name(i);
+ if (!bone_map.has(profile_bone_name)) {
+ bone_map.insert(profile_bone_name, StringName());
+ }
+ }
+ // Remove bones that do not exist in the profile from the map.
+ Vector<StringName> delete_bones;
+ StringName k;
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ k = E->key;
+ if (!current_profile->has_bone(k)) {
+ delete_bones.push_back(k);
+ }
+ ++E;
+ }
+ len = delete_bones.size();
+ for (int i = 0; i < len; i++) {
+ bone_map.erase(delete_bones[i]);
+ }
+ } else {
+ bone_map.clear();
+ }
+ emit_signal("retarget_option_updated");
+}
+
+void BoneMap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_profile"), &BoneMap::get_profile);
+ ClassDB::bind_method(D_METHOD("set_profile", "profile"), &BoneMap::set_profile);
+
+ ClassDB::bind_method(D_METHOD("get_skeleton_bone_name", "profile_bone_name"), &BoneMap::get_skeleton_bone_name);
+ ClassDB::bind_method(D_METHOD("set_skeleton_bone_name", "profile_bone_name", "skeleton_bone_name"), &BoneMap::set_skeleton_bone_name);
+
+ ClassDB::bind_method(D_METHOD("find_profile_bone_name", "skeleton_bone_name"), &BoneMap::find_profile_bone_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "profile", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonProfile"), "set_profile", "get_profile");
+
+ ADD_SIGNAL(MethodInfo("bone_map_updated"));
+ ADD_SIGNAL(MethodInfo("profile_updated"));
+}
+
+void BoneMap::_validate_property(PropertyInfo &property) const {
+ //
+}
+
+BoneMap::BoneMap() {
+ _validate_bone_map();
+}
+
+BoneMap::~BoneMap() {
+}
+
+//////////////////////////////////////
diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h
new file mode 100644
index 0000000000..4b7928015d
--- /dev/null
+++ b/scene/resources/bone_map.h
@@ -0,0 +1,69 @@
+/*************************************************************************/
+/* bone_map.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BONE_MAP_H
+#define BONE_MAP_H
+
+#include "skeleton_profile.h"
+
+class BoneMap : public Resource {
+ GDCLASS(BoneMap, Resource);
+
+ Ref<SkeletonProfile> profile;
+ HashMap<StringName, StringName> bone_map;
+
+ void _update_profile();
+ void _validate_bone_map();
+
+protected:
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ virtual void _validate_property(PropertyInfo &property) const override;
+ static void _bind_methods();
+
+public:
+ int get_profile_type() const;
+ void set_profile_type(const int p_profile_type);
+
+ Ref<SkeletonProfile> get_profile() const;
+ void set_profile(const Ref<SkeletonProfile> &p_profile);
+
+ int get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const;
+
+ StringName get_skeleton_bone_name(StringName p_profile_bone_name) const;
+ void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name);
+
+ StringName find_profile_bone_name(StringName p_skeleton_bone_name) const;
+
+ BoneMap();
+ ~BoneMap();
+};
+
+#endif // BONE_MAP_H
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index 7c44c125a8..160c67d6b1 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -64,7 +64,7 @@ private:
uint32_t key = 0;
static uint32_t hash(const MaterialKey &p_key) {
- return hash_djb2_one_32(p_key.key);
+ return hash_murmur3_one_32(p_key.key);
}
bool operator==(const MaterialKey &p_key) const {
return key == p_key.key;
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index 4711e38468..a265590edd 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -43,8 +43,8 @@ class ConcavePolygonShape3D : public Shape3D {
Vector3 a;
Vector3 b;
static uint32_t hash(const DrawEdge &p_edge) {
- uint32_t h = hash_djb2_one_32(HashMapHasherDefault::hash(p_edge.a));
- return hash_djb2_one_32(HashMapHasherDefault::hash(p_edge.b), h);
+ uint32_t h = hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.a));
+ return hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.b), h);
}
bool operator==(const DrawEdge &p_edge) const {
return (a == p_edge.a && b == p_edge.b);
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index c99f71b13e..da26a0261f 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -32,18 +32,6 @@
#include "core/core_string_names.h"
-template <class T>
-static _FORCE_INLINE_ T _bezier_interp(real_t p_t, T p_start, T p_control_1, T p_control_2, T p_end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - p_t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = p_t * p_t;
- real_t t3 = t2 * p_t;
-
- return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
-}
-
const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
Curve::Curve() {
@@ -56,12 +44,13 @@ void Curve::set_point_count(int p_count) {
mark_dirty();
} else {
for (int i = p_count - _points.size(); i > 0; i--) {
- add_point(Vector2());
+ _add_point(Vector2());
}
}
+ notify_property_list_changed();
}
-int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
+int Curve::_add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
// Add a point and preserve order
// Curve bounds is in 0..1
@@ -112,6 +101,13 @@ int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_t
return ret;
}
+int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
+ int ret = _add_point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode);
+ notify_property_list_changed();
+
+ return ret;
+}
+
int Curve::get_index(real_t p_offset) const {
// Lower-bound float binary search
@@ -217,15 +213,21 @@ Curve::TangentMode Curve::get_point_right_mode(int p_index) const {
return _points[p_index].right_mode;
}
-void Curve::remove_point(int p_index) {
+void Curve::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, _points.size());
_points.remove_at(p_index);
mark_dirty();
}
+void Curve::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
+}
+
void Curve::clear_points() {
_points.clear();
mark_dirty();
+ notify_property_list_changed();
}
void Curve::set_point_value(int p_index, real_t p_position) {
@@ -238,8 +240,8 @@ void Curve::set_point_value(int p_index, real_t p_position) {
int Curve::set_point_offset(int p_index, real_t p_offset) {
ERR_FAIL_INDEX_V(p_index, _points.size(), -1);
Point p = _points[p_index];
- remove_point(p_index);
- int i = add_point(Vector2(p_offset, p.position.y));
+ _remove_point(p_index);
+ int i = _add_point(Vector2(p_offset, p.position.y));
_points.write[i].left_tangent = p.left_tangent;
_points.write[i].right_tangent = p.right_tangent;
_points.write[i].left_mode = p.left_mode;
@@ -362,7 +364,7 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
real_t yac = a.position.y + d * a.right_tangent;
real_t ybc = b.position.y - d * b.left_tangent;
- real_t y = _bezier_interp(p_local_offset, a.position.y, yac, ybc, b.position.y);
+ real_t y = Math::bezier_interpolate(a.position.y, yac, ybc, b.position.y, p_local_offset);
return y;
}
@@ -370,7 +372,6 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
void Curve::mark_dirty() {
_baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
- notify_property_list_changed();
}
Array Curve::get_data() const {
@@ -429,6 +430,7 @@ void Curve::set_data(const Array p_input) {
}
mark_dirty();
+ notify_property_list_changed();
}
void Curve::bake() {
@@ -636,16 +638,15 @@ void Curve2D::set_point_count(int p_count) {
if (points.size() >= p_count) {
points.resize(p_count);
mark_dirty();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
} else {
for (int i = p_count - points.size(); i > 0; i--) {
- add_point(Vector2());
+ _add_point(Vector2());
}
}
+ notify_property_list_changed();
}
-void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
+void Curve2D::_add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
Point n;
n.position = p_position;
n.in = p_in;
@@ -659,6 +660,11 @@ void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Ve
mark_dirty();
}
+void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
+ _add_point(p_position, p_in, p_out, p_atpos);
+ notify_property_list_changed();
+}
+
void Curve2D::set_point_position(int p_index, const Vector2 &p_position) {
ERR_FAIL_INDEX(p_index, points.size());
@@ -695,16 +701,22 @@ Vector2 Curve2D::get_point_out(int p_index) const {
return points[p_index].out;
}
-void Curve2D::remove_point(int p_index) {
+void Curve2D::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
points.remove_at(p_index);
mark_dirty();
}
+void Curve2D::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
+}
+
void Curve2D::clear_points() {
if (!points.is_empty()) {
points.clear();
mark_dirty();
+ notify_property_list_changed();
}
}
@@ -723,7 +735,7 @@ Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
Vector2 p3 = points[p_index + 1].position;
Vector2 p2 = p3 + points[p_index + 1].in;
- return _bezier_interp(p_offset, p0, p1, p2, p3);
+ return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
Vector2 Curve2D::interpolatef(real_t p_findex) const {
@@ -739,14 +751,13 @@ Vector2 Curve2D::interpolatef(real_t p_findex) const {
void Curve2D::mark_dirty() {
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
- notify_property_list_changed();
}
void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
real_t mp = p_begin + (p_end - p_begin) * 0.5;
- Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+ Vector2 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector2 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ Vector2 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
Vector2 na = (mid - beg).normalized();
Vector2 nb = (end - mid).normalized();
@@ -805,7 +816,7 @@ void Curve2D::_bake() const {
np = 1.0;
}
- Vector2 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ Vector2 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
real_t d = position.distance_to(npp);
if (d > bake_interval) {
@@ -818,7 +829,7 @@ void Curve2D::_bake() const {
real_t mid = low + (hi - low) * 0.5;
for (int j = 0; j < iterations; j++) {
- npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
d = position.distance_to(npp);
if (bake_interval < d) {
@@ -1054,7 +1065,8 @@ void Curve2D::_set_data(const Dictionary &p_data) {
points.write[i].position = r[i * 3 + 2];
}
- baked_cache_dirty = true;
+ mark_dirty();
+ notify_property_list_changed();
}
PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) const {
@@ -1205,12 +1217,13 @@ void Curve3D::set_point_count(int p_count) {
mark_dirty();
} else {
for (int i = p_count - points.size(); i > 0; i--) {
- add_point(Vector3());
+ _add_point(Vector3());
}
}
+ notify_property_list_changed();
}
-void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
+void Curve3D::_add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
Point n;
n.position = p_position;
n.in = p_in;
@@ -1224,6 +1237,11 @@ void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Ve
mark_dirty();
}
+void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
+ _add_point(p_position, p_in, p_out, p_atpos);
+ notify_property_list_changed();
+}
+
void Curve3D::set_point_position(int p_index, const Vector3 &p_position) {
ERR_FAIL_INDEX(p_index, points.size());
@@ -1272,16 +1290,22 @@ Vector3 Curve3D::get_point_out(int p_index) const {
return points[p_index].out;
}
-void Curve3D::remove_point(int p_index) {
+void Curve3D::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
points.remove_at(p_index);
mark_dirty();
}
+void Curve3D::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
+}
+
void Curve3D::clear_points() {
if (!points.is_empty()) {
points.clear();
mark_dirty();
+ notify_property_list_changed();
}
}
@@ -1300,7 +1324,7 @@ Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
Vector3 p3 = points[p_index + 1].position;
Vector3 p2 = p3 + points[p_index + 1].in;
- return _bezier_interp(p_offset, p0, p1, p2, p3);
+ return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
Vector3 Curve3D::interpolatef(real_t p_findex) const {
@@ -1316,14 +1340,13 @@ Vector3 Curve3D::interpolatef(real_t p_findex) const {
void Curve3D::mark_dirty() {
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
- notify_property_list_changed();
}
void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
real_t mp = p_begin + (p_end - p_begin) * 0.5;
- Vector3 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector3 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector3 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+ Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
Vector3 na = (mid - beg).normalized();
Vector3 nb = (end - mid).normalized();
@@ -1391,7 +1414,7 @@ void Curve3D::_bake() const {
np = 1.0;
}
- Vector3 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ Vector3 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
real_t d = position.distance_to(npp);
if (d > bake_interval) {
@@ -1404,7 +1427,7 @@ void Curve3D::_bake() const {
real_t mid = low + (hi - low) * 0.5;
for (int j = 0; j < iterations; j++) {
- npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
d = position.distance_to(npp);
if (bake_interval < d) {
@@ -1839,7 +1862,8 @@ void Curve3D::_set_data(const Dictionary &p_data) {
points.write[i].tilt = rt[i];
}
- baked_cache_dirty = true;
+ mark_dirty();
+ notify_property_list_changed();
}
PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) const {
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 834e7ffa07..08807b1b6e 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -83,7 +83,6 @@ public:
real_t right_tangent = 0,
TangentMode left_mode = TANGENT_FREE,
TangentMode right_mode = TANGENT_FREE);
-
void remove_point(int p_index);
void clear_points();
@@ -137,6 +136,12 @@ protected:
private:
void mark_dirty();
+ int _add_point(Vector2 p_position,
+ real_t left_tangent = 0,
+ real_t right_tangent = 0,
+ TangentMode left_mode = TANGENT_FREE,
+ TangentMode right_mode = TANGENT_FREE);
+ void _remove_point(int p_index);
Vector<Point> _points;
bool _baked_cache_dirty = false;
@@ -184,6 +189,9 @@ class Curve2D : public Resource {
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
+ void _remove_point(int p_index);
+
protected:
static void _bind_methods();
@@ -256,6 +264,9 @@ class Curve3D : public Resource {
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
+ void _remove_point(int p_index);
+
protected:
static void _bind_methods();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 5fcaf8f2c4..9d13ac3a38 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -467,6 +467,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("completion_selected_color", "CodeEdit", Color(0.26, 0.26, 0.27));
theme->set_color("completion_existing_color", "CodeEdit", Color(0.87, 0.87, 0.87, 0.13));
theme->set_color("completion_scroll_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.29));
+ theme->set_color("completion_scroll_hovered_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.4));
theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67));
theme->set_color("font_color", "CodeEdit", control_font_color);
theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0));
@@ -570,7 +571,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Window
theme->set_stylebox("embedded_border", "Window", sb_expand(make_flat_stylebox(style_popup_color, 10, 28, 10, 8), 8, 32, 8, 6));
- theme->set_constant("scaleborder_size", "Window", 4 * scale);
theme->set_font("title_font", "Window", Ref<Font>());
theme->set_font_size("title_font_size", "Window", -1);
@@ -918,8 +918,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("panel", "TooltipPanel",
make_flat_stylebox(Color(0, 0, 0, 0.5), 2 * default_margin, 0.5 * default_margin, 2 * default_margin, 0.5 * default_margin));
- theme->set_font("font", "TooltipLabel", Ref<Font>());
theme->set_font_size("font_size", "TooltipLabel", -1);
+ theme->set_font("font", "TooltipLabel", Ref<Font>());
theme->set_color("font_color", "TooltipLabel", control_font_color);
theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0));
@@ -939,7 +939,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("italics_font", "RichTextLabel", italics_font);
theme->set_font("bold_italics_font", "RichTextLabel", bold_italics_font);
theme->set_font("mono_font", "RichTextLabel", Ref<Font>());
-
theme->set_font_size("normal_font_size", "RichTextLabel", -1);
theme->set_font_size("bold_font_size", "RichTextLabel", -1);
theme->set_font_size("italics_font_size", "RichTextLabel", -1);
@@ -1034,9 +1033,9 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
Ref<StyleBox> default_style;
Ref<Texture2D> default_icon;
Ref<Font> default_font;
- Ref<Font> bold_font;
- Ref<Font> bold_italics_font;
- Ref<Font> italics_font;
+ Ref<FontVariation> bold_font;
+ Ref<FontVariation> bold_italics_font;
+ Ref<FontVariation> italics_font;
float default_scale = CLAMP(p_scale, 0.5, 8.0);
if (p_font.is_valid()) {
@@ -1046,48 +1045,31 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
// Use the default DynamicFont (separate from the editor font).
// The default DynamicFont is chosen to have a small file size since it's
// embedded in both editor and export template binaries.
- Ref<Font> dynamic_font;
+ Ref<FontFile> dynamic_font;
dynamic_font.instantiate();
-
- Ref<FontData> dynamic_font_data;
- dynamic_font_data.instantiate();
- dynamic_font_data->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size);
- dynamic_font_data->set_subpixel_positioning(p_font_subpixel);
- dynamic_font_data->set_hinting(p_font_hinting);
- dynamic_font_data->set_antialiased(p_font_antialiased);
- dynamic_font_data->set_multichannel_signed_distance_field(p_font_msdf);
- dynamic_font_data->set_generate_mipmaps(p_font_generate_mipmaps);
-
- dynamic_font->add_data(dynamic_font_data);
+ dynamic_font->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size);
+ dynamic_font->set_subpixel_positioning(p_font_subpixel);
+ dynamic_font->set_hinting(p_font_hinting);
+ dynamic_font->set_antialiased(p_font_antialiased);
+ dynamic_font->set_multichannel_signed_distance_field(p_font_msdf);
+ dynamic_font->set_generate_mipmaps(p_font_generate_mipmaps);
default_font = dynamic_font;
}
if (default_font.is_valid()) {
bold_font.instantiate();
- for (int i = 0; i < default_font->get_data_count(); i++) {
- Ref<FontData> data = default_font->get_data(i)->duplicate();
- // Try to match OpenSans ExtraBold.
- data->set_embolden(1.2);
- bold_font->add_data(data);
- }
+ bold_font->set_base_font(default_font);
+ bold_font->set_variation_embolden(1.2);
bold_italics_font.instantiate();
- for (int i = 0; i < default_font->get_data_count(); i++) {
- Ref<FontData> data = default_font->get_data(i)->duplicate();
- // Try to match OpenSans ExtraBold Italic.
- data->set_embolden(1.2);
- data->set_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
- bold_italics_font->add_data(data);
- }
+ bold_italics_font->set_base_font(default_font);
+ bold_italics_font->set_variation_embolden(1.2);
+ bold_italics_font->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
italics_font.instantiate();
- for (int i = 0; i < default_font->get_data_count(); i++) {
- Ref<FontData> data = default_font->get_data(i)->duplicate();
- // Try to match OpenSans Italic.
- data->set_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
- italics_font->add_data(data);
- }
+ italics_font->set_base_font(default_font);
+ italics_font->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
}
fill_default_theme(t, default_font, bold_font, bold_italics_font, italics_font, default_icon, default_style, default_scale);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 8a353f4b49..6053d27ef7 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -30,6 +30,7 @@
#include "font.h"
+#include "core/core_string_names.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/string/translation.h"
@@ -37,439 +38,539 @@
#include "core/templates/hashfuncs.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
+#include "scene/resources/theme.h"
-_FORCE_INLINE_ void FontData::_clear_cache() {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->free_rid(cache[i]);
- cache.write[i] = RID();
- }
- }
-}
+/*************************************************************************/
+/* Font */
+/*************************************************************************/
-_FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const {
- if (unlikely(p_cache_index >= cache.size())) {
- cache.resize(p_cache_index + 1);
- }
- if (unlikely(!cache[p_cache_index].is_valid())) {
- cache.write[p_cache_index] = TS->create_font();
- TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
- TS->font_set_face_index(cache[p_cache_index], face_index);
- TS->font_set_antialiased(cache[p_cache_index], antialiased);
- TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
- TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
- TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range);
- TS->font_set_msdf_size(cache[p_cache_index], msdf_size);
- TS->font_set_fixed_size(cache[p_cache_index], fixed_size);
- TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter);
- TS->font_set_hinting(cache[p_cache_index], hinting);
- TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning);
- TS->font_set_embolden(cache[p_cache_index], embolden);
- TS->font_set_transform(cache[p_cache_index], transform);
- TS->font_set_oversampling(cache[p_cache_index], oversampling);
- }
-}
+void Font::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_fallbacks", "fallbacks"), &Font::set_fallbacks);
+ ClassDB::bind_method(D_METHOD("get_fallbacks"), &Font::get_fallbacks);
+
+ // Output.
+ ClassDB::bind_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform"), &Font::find_variation, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D()));
+ ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids);
-void FontData::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load_bitmap_font", "path"), &FontData::load_bitmap_font);
- ClassDB::bind_method(D_METHOD("load_dynamic_font", "path"), &FontData::load_dynamic_font);
+ // Font metrics.
+ ClassDB::bind_method(D_METHOD("get_height", "font_size"), &Font::get_height, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_ascent", "font_size"), &Font::get_ascent, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_descent", "font_size"), &Font::get_descent, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_underline_position", "font_size"), &Font::get_underline_position, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_underline_thickness", "font_size"), &Font::get_underline_thickness, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data);
- ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data);
+ ClassDB::bind_method(D_METHOD("get_font_name"), &Font::get_font_name);
+ ClassDB::bind_method(D_METHOD("get_font_style_name"), &Font::get_font_style_name);
+ ClassDB::bind_method(D_METHOD("get_font_style"), &Font::get_font_style);
- ClassDB::bind_method(D_METHOD("set_face_index", "face_index"), &FontData::set_face_index);
- ClassDB::bind_method(D_METHOD("get_face_index"), &FontData::get_face_index);
+ ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing);
+ ClassDB::bind_method(D_METHOD("get_opentype_features"), &Font::get_opentype_features);
- ClassDB::bind_method(D_METHOD("get_face_count"), &FontData::get_face_count);
+ // Drawing string.
+ ClassDB::bind_method(D_METHOD("set_cache_capacity", "single_line", "multi_line"), &Font::set_cache_capacity);
- ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
- ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
+ ClassDB::bind_method(D_METHOD("get_string_size", "text", "alignment", "width", "font_size", "flags", "direction", "orientation"), &Font::get_string_size, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("get_multiline_string_size", "text", "alignment", "width", "font_size", "max_lines", "flags", "direction", "orientation"), &Font::get_multiline_string_size, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
- ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontData::set_generate_mipmaps);
- ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontData::get_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("draw_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "modulate", "flags", "direction", "orientation"), &Font::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("draw_multiline_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "max_lines", "modulate", "flags", "direction", "orientation"), &Font::draw_multiline_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
- ClassDB::bind_method(D_METHOD("set_font_name", "name"), &FontData::set_font_name);
- ClassDB::bind_method(D_METHOD("get_font_name"), &FontData::get_font_name);
+ ClassDB::bind_method(D_METHOD("draw_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "size", "modulate", "flags", "direction", "orientation"), &Font::draw_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("draw_multiline_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "max_lines", "size", "modulate", "flags", "direction", "orientation"), &Font::draw_multiline_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
- ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontData::set_font_style_name);
- ClassDB::bind_method(D_METHOD("get_font_style_name"), &FontData::get_font_style_name);
+ // Drawing char.
+ ClassDB::bind_method(D_METHOD("get_char_size", "char"), &Font::get_char_size);
+ ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "modulate"), &Font::draw_char, DEFVAL(Color(1.0, 1.0, 1.0)));
+ ClassDB::bind_method(D_METHOD("draw_char_outline", "canvas_item", "pos", "char", "size", "modulate"), &Font::draw_char_outline, DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)));
- ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontData::set_font_style);
- ClassDB::bind_method(D_METHOD("get_font_style"), &FontData::get_font_style);
+ // Helper functions.
+ ClassDB::bind_method(D_METHOD("has_char", "char"), &Font::has_char);
+ ClassDB::bind_method(D_METHOD("get_supported_chars"), &Font::get_supported_chars);
- ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &FontData::set_multichannel_signed_distance_field);
- ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &FontData::is_multichannel_signed_distance_field);
+ ClassDB::bind_method(D_METHOD("is_language_supported", "language"), &Font::is_language_supported);
+ ClassDB::bind_method(D_METHOD("is_script_supported", "script"), &Font::is_script_supported);
- ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &FontData::set_msdf_pixel_range);
- ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &FontData::get_msdf_pixel_range);
+ ClassDB::bind_method(D_METHOD("get_supported_feature_list"), &Font::get_supported_feature_list);
+ ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &Font::get_supported_variation_list);
+ ClassDB::bind_method(D_METHOD("get_face_count"), &Font::get_face_count);
+}
+
+void Font::_update_rids_fb(const Ref<Font> &p_f, int p_depth) const {
+ ERR_FAIL_COND(p_depth > MAX_FALLBACK_DEPTH);
+ if (p_f.is_valid()) {
+ RID rid = p_f->_get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
+ }
+ const TypedArray<Font> &_fallbacks = p_f->get_fallbacks();
+ for (int i = 0; i < _fallbacks.size(); i++) {
+ _update_rids_fb(_fallbacks[i], p_depth + 1);
+ }
+ }
+}
+
+void Font::_update_rids() const {
+ rids.clear();
+ _update_rids_fb(const_cast<Font *>(this), 0);
+ dirty_rids = false;
+}
+
+void Font::_invalidate_rids() {
+ rids.clear();
+ dirty_rids = true;
+
+ cache.clear();
+ cache_wrap.clear();
+
+ emit_changed();
+}
+
+bool Font::_is_cyclic(const Ref<Font> &p_f, int p_depth) const {
+ ERR_FAIL_COND_V(p_depth > MAX_FALLBACK_DEPTH, false);
+ if (p_f.is_null()) {
+ return false;
+ }
+ for (int i = 0; i < p_f->fallbacks.size(); i++) {
+ const Ref<Font> &f = p_f->fallbacks[i];
+ if (f == this) {
+ return true;
+ }
+ return _is_cyclic(f, p_depth + 1);
+ }
+ return false;
+}
+
+void Font::reset_state() {
+ _invalidate_rids();
+}
+
+// Fallbacks.
+void Font::set_fallbacks(const TypedArray<Font> &p_fallbacks) {
+ ERR_FAIL_COND(_is_cyclic(this, 0));
+ for (int i = 0; i < fallbacks.size(); i++) {
+ Ref<Font> f = fallbacks[i];
+ if (f.is_valid()) {
+ f->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Font::_invalidate_rids));
+ }
+ }
+ fallbacks = p_fallbacks;
+ for (int i = 0; i < fallbacks.size(); i++) {
+ Ref<Font> f = fallbacks[i];
+ if (f.is_valid()) {
+ f->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ }
+ _invalidate_rids();
+}
- ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontData::set_msdf_size);
- ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontData::get_msdf_size);
+TypedArray<Font> Font::get_fallbacks() const {
+ return fallbacks;
+}
- ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontData::set_fixed_size);
- ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontData::get_fixed_size);
+// Output.
+TypedArray<RID> Font::get_rids() const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ return rids;
+}
- ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontData::set_force_autohinter);
- ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontData::is_force_autohinter);
+// Drawing string.
+real_t Font::get_height(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_ascent(rids[i], p_font_size) + TS->font_get_descent(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_BOTTOM) + get_spacing(TextServer::SPACING_TOP);
+}
- ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting);
- ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting);
+real_t Font::get_ascent(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_ascent(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_TOP);
+}
- ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontData::set_subpixel_positioning);
- ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontData::get_subpixel_positioning);
+real_t Font::get_descent(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_descent(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_BOTTOM);
+}
- ClassDB::bind_method(D_METHOD("set_embolden", "strength"), &FontData::set_embolden);
- ClassDB::bind_method(D_METHOD("get_embolden"), &FontData::get_embolden);
+real_t Font::get_underline_position(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_underline_position(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_TOP);
+}
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &FontData::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &FontData::get_transform);
+real_t Font::get_underline_thickness(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_underline_thickness(rids[i], p_font_size));
+ }
+ return ret;
+}
- ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontData::set_oversampling);
- ClassDB::bind_method(D_METHOD("get_oversampling"), &FontData::get_oversampling);
+String Font::get_font_name() const {
+ return TS->font_get_name(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("find_cache", "variation_coordinates"), &FontData::find_cache);
+String Font::get_font_style_name() const {
+ return TS->font_get_style_name(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("get_cache_count"), &FontData::get_cache_count);
- ClassDB::bind_method(D_METHOD("clear_cache"), &FontData::clear_cache);
- ClassDB::bind_method(D_METHOD("remove_cache", "cache_index"), &FontData::remove_cache);
+uint32_t Font::get_font_style() const {
+ return TS->font_get_style(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("get_size_cache_list", "cache_index"), &FontData::get_size_cache_list);
- ClassDB::bind_method(D_METHOD("clear_size_cache", "cache_index"), &FontData::clear_size_cache);
- ClassDB::bind_method(D_METHOD("remove_size_cache", "cache_index", "size"), &FontData::remove_size_cache);
+Dictionary Font::get_opentype_features() const {
+ return Dictionary();
+}
- ClassDB::bind_method(D_METHOD("set_variation_coordinates", "cache_index", "variation_coordinates"), &FontData::set_variation_coordinates);
- ClassDB::bind_method(D_METHOD("get_variation_coordinates", "cache_index"), &FontData::get_variation_coordinates);
+// Drawing string.
+void Font::set_cache_capacity(int p_single_line, int p_multi_line) {
+ cache.set_capacity(p_single_line);
+ cache_wrap.set_capacity(p_multi_line);
+}
- ClassDB::bind_method(D_METHOD("set_ascent", "cache_index", "size", "ascent"), &FontData::set_ascent);
- ClassDB::bind_method(D_METHOD("get_ascent", "cache_index", "size"), &FontData::get_ascent);
+Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, uint16_t p_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_flags, hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
+ }
- ClassDB::bind_method(D_METHOD("set_descent", "cache_index", "size", "descent"), &FontData::set_descent);
- ClassDB::bind_method(D_METHOD("get_descent", "cache_index", "size"), &FontData::get_descent);
+ Ref<TextLine> buffer;
+ if (cache.has(hash)) {
+ buffer = cache.get(hash);
+ } else {
+ buffer.instantiate();
+ buffer->set_direction(p_direction);
+ buffer->set_orientation(p_orientation);
+ buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ cache.insert(hash, buffer);
+ }
+ return buffer->get_size();
+}
- ClassDB::bind_method(D_METHOD("set_underline_position", "cache_index", "size", "underline_position"), &FontData::set_underline_position);
- ClassDB::bind_method(D_METHOD("get_underline_position", "cache_index", "size"), &FontData::get_underline_position);
+Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, uint16_t p_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_flags, hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_underline_thickness", "cache_index", "size", "underline_thickness"), &FontData::set_underline_thickness);
- ClassDB::bind_method(D_METHOD("get_underline_thickness", "cache_index", "size"), &FontData::get_underline_thickness);
+ Ref<TextParagraph> lines_buffer;
+ if (cache_wrap.has(hash)) {
+ lines_buffer = cache_wrap.get(hash);
+ } else {
+ lines_buffer.instantiate();
+ lines_buffer->set_direction(p_direction);
+ lines_buffer->set_orientation(p_orientation);
+ lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ lines_buffer->set_width(p_width);
+ lines_buffer->set_flags(p_flags);
+ cache_wrap.insert(hash, lines_buffer);
+ }
- ClassDB::bind_method(D_METHOD("set_scale", "cache_index", "size", "scale"), &FontData::set_scale);
- ClassDB::bind_method(D_METHOD("get_scale", "cache_index", "size"), &FontData::get_scale);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- ClassDB::bind_method(D_METHOD("set_spacing", "cache_index", "size", "spacing_type", "value"), &FontData::set_spacing);
- ClassDB::bind_method(D_METHOD("get_spacing", "cache_index", "size", "spacing_type"), &FontData::get_spacing);
+ return lines_buffer->get_size();
+}
- ClassDB::bind_method(D_METHOD("get_texture_count", "cache_index", "size"), &FontData::get_texture_count);
- ClassDB::bind_method(D_METHOD("clear_textures", "cache_index", "size"), &FontData::clear_textures);
- ClassDB::bind_method(D_METHOD("remove_texture", "cache_index", "size", "texture_index"), &FontData::remove_texture);
+void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, uint16_t p_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_flags, hash);
+ }
- ClassDB::bind_method(D_METHOD("set_texture_image", "cache_index", "size", "texture_index", "image"), &FontData::set_texture_image);
- ClassDB::bind_method(D_METHOD("get_texture_image", "cache_index", "size", "texture_index"), &FontData::get_texture_image);
+ Ref<TextLine> buffer;
+ if (cache.has(hash)) {
+ buffer = cache.get(hash);
+ } else {
+ buffer.instantiate();
+ buffer->set_direction(p_direction);
+ buffer->set_orientation(p_orientation);
+ buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ cache.insert(hash, buffer);
+ }
- ClassDB::bind_method(D_METHOD("set_texture_offsets", "cache_index", "size", "texture_index", "offset"), &FontData::set_texture_offsets);
- ClassDB::bind_method(D_METHOD("get_texture_offsets", "cache_index", "size", "texture_index"), &FontData::get_texture_offsets);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= buffer->get_line_ascent();
+ } else {
+ ofs.x -= buffer->get_line_ascent();
+ }
- ClassDB::bind_method(D_METHOD("get_glyph_list", "cache_index", "size"), &FontData::get_glyph_list);
- ClassDB::bind_method(D_METHOD("clear_glyphs", "cache_index", "size"), &FontData::clear_glyphs);
- ClassDB::bind_method(D_METHOD("remove_glyph", "cache_index", "size", "glyph"), &FontData::remove_glyph);
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ buffer->set_flags(p_flags);
- ClassDB::bind_method(D_METHOD("set_glyph_advance", "cache_index", "size", "glyph", "advance"), &FontData::set_glyph_advance);
- ClassDB::bind_method(D_METHOD("get_glyph_advance", "cache_index", "size", "glyph"), &FontData::get_glyph_advance);
+ buffer->draw(p_canvas_item, ofs, p_modulate);
+}
- ClassDB::bind_method(D_METHOD("set_glyph_offset", "cache_index", "size", "glyph", "offset"), &FontData::set_glyph_offset);
- ClassDB::bind_method(D_METHOD("get_glyph_offset", "cache_index", "size", "glyph"), &FontData::get_glyph_offset);
+void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, uint16_t p_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_flags, hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_glyph_size", "cache_index", "size", "glyph", "gl_size"), &FontData::set_glyph_size);
- ClassDB::bind_method(D_METHOD("get_glyph_size", "cache_index", "size", "glyph"), &FontData::get_glyph_size);
+ Ref<TextParagraph> lines_buffer;
+ if (cache_wrap.has(hash)) {
+ lines_buffer = cache_wrap.get(hash);
+ } else {
+ lines_buffer.instantiate();
+ lines_buffer->set_direction(p_direction);
+ lines_buffer->set_orientation(p_orientation);
+ lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ lines_buffer->set_width(p_width);
+ lines_buffer->set_flags(p_flags);
+ cache_wrap.insert(hash, lines_buffer);
+ }
- ClassDB::bind_method(D_METHOD("set_glyph_uv_rect", "cache_index", "size", "glyph", "uv_rect"), &FontData::set_glyph_uv_rect);
- ClassDB::bind_method(D_METHOD("get_glyph_uv_rect", "cache_index", "size", "glyph"), &FontData::get_glyph_uv_rect);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= lines_buffer->get_line_ascent(0);
+ } else {
+ ofs.x -= lines_buffer->get_line_ascent(0);
+ }
- ClassDB::bind_method(D_METHOD("set_glyph_texture_idx", "cache_index", "size", "glyph", "texture_idx"), &FontData::set_glyph_texture_idx);
- ClassDB::bind_method(D_METHOD("get_glyph_texture_idx", "cache_index", "size", "glyph"), &FontData::get_glyph_texture_idx);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- ClassDB::bind_method(D_METHOD("get_kerning_list", "cache_index", "size"), &FontData::get_kerning_list);
- ClassDB::bind_method(D_METHOD("clear_kerning_map", "cache_index", "size"), &FontData::clear_kerning_map);
- ClassDB::bind_method(D_METHOD("remove_kerning", "cache_index", "size", "glyph_pair"), &FontData::remove_kerning);
+ lines_buffer->draw(p_canvas_item, ofs, p_modulate);
+}
- ClassDB::bind_method(D_METHOD("set_kerning", "cache_index", "size", "glyph_pair", "kerning"), &FontData::set_kerning);
- ClassDB::bind_method(D_METHOD("get_kerning", "cache_index", "size", "glyph_pair"), &FontData::get_kerning);
+void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, uint16_t p_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_flags, hash);
+ }
- ClassDB::bind_method(D_METHOD("render_range", "cache_index", "size", "start", "end"), &FontData::render_range);
- ClassDB::bind_method(D_METHOD("render_glyph", "cache_index", "size", "index"), &FontData::render_glyph);
+ Ref<TextLine> buffer;
+ if (cache.has(hash)) {
+ buffer = cache.get(hash);
+ } else {
+ buffer.instantiate();
+ buffer->set_direction(p_direction);
+ buffer->set_orientation(p_orientation);
+ buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ cache.insert(hash, buffer);
+ }
- ClassDB::bind_method(D_METHOD("get_cache_rid", "cache_index"), &FontData::get_cache_rid);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= buffer->get_line_ascent();
+ } else {
+ ofs.x -= buffer->get_line_ascent();
+ }
- ClassDB::bind_method(D_METHOD("is_language_supported", "language"), &FontData::is_language_supported);
- ClassDB::bind_method(D_METHOD("set_language_support_override", "language", "supported"), &FontData::set_language_support_override);
- ClassDB::bind_method(D_METHOD("get_language_support_override", "language"), &FontData::get_language_support_override);
- ClassDB::bind_method(D_METHOD("remove_language_support_override", "language"), &FontData::remove_language_support_override);
- ClassDB::bind_method(D_METHOD("get_language_support_overrides"), &FontData::get_language_support_overrides);
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ buffer->set_flags(p_flags);
- ClassDB::bind_method(D_METHOD("is_script_supported", "script"), &FontData::is_script_supported);
- ClassDB::bind_method(D_METHOD("set_script_support_override", "script", "supported"), &FontData::set_script_support_override);
- ClassDB::bind_method(D_METHOD("get_script_support_override", "script"), &FontData::get_script_support_override);
- ClassDB::bind_method(D_METHOD("remove_script_support_override", "script"), &FontData::remove_script_support_override);
- ClassDB::bind_method(D_METHOD("get_script_support_overrides"), &FontData::get_script_support_overrides);
+ buffer->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
+}
- ClassDB::bind_method(D_METHOD("set_opentype_feature_overrides", "overrides"), &FontData::set_opentype_feature_overrides);
- ClassDB::bind_method(D_METHOD("get_opentype_feature_overrides"), &FontData::get_opentype_feature_overrides);
+void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, uint16_t p_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_flags, hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("has_char", "char"), &FontData::has_char);
- ClassDB::bind_method(D_METHOD("get_supported_chars"), &FontData::get_supported_chars);
+ Ref<TextParagraph> lines_buffer;
+ if (cache_wrap.has(hash)) {
+ lines_buffer = cache_wrap.get(hash);
+ } else {
+ lines_buffer.instantiate();
+ lines_buffer->set_direction(p_direction);
+ lines_buffer->set_orientation(p_orientation);
+ lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ lines_buffer->set_width(p_width);
+ lines_buffer->set_flags(p_flags);
+ cache_wrap.insert(hash, lines_buffer);
+ }
- ClassDB::bind_method(D_METHOD("get_glyph_index", "size", "char", "variation_selector"), &FontData::get_glyph_index);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= lines_buffer->get_line_ascent(0);
+ } else {
+ ofs.x -= lines_buffer->get_line_ascent(0);
+ }
- ClassDB::bind_method(D_METHOD("get_supported_feature_list"), &FontData::get_supported_feature_list);
- ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &FontData::get_supported_variation_list);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_face_index", "get_face_index");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01", PROPERTY_USAGE_STORAGE), "set_embolden", "get_embolden");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_transform", "get_transform");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_opentype_feature_overrides", "get_opentype_feature_overrides");
+ lines_buffer->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
}
-bool FontData::_set(const StringName &p_name, const Variant &p_value) {
- Vector<String> tokens = p_name.operator String().split("/");
- if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- set_language_support_override(lang, p_value);
- return true;
- } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- set_script_support_override(script, p_value);
- return true;
- } else if (tokens.size() >= 3 && tokens[0] == "cache") {
- int cache_index = tokens[1].to_int();
- if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
- set_variation_coordinates(cache_index, p_value);
- return true;
- }
- if (tokens.size() >= 5) {
- Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
- if (tokens[4] == "ascent") {
- set_ascent(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "descent") {
- set_descent(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "underline_position") {
- set_underline_position(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "underline_thickness") {
- set_underline_thickness(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "scale") {
- set_scale(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "spacing_glyph") {
- set_spacing(cache_index, sz.x, TextServer::SPACING_GLYPH, p_value);
- return true;
- } else if (tokens[4] == "spacing_space") {
- set_spacing(cache_index, sz.x, TextServer::SPACING_SPACE, p_value);
- return true;
- } else if (tokens.size() == 7 && tokens[4] == "textures") {
- int texture_index = tokens[5].to_int();
- if (tokens[6] == "image") {
- set_texture_image(cache_index, sz, texture_index, p_value);
- return true;
- } else if (tokens[6] == "offsets") {
- set_texture_offsets(cache_index, sz, texture_index, p_value);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
- int32_t glyph_index = tokens[5].to_int();
- if (tokens[6] == "advance") {
- set_glyph_advance(cache_index, sz.x, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "offset") {
- set_glyph_offset(cache_index, sz, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "size") {
- set_glyph_size(cache_index, sz, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "uv_rect") {
- set_glyph_uv_rect(cache_index, sz, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "texture_idx") {
- set_glyph_texture_idx(cache_index, sz, glyph_index, p_value);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
- Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
- set_kerning(cache_index, sz.x, gp, p_value);
- return true;
- }
+// Drawing char.
+Size2 Font::get_char_size(char32_t p_char, int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
+ return Size2(TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x, get_height(p_font_size));
}
}
- return false;
+ return Size2();
}
-bool FontData::_get(const StringName &p_name, Variant &r_ret) const {
- Vector<String> tokens = p_name.operator String().split("/");
- if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- r_ret = get_language_support_override(lang);
- return true;
- } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- r_ret = get_script_support_override(script);
- return true;
- } else if (tokens.size() >= 3 && tokens[0] == "cache") {
- int cache_index = tokens[1].to_int();
- if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
- r_ret = get_variation_coordinates(cache_index);
- return true;
+real_t Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size, const Color &p_modulate) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
+ TS->font_draw_glyph(rids[i], p_canvas_item, p_font_size, p_pos, glyph, p_modulate);
+ return TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x;
}
- if (tokens.size() >= 5) {
- Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
- if (tokens[4] == "ascent") {
- r_ret = get_ascent(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "descent") {
- r_ret = get_descent(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "underline_position") {
- r_ret = get_underline_position(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "underline_thickness") {
- r_ret = get_underline_thickness(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "scale") {
- r_ret = get_scale(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "spacing_glyph") {
- r_ret = get_spacing(cache_index, sz.x, TextServer::SPACING_GLYPH);
- return true;
- } else if (tokens[4] == "spacing_space") {
- r_ret = get_spacing(cache_index, sz.x, TextServer::SPACING_SPACE);
- return true;
- } else if (tokens.size() == 7 && tokens[4] == "textures") {
- int texture_index = tokens[5].to_int();
- if (tokens[6] == "image") {
- r_ret = get_texture_image(cache_index, sz, texture_index);
- return true;
- } else if (tokens[6] == "offsets") {
- r_ret = get_texture_offsets(cache_index, sz, texture_index);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
- int32_t glyph_index = tokens[5].to_int();
- if (tokens[6] == "advance") {
- r_ret = get_glyph_advance(cache_index, sz.x, glyph_index);
- return true;
- } else if (tokens[6] == "offset") {
- r_ret = get_glyph_offset(cache_index, sz, glyph_index);
- return true;
- } else if (tokens[6] == "size") {
- r_ret = get_glyph_size(cache_index, sz, glyph_index);
- return true;
- } else if (tokens[6] == "uv_rect") {
- r_ret = get_glyph_uv_rect(cache_index, sz, glyph_index);
- return true;
- } else if (tokens[6] == "texture_idx") {
- r_ret = get_glyph_texture_idx(cache_index, sz, glyph_index);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
- Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
- r_ret = get_kerning(cache_index, sz.x, gp);
- return true;
- }
+ }
+ return 0.f;
+}
+
+real_t Font::draw_char_outline(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size, int p_size, const Color &p_modulate) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
+ TS->font_draw_glyph_outline(rids[i], p_canvas_item, p_font_size, p_size, p_pos, glyph, p_modulate);
+ return TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x;
}
}
- return false;
+ return 0.f;
}
-void FontData::_get_property_list(List<PropertyInfo> *p_list) const {
- Vector<String> lang_over = get_language_support_overrides();
- for (int i = 0; i < lang_over.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "language_support_override/" + lang_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+// Helper functions.
+bool Font::has_char(char32_t p_char) const {
+ if (dirty_rids) {
+ _update_rids();
}
- Vector<String> scr_over = get_script_support_overrides();
- for (int i = 0; i < scr_over.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ return true;
+ }
}
- for (int i = 0; i < cache.size(); i++) {
- String prefix = "cache/" + itos(i) + "/";
- Array sizes = get_size_cache_list(i);
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- for (int j = 0; j < sizes.size(); j++) {
- Vector2i sz = sizes[j];
- String prefix_sz = prefix + itos(sz.x) + "/" + itos(sz.y) + "/";
- if (sz.y == 0) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "ascent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "descent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_thickness", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::BOOL, prefix_sz + "spacing_glyph", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::BOOL, prefix_sz + "spacing_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
+ return false;
+}
- int tx_cnt = get_texture_count(i, sz);
- for (int k = 0; k < tx_cnt; k++) {
- p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
- }
- Array glyphs = get_glyph_list(i, sz);
- for (int k = 0; k < glyphs.size(); k++) {
- const int32_t &gl = glyphs[k];
- if (sz.y == 0) {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::RECT2, prefix_sz + "glyphs/" + itos(gl) + "/uv_rect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
- if (sz.y == 0) {
- Array kerning_map = get_kerning_list(i, sz.x);
- for (int k = 0; k < kerning_map.size(); k++) {
- const Vector2i &gl_pair = kerning_map[k];
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
+String Font::get_supported_chars() const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ String chars;
+ for (int i = 0; i < rids.size(); i++) {
+ String data_chars = TS->font_get_supported_chars(rids[i]);
+ for (int j = 0; j < data_chars.length(); j++) {
+ if (chars.find_char(data_chars[j]) == -1) {
+ chars += data_chars[j];
}
}
}
+ return chars;
}
-void FontData::reset_state() {
- _clear_cache();
- data.clear();
- data_ptr = nullptr;
- data_size = 0;
- face_index = 0;
- cache.clear();
+bool Font::is_language_supported(const String &p_language) const {
+ return TS->font_is_language_supported(_get_rid(), p_language);
+}
- antialiased = true;
- mipmaps = false;
- msdf = false;
- force_autohinter = false;
- hinting = TextServer::HINTING_LIGHT;
- subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
- msdf_pixel_range = 14;
- msdf_size = 128;
- fixed_size = 0;
- embolden = 0.f;
- transform = Transform2D();
- oversampling = 0.f;
+bool Font::is_script_supported(const String &p_script) const {
+ return TS->font_is_script_supported(_get_rid(), p_script);
+}
+
+Dictionary Font::get_supported_feature_list() const {
+ return TS->font_supported_feature_list(_get_rid());
+}
+
+Dictionary Font::get_supported_variation_list() const {
+ return TS->font_supported_variation_list(_get_rid());
+}
+
+int64_t Font::get_face_count() const {
+ return TS->font_get_face_count(_get_rid());
+}
+
+Font::Font() {
+ cache.set_capacity(64);
+ cache_wrap.set_capacity(16);
+}
+
+Font::~Font() {
+ reset_state();
}
-void FontData::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) {
+/*************************************************************************/
+/* FontFile */
+/*************************************************************************/
+
+_FORCE_INLINE_ void FontFile::_clear_cache() {
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->free_rid(cache[i]);
+ cache.write[i] = RID();
+ }
+ }
+}
+
+_FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index) const {
+ if (unlikely(p_cache_index >= cache.size())) {
+ cache.resize(p_cache_index + 1);
+ }
+ if (unlikely(!cache[p_cache_index].is_valid())) {
+ cache.write[p_cache_index] = TS->create_font();
+ TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
+ TS->font_set_antialiased(cache[p_cache_index], antialiased);
+ TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
+ TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
+ TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range);
+ TS->font_set_msdf_size(cache[p_cache_index], msdf_size);
+ TS->font_set_fixed_size(cache[p_cache_index], fixed_size);
+ TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter);
+ TS->font_set_hinting(cache[p_cache_index], hinting);
+ TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning);
+ TS->font_set_oversampling(cache[p_cache_index], oversampling);
+ }
+}
+
+void FontFile::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -516,7 +617,7 @@ void FontData::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz)
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a);
}
-void FontData::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
+void FontFile::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -616,7 +717,7 @@ void FontData::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz)
set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 3, img_ao);
}
-void FontData::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
+void FontFile::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -672,7 +773,7 @@ void FontData::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
set_texture_image(0, Vector2i(p_sz, 1), p_page, img_o);
}
-void FontData::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
+void FontFile::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -701,7 +802,7 @@ void FontData::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, in
set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_g);
}
-void FontData::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
+void FontFile::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -744,9 +845,477 @@ void FontData::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, in
set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_o);
}
+void FontFile::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load_bitmap_font", "path"), &FontFile::load_bitmap_font);
+ ClassDB::bind_method(D_METHOD("load_dynamic_font", "path"), &FontFile::load_dynamic_font);
+
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &FontFile::set_data);
+ ClassDB::bind_method(D_METHOD("get_data"), &FontFile::get_data);
+
+ ClassDB::bind_method(D_METHOD("set_font_name", "name"), &FontFile::set_font_name);
+ ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontFile::set_font_style_name);
+ ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontFile::set_font_style);
+
+ ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontFile::set_antialiased);
+ ClassDB::bind_method(D_METHOD("is_antialiased"), &FontFile::is_antialiased);
+
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontFile::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontFile::get_generate_mipmaps);
+
+ ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &FontFile::set_multichannel_signed_distance_field);
+ ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &FontFile::is_multichannel_signed_distance_field);
+
+ ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &FontFile::set_msdf_pixel_range);
+ ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &FontFile::get_msdf_pixel_range);
+
+ ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontFile::set_msdf_size);
+ ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontFile::get_msdf_size);
+
+ ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontFile::set_fixed_size);
+ ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontFile::get_fixed_size);
+
+ ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontFile::set_force_autohinter);
+ ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontFile::is_force_autohinter);
+
+ ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontFile::set_hinting);
+ ClassDB::bind_method(D_METHOD("get_hinting"), &FontFile::get_hinting);
+
+ ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontFile::set_subpixel_positioning);
+ ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontFile::get_subpixel_positioning);
+
+ ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontFile::set_oversampling);
+ ClassDB::bind_method(D_METHOD("get_oversampling"), &FontFile::get_oversampling);
+
+ ClassDB::bind_method(D_METHOD("get_cache_count"), &FontFile::get_cache_count);
+ ClassDB::bind_method(D_METHOD("clear_cache"), &FontFile::clear_cache);
+ ClassDB::bind_method(D_METHOD("remove_cache", "cache_index"), &FontFile::remove_cache);
+
+ ClassDB::bind_method(D_METHOD("get_size_cache_list", "cache_index"), &FontFile::get_size_cache_list);
+ ClassDB::bind_method(D_METHOD("clear_size_cache", "cache_index"), &FontFile::clear_size_cache);
+ ClassDB::bind_method(D_METHOD("remove_size_cache", "cache_index", "size"), &FontFile::remove_size_cache);
+
+ ClassDB::bind_method(D_METHOD("set_variation_coordinates", "cache_index", "variation_coordinates"), &FontFile::set_variation_coordinates);
+ ClassDB::bind_method(D_METHOD("get_variation_coordinates", "cache_index"), &FontFile::get_variation_coordinates);
+
+ ClassDB::bind_method(D_METHOD("set_embolden", "cache_index", "strength"), &FontFile::set_embolden);
+ ClassDB::bind_method(D_METHOD("get_embolden", "cache_index"), &FontFile::get_embolden);
+
+ ClassDB::bind_method(D_METHOD("set_transform", "cache_index", "transform"), &FontFile::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform", "cache_index"), &FontFile::get_transform);
+
+ ClassDB::bind_method(D_METHOD("set_face_index", "cache_index", "face_index"), &FontFile::set_face_index);
+ ClassDB::bind_method(D_METHOD("get_face_index", "cache_index"), &FontFile::get_face_index);
+
+ ClassDB::bind_method(D_METHOD("set_cache_ascent", "cache_index", "size", "ascent"), &FontFile::set_cache_ascent);
+ ClassDB::bind_method(D_METHOD("get_cache_ascent", "cache_index", "size"), &FontFile::get_cache_ascent);
+
+ ClassDB::bind_method(D_METHOD("set_cache_descent", "cache_index", "size", "descent"), &FontFile::set_cache_descent);
+ ClassDB::bind_method(D_METHOD("get_cache_descent", "cache_index", "size"), &FontFile::get_cache_descent);
+
+ ClassDB::bind_method(D_METHOD("set_cache_underline_position", "cache_index", "size", "underline_position"), &FontFile::set_cache_underline_position);
+ ClassDB::bind_method(D_METHOD("get_cache_underline_position", "cache_index", "size"), &FontFile::get_cache_underline_position);
+
+ ClassDB::bind_method(D_METHOD("set_cache_underline_thickness", "cache_index", "size", "underline_thickness"), &FontFile::set_cache_underline_thickness);
+ ClassDB::bind_method(D_METHOD("get_cache_underline_thickness", "cache_index", "size"), &FontFile::get_cache_underline_thickness);
+
+ ClassDB::bind_method(D_METHOD("set_cache_scale", "cache_index", "size", "scale"), &FontFile::set_cache_scale);
+ ClassDB::bind_method(D_METHOD("get_cache_scale", "cache_index", "size"), &FontFile::get_cache_scale);
+
+ ClassDB::bind_method(D_METHOD("get_texture_count", "cache_index", "size"), &FontFile::get_texture_count);
+ ClassDB::bind_method(D_METHOD("clear_textures", "cache_index", "size"), &FontFile::clear_textures);
+ ClassDB::bind_method(D_METHOD("remove_texture", "cache_index", "size", "texture_index"), &FontFile::remove_texture);
+
+ ClassDB::bind_method(D_METHOD("set_texture_image", "cache_index", "size", "texture_index", "image"), &FontFile::set_texture_image);
+ ClassDB::bind_method(D_METHOD("get_texture_image", "cache_index", "size", "texture_index"), &FontFile::get_texture_image);
+
+ ClassDB::bind_method(D_METHOD("set_texture_offsets", "cache_index", "size", "texture_index", "offset"), &FontFile::set_texture_offsets);
+ ClassDB::bind_method(D_METHOD("get_texture_offsets", "cache_index", "size", "texture_index"), &FontFile::get_texture_offsets);
+
+ ClassDB::bind_method(D_METHOD("get_glyph_list", "cache_index", "size"), &FontFile::get_glyph_list);
+ ClassDB::bind_method(D_METHOD("clear_glyphs", "cache_index", "size"), &FontFile::clear_glyphs);
+ ClassDB::bind_method(D_METHOD("remove_glyph", "cache_index", "size", "glyph"), &FontFile::remove_glyph);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_advance", "cache_index", "size", "glyph", "advance"), &FontFile::set_glyph_advance);
+ ClassDB::bind_method(D_METHOD("get_glyph_advance", "cache_index", "size", "glyph"), &FontFile::get_glyph_advance);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_offset", "cache_index", "size", "glyph", "offset"), &FontFile::set_glyph_offset);
+ ClassDB::bind_method(D_METHOD("get_glyph_offset", "cache_index", "size", "glyph"), &FontFile::get_glyph_offset);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_size", "cache_index", "size", "glyph", "gl_size"), &FontFile::set_glyph_size);
+ ClassDB::bind_method(D_METHOD("get_glyph_size", "cache_index", "size", "glyph"), &FontFile::get_glyph_size);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_uv_rect", "cache_index", "size", "glyph", "uv_rect"), &FontFile::set_glyph_uv_rect);
+ ClassDB::bind_method(D_METHOD("get_glyph_uv_rect", "cache_index", "size", "glyph"), &FontFile::get_glyph_uv_rect);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_texture_idx", "cache_index", "size", "glyph", "texture_idx"), &FontFile::set_glyph_texture_idx);
+ ClassDB::bind_method(D_METHOD("get_glyph_texture_idx", "cache_index", "size", "glyph"), &FontFile::get_glyph_texture_idx);
+
+ ClassDB::bind_method(D_METHOD("get_kerning_list", "cache_index", "size"), &FontFile::get_kerning_list);
+ ClassDB::bind_method(D_METHOD("clear_kerning_map", "cache_index", "size"), &FontFile::clear_kerning_map);
+ ClassDB::bind_method(D_METHOD("remove_kerning", "cache_index", "size", "glyph_pair"), &FontFile::remove_kerning);
+
+ ClassDB::bind_method(D_METHOD("set_kerning", "cache_index", "size", "glyph_pair", "kerning"), &FontFile::set_kerning);
+ ClassDB::bind_method(D_METHOD("get_kerning", "cache_index", "size", "glyph_pair"), &FontFile::get_kerning);
+
+ ClassDB::bind_method(D_METHOD("render_range", "cache_index", "size", "start", "end"), &FontFile::render_range);
+ ClassDB::bind_method(D_METHOD("render_glyph", "cache_index", "size", "index"), &FontFile::render_glyph);
+
+ ClassDB::bind_method(D_METHOD("set_language_support_override", "language", "supported"), &FontFile::set_language_support_override);
+ ClassDB::bind_method(D_METHOD("get_language_support_override", "language"), &FontFile::get_language_support_override);
+ ClassDB::bind_method(D_METHOD("remove_language_support_override", "language"), &FontFile::remove_language_support_override);
+ ClassDB::bind_method(D_METHOD("get_language_support_overrides"), &FontFile::get_language_support_overrides);
+
+ ClassDB::bind_method(D_METHOD("set_script_support_override", "script", "supported"), &FontFile::set_script_support_override);
+ ClassDB::bind_method(D_METHOD("get_script_support_override", "script"), &FontFile::get_script_support_override);
+ ClassDB::bind_method(D_METHOD("remove_script_support_override", "script"), &FontFile::remove_script_support_override);
+ ClassDB::bind_method(D_METHOD("get_script_support_overrides"), &FontFile::get_script_support_overrides);
+
+ ClassDB::bind_method(D_METHOD("set_opentype_feature_overrides", "overrides"), &FontFile::set_opentype_feature_overrides);
+ ClassDB::bind_method(D_METHOD("get_opentype_feature_overrides"), &FontFile::get_opentype_feature_overrides);
+
+ ClassDB::bind_method(D_METHOD("get_glyph_index", "size", "char", "variation_selector"), &FontFile::get_glyph_index);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_opentype_feature_overrides", "get_opentype_feature_overrides");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font"), PROPERTY_USAGE_STORAGE), "set_fallbacks", "get_fallbacks");
+}
+
+bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> tokens = p_name.operator String().split("/");
+
+#ifndef DISABLE_DEPRECATED
+ if (tokens.size() == 1 && tokens[0] == "font_path") {
+ // Compatibility, DynamicFontData.
+ load_dynamic_font(p_value);
+ } else if (tokens.size() == 1 && tokens[0] == "override_oversampling") {
+ set_oversampling(p_value);
+ }
+ if (tokens.size() == 1 && tokens[0] == "font_data") {
+ // Compatibility, DynamicFont.
+ Ref<Font> f = p_value;
+ if (f.is_valid()) {
+ fallbacks.push_back(f);
+ return true;
+ }
+ return false;
+ } else if (tokens.size() == 2 && tokens[0] == "fallback") {
+ // Compatibility, DynamicFont.
+ Ref<FontFile> f = p_value;
+ if (f.is_valid()) {
+ fallbacks.push_back(f);
+ return true;
+ }
+ return false;
+ } else if (tokens.size() == 1 && tokens[0] == "textures") {
+ // Compatibility, BitmapFont.
+ set_fixed_size(16);
+ Array textures = p_value;
+ for (int i = 0; i < textures.size(); i++) {
+ Ref<ImageTexture> tex = textures[i];
+ ERR_CONTINUE(!tex.is_valid());
+ set_texture_image(0, Vector2i(16, 0), i, tex->get_image());
+ }
+ } else if (tokens.size() == 1 && tokens[0] == "chars") {
+ // Compatibility, BitmapFont.
+ set_fixed_size(16);
+ PackedInt32Array arr = p_value;
+ int len = arr.size();
+ ERR_FAIL_COND_V(len % 9, false);
+ if (!len) {
+ return false;
+ }
+ int chars = len / 9;
+ for (int i = 0; i < chars; i++) {
+ const int32_t *data = &arr[i * 9];
+ char32_t c = data[0];
+ set_glyph_texture_idx(0, Vector2i(16, 0), c, data[1]);
+ set_glyph_uv_rect(0, Vector2i(16, 0), c, Rect2(data[2], data[3], data[4], data[5]));
+ set_glyph_offset(0, Vector2i(16, 0), c, Size2(data[6], data[7]));
+ set_glyph_advance(0, 16, c, Vector2(data[8], 0));
+ }
+ } else if (tokens.size() == 1 && tokens[0] == "kernings") {
+ // Compatibility, BitmapFont.
+ set_fixed_size(16);
+ PackedInt32Array arr = p_value;
+ int len = arr.size();
+ ERR_FAIL_COND_V(len % 3, false);
+ if (!len) {
+ return false;
+ }
+ for (int i = 0; i < len / 3; i++) {
+ const int32_t *data = &arr[i * 3];
+ set_kerning(0, 16, Vector2i(data[0], data[1]), Vector2(data[2], 0));
+ }
+ } else if (tokens.size() == 1 && tokens[0] == "height") {
+ // Compatibility, BitmapFont.
+ bmp_height = p_value;
+ set_fixed_size(16);
+ set_cache_descent(0, 16, bmp_height - bmp_ascent);
+ } else if (tokens.size() == 1 && tokens[0] == "ascent") {
+ // Compatibility, BitmapFont.
+ bmp_ascent = p_value;
+ set_fixed_size(16);
+ set_cache_ascent(0, 16, bmp_ascent);
+ set_cache_descent(0, 16, bmp_height - bmp_ascent);
+ } else if (tokens.size() == 1 && tokens[0] == "fallback") {
+ // Compatibility, BitmapFont.
+ Ref<Font> f = p_value;
+ if (f.is_valid()) {
+ fallbacks.push_back(f);
+ return true;
+ }
+ return false;
+ }
+#endif // DISABLE_DEPRECATED
+
+ if (tokens.size() == 2 && tokens[0] == "language_support_override") {
+ String lang = tokens[1];
+ set_language_support_override(lang, p_value);
+ return true;
+ } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
+ String script = tokens[1];
+ set_script_support_override(script, p_value);
+ return true;
+ } else if (tokens.size() >= 3 && tokens[0] == "cache") {
+ int cache_index = tokens[1].to_int();
+ if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
+ set_variation_coordinates(cache_index, p_value);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "embolden") {
+ set_embolden(cache_index, p_value);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "face_index") {
+ set_face_index(cache_index, p_value);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "transform") {
+ set_transform(cache_index, p_value);
+ return true;
+ }
+ if (tokens.size() >= 5) {
+ Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
+ if (tokens[4] == "ascent") {
+ set_cache_ascent(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "descent") {
+ set_cache_descent(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "underline_position") {
+ set_cache_underline_position(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "underline_thickness") {
+ set_cache_underline_thickness(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "scale") {
+ set_cache_scale(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens.size() == 7 && tokens[4] == "textures") {
+ int texture_index = tokens[5].to_int();
+ if (tokens[6] == "image") {
+ set_texture_image(cache_index, sz, texture_index, p_value);
+ return true;
+ } else if (tokens[6] == "offsets") {
+ set_texture_offsets(cache_index, sz, texture_index, p_value);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
+ int32_t glyph_index = tokens[5].to_int();
+ if (tokens[6] == "advance") {
+ set_glyph_advance(cache_index, sz.x, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "offset") {
+ set_glyph_offset(cache_index, sz, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "size") {
+ set_glyph_size(cache_index, sz, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "uv_rect") {
+ set_glyph_uv_rect(cache_index, sz, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "texture_idx") {
+ set_glyph_texture_idx(cache_index, sz, glyph_index, p_value);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
+ Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
+ set_kerning(cache_index, sz.x, gp, p_value);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool FontFile::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> tokens = p_name.operator String().split("/");
+ if (tokens.size() == 2 && tokens[0] == "language_support_override") {
+ String lang = tokens[1];
+ r_ret = get_language_support_override(lang);
+ return true;
+ } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
+ String script = tokens[1];
+ r_ret = get_script_support_override(script);
+ return true;
+ } else if (tokens.size() >= 3 && tokens[0] == "cache") {
+ int cache_index = tokens[1].to_int();
+ if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
+ r_ret = get_variation_coordinates(cache_index);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "embolden") {
+ r_ret = get_embolden(cache_index);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "face_index") {
+ r_ret = get_face_index(cache_index);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "transform") {
+ r_ret = get_transform(cache_index);
+ return true;
+ }
+ if (tokens.size() >= 5) {
+ Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
+ if (tokens[4] == "ascent") {
+ r_ret = get_cache_ascent(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "descent") {
+ r_ret = get_cache_descent(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "underline_position") {
+ r_ret = get_cache_underline_position(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "underline_thickness") {
+ r_ret = get_cache_underline_thickness(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "scale") {
+ r_ret = get_cache_scale(cache_index, sz.x);
+ return true;
+ } else if (tokens.size() == 7 && tokens[4] == "textures") {
+ int texture_index = tokens[5].to_int();
+ if (tokens[6] == "image") {
+ r_ret = get_texture_image(cache_index, sz, texture_index);
+ return true;
+ } else if (tokens[6] == "offsets") {
+ r_ret = get_texture_offsets(cache_index, sz, texture_index);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
+ int32_t glyph_index = tokens[5].to_int();
+ if (tokens[6] == "advance") {
+ r_ret = get_glyph_advance(cache_index, sz.x, glyph_index);
+ return true;
+ } else if (tokens[6] == "offset") {
+ r_ret = get_glyph_offset(cache_index, sz, glyph_index);
+ return true;
+ } else if (tokens[6] == "size") {
+ r_ret = get_glyph_size(cache_index, sz, glyph_index);
+ return true;
+ } else if (tokens[6] == "uv_rect") {
+ r_ret = get_glyph_uv_rect(cache_index, sz, glyph_index);
+ return true;
+ } else if (tokens[6] == "texture_idx") {
+ r_ret = get_glyph_texture_idx(cache_index, sz, glyph_index);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
+ Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
+ r_ret = get_kerning(cache_index, sz.x, gp);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
+ Vector<String> lang_over = get_language_support_overrides();
+ for (int i = 0; i < lang_over.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "language_support_override/" + lang_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ Vector<String> scr_over = get_script_support_overrides();
+ for (int i = 0; i < scr_over.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ for (int i = 0; i < cache.size(); i++) {
+ String prefix = "cache/" + itos(i) + "/";
+ Array sizes = get_size_cache_list(i);
+ p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+
+ for (int j = 0; j < sizes.size(); j++) {
+ Vector2i sz = sizes[j];
+ String prefix_sz = prefix + itos(sz.x) + "/" + itos(sz.y) + "/";
+ if (sz.y == 0) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "ascent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "descent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_thickness", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+
+ int tx_cnt = get_texture_count(i, sz);
+ for (int k = 0; k < tx_cnt; k++) {
+ p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
+ }
+ Array glyphs = get_glyph_list(i, sz);
+ for (int k = 0; k < glyphs.size(); k++) {
+ const int32_t &gl = glyphs[k];
+ if (sz.y == 0) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::RECT2, prefix_sz + "glyphs/" + itos(gl) + "/uv_rect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ if (sz.y == 0) {
+ Array kerning_map = get_kerning_list(i, sz.x);
+ for (int k = 0; k < kerning_map.size(); k++) {
+ const Vector2i &gl_pair = kerning_map[k];
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ }
+ }
+ }
+}
+
+void FontFile::reset_state() {
+ _clear_cache();
+ data.clear();
+ data_ptr = nullptr;
+ data_size = 0;
+ cache.clear();
+
+ antialiased = true;
+ mipmaps = false;
+ msdf = false;
+ force_autohinter = false;
+ hinting = TextServer::HINTING_LIGHT;
+ subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
+ msdf_pixel_range = 14;
+ msdf_size = 128;
+ fixed_size = 0;
+ oversampling = 0.f;
+
+ Font::reset_state();
+}
+
/*************************************************************************/
-Error FontData::load_bitmap_font(const String &p_path) {
+Error FontFile::load_bitmap_font(const String &p_path) {
reset_state();
antialiased = false;
@@ -1209,13 +1778,13 @@ Error FontData::load_bitmap_font(const String &p_path) {
set_font_name(font_name);
set_font_style(st_flags);
- set_ascent(0, base_size, ascent);
- set_descent(0, base_size, height - ascent);
+ set_cache_ascent(0, base_size, ascent);
+ set_cache_descent(0, base_size, height - ascent);
return OK;
}
-Error FontData::load_dynamic_font(const String &p_path) {
+Error FontFile::load_dynamic_font(const String &p_path) {
reset_state();
Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
@@ -1224,7 +1793,7 @@ Error FontData::load_dynamic_font(const String &p_path) {
return OK;
}
-void FontData::set_data_ptr(const uint8_t *p_data, size_t p_size) {
+void FontFile::set_data_ptr(const uint8_t *p_data, size_t p_size) {
data.clear();
data_ptr = p_data;
data_size = p_size;
@@ -1238,7 +1807,7 @@ void FontData::set_data_ptr(const uint8_t *p_data, size_t p_size) {
}
}
-void FontData::set_data(const PackedByteArray &p_data) {
+void FontFile::set_data(const PackedByteArray &p_data) {
data = p_data;
data_ptr = data.ptr();
data_size = data.size();
@@ -1252,32 +1821,7 @@ void FontData::set_data(const PackedByteArray &p_data) {
}
}
-void FontData::set_face_index(int64_t p_index) {
- ERR_FAIL_COND(p_index < 0);
- ERR_FAIL_COND(p_index >= 0x7FFF);
-
- if (face_index != p_index) {
- face_index = p_index;
- if (data_ptr != nullptr) {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->font_set_face_index(cache[i], face_index);
- }
- }
- }
- }
-}
-
-int64_t FontData::get_face_index() const {
- return face_index;
-}
-
-int64_t FontData::get_face_count() const {
- _ensure_rid(0);
- return TS->font_get_face_count(cache[0]);
-}
-
-PackedByteArray FontData::get_data() const {
+PackedByteArray FontFile::get_data() const {
if (unlikely((size_t)data.size() != data_size)) {
PackedByteArray *data_w = const_cast<PackedByteArray *>(&data);
data_w->resize(data_size);
@@ -1286,37 +1830,22 @@ PackedByteArray FontData::get_data() const {
return data;
}
-void FontData::set_font_name(const String &p_name) {
+void FontFile::set_font_name(const String &p_name) {
_ensure_rid(0);
TS->font_set_name(cache[0], p_name);
}
-String FontData::get_font_name() const {
- _ensure_rid(0);
- return TS->font_get_name(cache[0]);
-}
-
-void FontData::set_font_style_name(const String &p_name) {
+void FontFile::set_font_style_name(const String &p_name) {
_ensure_rid(0);
TS->font_set_style_name(cache[0], p_name);
}
-String FontData::get_font_style_name() const {
- _ensure_rid(0);
- return TS->font_get_style_name(cache[0]);
-}
-
-void FontData::set_font_style(uint32_t p_style) {
+void FontFile::set_font_style(uint32_t p_style) {
_ensure_rid(0);
TS->font_set_style(cache[0], p_style);
}
-uint32_t FontData::get_font_style() const {
- _ensure_rid(0);
- return TS->font_get_style(cache[0]);
-}
-
-void FontData::set_antialiased(bool p_antialiased) {
+void FontFile::set_antialiased(bool p_antialiased) {
if (antialiased != p_antialiased) {
antialiased = p_antialiased;
for (int i = 0; i < cache.size(); i++) {
@@ -1327,11 +1856,11 @@ void FontData::set_antialiased(bool p_antialiased) {
}
}
-bool FontData::is_antialiased() const {
+bool FontFile::is_antialiased() const {
return antialiased;
}
-void FontData::set_generate_mipmaps(bool p_generate_mipmaps) {
+void FontFile::set_generate_mipmaps(bool p_generate_mipmaps) {
if (mipmaps != p_generate_mipmaps) {
mipmaps = p_generate_mipmaps;
for (int i = 0; i < cache.size(); i++) {
@@ -1342,11 +1871,11 @@ void FontData::set_generate_mipmaps(bool p_generate_mipmaps) {
}
}
-bool FontData::get_generate_mipmaps() const {
+bool FontFile::get_generate_mipmaps() const {
return mipmaps;
}
-void FontData::set_multichannel_signed_distance_field(bool p_msdf) {
+void FontFile::set_multichannel_signed_distance_field(bool p_msdf) {
if (msdf != p_msdf) {
msdf = p_msdf;
for (int i = 0; i < cache.size(); i++) {
@@ -1357,11 +1886,11 @@ void FontData::set_multichannel_signed_distance_field(bool p_msdf) {
}
}
-bool FontData::is_multichannel_signed_distance_field() const {
+bool FontFile::is_multichannel_signed_distance_field() const {
return msdf;
}
-void FontData::set_msdf_pixel_range(int p_msdf_pixel_range) {
+void FontFile::set_msdf_pixel_range(int p_msdf_pixel_range) {
if (msdf_pixel_range != p_msdf_pixel_range) {
msdf_pixel_range = p_msdf_pixel_range;
for (int i = 0; i < cache.size(); i++) {
@@ -1372,11 +1901,11 @@ void FontData::set_msdf_pixel_range(int p_msdf_pixel_range) {
}
}
-int FontData::get_msdf_pixel_range() const {
+int FontFile::get_msdf_pixel_range() const {
return msdf_pixel_range;
}
-void FontData::set_msdf_size(int p_msdf_size) {
+void FontFile::set_msdf_size(int p_msdf_size) {
if (msdf_size != p_msdf_size) {
msdf_size = p_msdf_size;
for (int i = 0; i < cache.size(); i++) {
@@ -1387,11 +1916,11 @@ void FontData::set_msdf_size(int p_msdf_size) {
}
}
-int FontData::get_msdf_size() const {
+int FontFile::get_msdf_size() const {
return msdf_size;
}
-void FontData::set_fixed_size(int p_fixed_size) {
+void FontFile::set_fixed_size(int p_fixed_size) {
if (fixed_size != p_fixed_size) {
fixed_size = p_fixed_size;
for (int i = 0; i < cache.size(); i++) {
@@ -1402,11 +1931,11 @@ void FontData::set_fixed_size(int p_fixed_size) {
}
}
-int FontData::get_fixed_size() const {
+int FontFile::get_fixed_size() const {
return fixed_size;
}
-void FontData::set_force_autohinter(bool p_force_autohinter) {
+void FontFile::set_force_autohinter(bool p_force_autohinter) {
if (force_autohinter != p_force_autohinter) {
force_autohinter = p_force_autohinter;
for (int i = 0; i < cache.size(); i++) {
@@ -1417,11 +1946,11 @@ void FontData::set_force_autohinter(bool p_force_autohinter) {
}
}
-bool FontData::is_force_autohinter() const {
+bool FontFile::is_force_autohinter() const {
return force_autohinter;
}
-void FontData::set_hinting(TextServer::Hinting p_hinting) {
+void FontFile::set_hinting(TextServer::Hinting p_hinting) {
if (hinting != p_hinting) {
hinting = p_hinting;
for (int i = 0; i < cache.size(); i++) {
@@ -1432,11 +1961,11 @@ void FontData::set_hinting(TextServer::Hinting p_hinting) {
}
}
-TextServer::Hinting FontData::get_hinting() const {
+TextServer::Hinting FontFile::get_hinting() const {
return hinting;
}
-void FontData::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
+void FontFile::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
if (subpixel_positioning != p_subpixel) {
subpixel_positioning = p_subpixel;
for (int i = 0; i < cache.size(); i++) {
@@ -1447,41 +1976,11 @@ void FontData::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpix
}
}
-TextServer::SubpixelPositioning FontData::get_subpixel_positioning() const {
+TextServer::SubpixelPositioning FontFile::get_subpixel_positioning() const {
return subpixel_positioning;
}
-void FontData::set_embolden(float p_strength) {
- if (embolden != p_strength) {
- embolden = p_strength;
- for (int i = 0; i < cache.size(); i++) {
- _ensure_rid(i);
- TS->font_set_embolden(cache[i], embolden);
- }
- emit_changed();
- }
-}
-
-float FontData::get_embolden() const {
- return embolden;
-}
-
-void FontData::set_transform(Transform2D p_transform) {
- if (transform != p_transform) {
- transform = p_transform;
- for (int i = 0; i < cache.size(); i++) {
- _ensure_rid(i);
- TS->font_set_transform(cache[i], transform);
- }
- emit_changed();
- }
-}
-
-Transform2D FontData::get_transform() const {
- return transform;
-}
-
-void FontData::set_oversampling(real_t p_oversampling) {
+void FontFile::set_oversampling(real_t p_oversampling) {
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
for (int i = 0; i < cache.size(); i++) {
@@ -1492,17 +1991,20 @@ void FontData::set_oversampling(real_t p_oversampling) {
}
}
-real_t FontData::get_oversampling() const {
+real_t FontFile::get_oversampling() const {
return oversampling;
}
-RID FontData::find_cache(const Dictionary &p_variation_coordinates) const {
+RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform) const {
// Find existing variation cache.
const Dictionary &supported_coords = get_supported_variation_list();
for (int i = 0; i < cache.size(); i++) {
if (cache[i].is_valid()) {
const Dictionary &cache_var = TS->font_get_variation_coordinates(cache[i]);
bool match = true;
+ match = match && (TS->font_get_face_index(cache[i]) == p_face_index);
+ match = match && (TS->font_get_embolden(cache[i]) == p_strength);
+ match = match && (TS->font_get_transform(cache[i]) == p_transform);
for (const Variant *V = supported_coords.next(nullptr); V && match; V = supported_coords.next(V)) {
const Vector3 &def = supported_coords[*V];
@@ -1538,19 +2040,28 @@ RID FontData::find_cache(const Dictionary &p_variation_coordinates) const {
int idx = cache.size();
_ensure_rid(idx);
TS->font_set_variation_coordinates(cache[idx], p_variation_coordinates);
+ TS->font_set_face_index(cache[idx], p_face_index);
+ TS->font_set_embolden(cache[idx], p_strength);
+ TS->font_set_transform(cache[idx], p_transform);
return cache[idx];
}
-int FontData::get_cache_count() const {
+RID FontFile::_get_rid() const {
+ _ensure_rid(0);
+ return cache[0];
+}
+
+int FontFile::get_cache_count() const {
return cache.size();
}
-void FontData::clear_cache() {
+void FontFile::clear_cache() {
_clear_cache();
cache.clear();
+ emit_changed();
}
-void FontData::remove_cache(int p_cache_index) {
+void FontFile::remove_cache(int p_cache_index) {
ERR_FAIL_INDEX(p_cache_index, cache.size());
if (cache[p_cache_index].is_valid()) {
TS->free_rid(cache.write[p_cache_index]);
@@ -1559,952 +2070,607 @@ void FontData::remove_cache(int p_cache_index) {
emit_changed();
}
-Array FontData::get_size_cache_list(int p_cache_index) const {
+Array FontFile::get_size_cache_list(int p_cache_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_size_cache_list(cache[p_cache_index]);
}
-void FontData::clear_size_cache(int p_cache_index) {
+void FontFile::clear_size_cache(int p_cache_index) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_size_cache(cache[p_cache_index]);
}
-void FontData::remove_size_cache(int p_cache_index, const Vector2i &p_size) {
+void FontFile::remove_size_cache(int p_cache_index, const Vector2i &p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_size_cache(cache[p_cache_index], p_size);
}
-void FontData::set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates) {
+void FontFile::set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_variation_coordinates(cache[p_cache_index], p_variation_coordinates);
- emit_changed();
}
-Dictionary FontData::get_variation_coordinates(int p_cache_index) const {
+Dictionary FontFile::get_variation_coordinates(int p_cache_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Dictionary());
_ensure_rid(p_cache_index);
return TS->font_get_variation_coordinates(cache[p_cache_index]);
}
-void FontData::set_ascent(int p_cache_index, int p_size, real_t p_ascent) {
+void FontFile::set_embolden(int p_cache_index, float p_strength) {
+ ERR_FAIL_COND(p_cache_index < 0);
+ _ensure_rid(p_cache_index);
+ TS->font_set_embolden(cache[p_cache_index], p_strength);
+}
+
+float FontFile::get_embolden(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
+ _ensure_rid(p_cache_index);
+ return TS->font_get_embolden(cache[p_cache_index]);
+}
+
+void FontFile::set_transform(int p_cache_index, Transform2D p_transform) {
+ ERR_FAIL_COND(p_cache_index < 0);
+ _ensure_rid(p_cache_index);
+ TS->font_set_transform(cache[p_cache_index], p_transform);
+}
+
+Transform2D FontFile::get_transform(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Transform2D());
+ _ensure_rid(p_cache_index);
+ return TS->font_get_transform(cache[p_cache_index]);
+}
+
+void FontFile::set_face_index(int p_cache_index, int64_t p_index) {
+ ERR_FAIL_COND(p_cache_index < 0);
+ ERR_FAIL_COND(p_index < 0);
+ ERR_FAIL_COND(p_index >= 0x7FFF);
+
+ _ensure_rid(p_cache_index);
+ TS->font_set_face_index(cache[p_cache_index], p_index);
+}
+
+int64_t FontFile::get_face_index(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0);
+ _ensure_rid(p_cache_index);
+ return TS->font_get_face_index(cache[p_cache_index]);
+}
+
+void FontFile::set_cache_ascent(int p_cache_index, int p_size, real_t p_ascent) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_ascent(cache[p_cache_index], p_size, p_ascent);
}
-real_t FontData::get_ascent(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_ascent(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_ascent(cache[p_cache_index], p_size);
}
-void FontData::set_descent(int p_cache_index, int p_size, real_t p_descent) {
+void FontFile::set_cache_descent(int p_cache_index, int p_size, real_t p_descent) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_descent(cache[p_cache_index], p_size, p_descent);
}
-real_t FontData::get_descent(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_descent(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_descent(cache[p_cache_index], p_size);
}
-void FontData::set_underline_position(int p_cache_index, int p_size, real_t p_underline_position) {
+void FontFile::set_cache_underline_position(int p_cache_index, int p_size, real_t p_underline_position) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_underline_position(cache[p_cache_index], p_size, p_underline_position);
}
-real_t FontData::get_underline_position(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_underline_position(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_underline_position(cache[p_cache_index], p_size);
}
-void FontData::set_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness) {
+void FontFile::set_cache_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_underline_thickness(cache[p_cache_index], p_size, p_underline_thickness);
}
-real_t FontData::get_underline_thickness(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_underline_thickness(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_underline_thickness(cache[p_cache_index], p_size);
}
-void FontData::set_scale(int p_cache_index, int p_size, real_t p_scale) {
+void FontFile::set_cache_scale(int p_cache_index, int p_size, real_t p_scale) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_scale(cache[p_cache_index], p_size, p_scale);
}
-real_t FontData::get_scale(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_scale(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_scale(cache[p_cache_index], p_size);
}
-void FontData::set_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing, int p_value) {
- ERR_FAIL_COND(p_cache_index < 0);
- _ensure_rid(p_cache_index);
- TS->font_set_spacing(cache[p_cache_index], p_size, p_spacing, p_value);
-}
-
-int FontData::get_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing) const {
- ERR_FAIL_COND_V(p_cache_index < 0, 0);
- _ensure_rid(p_cache_index);
- return TS->font_get_spacing(cache[p_cache_index], p_size, p_spacing);
-}
-
-int FontData::get_texture_count(int p_cache_index, const Vector2i &p_size) const {
+int FontFile::get_texture_count(int p_cache_index, const Vector2i &p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_texture_count(cache[p_cache_index], p_size);
}
-void FontData::clear_textures(int p_cache_index, const Vector2i &p_size) {
+void FontFile::clear_textures(int p_cache_index, const Vector2i &p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_textures(cache[p_cache_index], p_size);
}
-void FontData::remove_texture(int p_cache_index, const Vector2i &p_size, int p_texture_index) {
+void FontFile::remove_texture(int p_cache_index, const Vector2i &p_size, int p_texture_index) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_texture(cache[p_cache_index], p_size, p_texture_index);
}
-void FontData::set_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+void FontFile::set_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_texture_image(cache[p_cache_index], p_size, p_texture_index, p_image);
}
-Ref<Image> FontData::get_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
+Ref<Image> FontFile::get_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Ref<Image>());
_ensure_rid(p_cache_index);
return TS->font_get_texture_image(cache[p_cache_index], p_size, p_texture_index);
}
-void FontData::set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+void FontFile::set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_texture_offsets(cache[p_cache_index], p_size, p_texture_index, p_offset);
}
-PackedInt32Array FontData::get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
+PackedInt32Array FontFile::get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
_ensure_rid(p_cache_index);
return TS->font_get_texture_offsets(cache[p_cache_index], p_size, p_texture_index);
}
-Array FontData::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
+Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_list(cache[p_cache_index], p_size);
}
-void FontData::clear_glyphs(int p_cache_index, const Vector2i &p_size) {
+void FontFile::clear_glyphs(int p_cache_index, const Vector2i &p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_glyphs(cache[p_cache_index], p_size);
}
-void FontData::remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) {
+void FontFile::remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_glyph(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+void FontFile::set_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_advance(cache[p_cache_index], p_size, p_glyph, p_advance);
}
-Vector2 FontData::get_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph) const {
+Vector2 FontFile::get_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_advance(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+void FontFile::set_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_offset(cache[p_cache_index], p_size, p_glyph, p_offset);
}
-Vector2 FontData::get_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 FontFile::get_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_offset(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+void FontFile::set_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_size(cache[p_cache_index], p_size, p_glyph, p_gl_size);
}
-Vector2 FontData::get_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 FontFile::get_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_size(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+void FontFile::set_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph, p_uv_rect);
}
-Rect2 FontData::get_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+Rect2 FontFile::get_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Rect2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+void FontFile::set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph, p_texture_idx);
}
-int FontData::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+int FontFile::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph);
}
-Array FontData::get_kerning_list(int p_cache_index, int p_size) const {
+Array FontFile::get_kerning_list(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_kerning_list(cache[p_cache_index], p_size);
}
-void FontData::clear_kerning_map(int p_cache_index, int p_size) {
+void FontFile::clear_kerning_map(int p_cache_index, int p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_kerning_map(cache[p_cache_index], p_size);
}
-void FontData::remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) {
+void FontFile::remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_kerning(cache[p_cache_index], p_size, p_glyph_pair);
}
-void FontData::set_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+void FontFile::set_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_kerning(cache[p_cache_index], p_size, p_glyph_pair, p_kerning);
}
-Vector2 FontData::get_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) const {
+Vector2 FontFile::get_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_kerning(cache[p_cache_index], p_size, p_glyph_pair);
}
-void FontData::render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+void FontFile::render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_render_range(cache[p_cache_index], p_size, p_start, p_end);
}
-void FontData::render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index) {
+void FontFile::render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_render_glyph(cache[p_cache_index], p_size, p_index);
}
-RID FontData::get_cache_rid(int p_cache_index) const {
- ERR_FAIL_COND_V(p_cache_index < 0, RID());
- _ensure_rid(p_cache_index);
- return cache[p_cache_index];
-}
-
-bool FontData::is_language_supported(const String &p_language) const {
- _ensure_rid(0);
- return TS->font_is_language_supported(cache[0], p_language);
-}
-
-void FontData::set_language_support_override(const String &p_language, bool p_supported) {
+void FontFile::set_language_support_override(const String &p_language, bool p_supported) {
_ensure_rid(0);
TS->font_set_language_support_override(cache[0], p_language, p_supported);
}
-bool FontData::get_language_support_override(const String &p_language) const {
+bool FontFile::get_language_support_override(const String &p_language) const {
_ensure_rid(0);
return TS->font_get_language_support_override(cache[0], p_language);
}
-void FontData::remove_language_support_override(const String &p_language) {
+void FontFile::remove_language_support_override(const String &p_language) {
_ensure_rid(0);
TS->font_remove_language_support_override(cache[0], p_language);
}
-Vector<String> FontData::get_language_support_overrides() const {
+Vector<String> FontFile::get_language_support_overrides() const {
_ensure_rid(0);
return TS->font_get_language_support_overrides(cache[0]);
}
-bool FontData::is_script_supported(const String &p_script) const {
- _ensure_rid(0);
- return TS->font_is_script_supported(cache[0], p_script);
-}
-
-void FontData::set_script_support_override(const String &p_script, bool p_supported) {
+void FontFile::set_script_support_override(const String &p_script, bool p_supported) {
_ensure_rid(0);
TS->font_set_script_support_override(cache[0], p_script, p_supported);
}
-bool FontData::get_script_support_override(const String &p_script) const {
+bool FontFile::get_script_support_override(const String &p_script) const {
_ensure_rid(0);
return TS->font_get_script_support_override(cache[0], p_script);
}
-void FontData::remove_script_support_override(const String &p_script) {
+void FontFile::remove_script_support_override(const String &p_script) {
_ensure_rid(0);
TS->font_remove_script_support_override(cache[0], p_script);
}
-Vector<String> FontData::get_script_support_overrides() const {
+Vector<String> FontFile::get_script_support_overrides() const {
_ensure_rid(0);
return TS->font_get_script_support_overrides(cache[0]);
}
-void FontData::set_opentype_feature_overrides(const Dictionary &p_overrides) {
+void FontFile::set_opentype_feature_overrides(const Dictionary &p_overrides) {
_ensure_rid(0);
TS->font_set_opentype_feature_overrides(cache[0], p_overrides);
}
-Dictionary FontData::get_opentype_feature_overrides() const {
+Dictionary FontFile::get_opentype_feature_overrides() const {
_ensure_rid(0);
return TS->font_get_opentype_feature_overrides(cache[0]);
}
-bool FontData::has_char(char32_t p_char) const {
- _ensure_rid(0);
- return TS->font_has_char(cache[0], p_char);
-}
-
-String FontData::get_supported_chars() const {
- _ensure_rid(0);
- return TS->font_get_supported_chars(cache[0]);
-}
-
-int32_t FontData::get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector) const {
+int32_t FontFile::get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector) const {
_ensure_rid(0);
return TS->font_get_glyph_index(cache[0], p_size, p_char, p_variation_selector);
}
-Dictionary FontData::get_supported_feature_list() const {
- _ensure_rid(0);
- return TS->font_supported_feature_list(cache[0]);
-}
-
-Dictionary FontData::get_supported_variation_list() const {
- _ensure_rid(0);
- return TS->font_supported_variation_list(cache[0]);
-}
-
-FontData::FontData() {
+FontFile::FontFile() {
/* NOP */
}
-FontData::~FontData() {
- _clear_cache();
+FontFile::~FontFile() {
+ reset_state();
}
/*************************************************************************/
+/* FontVariation */
+/*************************************************************************/
-void Font::_data_changed() {
- for (int i = 0; i < rids.size(); i++) {
- rids.write[i] = RID();
- }
- emit_changed();
-}
+void FontVariation::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_base_font", "font"), &FontVariation::set_base_font);
+ ClassDB::bind_method(D_METHOD("get_base_font"), &FontVariation::get_base_font);
-void Font::_ensure_rid(int p_index) const {
- // Find or create cache record.
- if (!rids[p_index].is_valid() && data[p_index].is_valid()) {
- rids.write[p_index] = data[p_index]->find_cache(variation_coordinates);
- }
-}
+ ClassDB::bind_method(D_METHOD("set_variation_opentype", "coords"), &FontVariation::set_variation_opentype);
+ ClassDB::bind_method(D_METHOD("get_variation_opentype"), &FontVariation::get_variation_opentype);
-void Font::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_data", "data"), &Font::add_data);
- ClassDB::bind_method(D_METHOD("set_data", "idx", "data"), &Font::set_data);
- ClassDB::bind_method(D_METHOD("get_data_count"), &Font::get_data_count);
- ClassDB::bind_method(D_METHOD("get_data", "idx"), &Font::get_data);
- ClassDB::bind_method(D_METHOD("get_data_rid", "idx"), &Font::get_data_rid);
- ClassDB::bind_method(D_METHOD("clear_data"), &Font::clear_data);
- ClassDB::bind_method(D_METHOD("remove_data", "idx"), &Font::remove_data);
-
- ClassDB::bind_method(D_METHOD("set_variation_coordinates", "variation_coordinates"), &Font::set_variation_coordinates);
- ClassDB::bind_method(D_METHOD("get_variation_coordinates"), &Font::get_variation_coordinates);
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "variation_coordinates"), "set_variation_coordinates", "get_variation_coordinates");
-
- ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &Font::set_spacing);
- ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing);
+ ClassDB::bind_method(D_METHOD("set_variation_embolden", "strength"), &FontVariation::set_variation_embolden);
+ ClassDB::bind_method(D_METHOD("get_variation_embolden"), &FontVariation::get_variation_embolden);
- ADD_GROUP("Extra Spacing", "spacing");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_BOTTOM);
+ ClassDB::bind_method(D_METHOD("set_variation_face_index", "face_index"), &FontVariation::set_variation_face_index);
+ ClassDB::bind_method(D_METHOD("get_variation_face_index"), &FontVariation::get_variation_face_index);
- ClassDB::bind_method(D_METHOD("get_height", "size"), &Font::get_height, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_ascent", "size"), &Font::get_ascent, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_descent", "size"), &Font::get_descent, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &Font::get_underline_position, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &Font::get_underline_thickness, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("set_variation_transform", "transform"), &FontVariation::set_variation_transform);
+ ClassDB::bind_method(D_METHOD("get_variation_transform"), &FontVariation::get_variation_transform);
- ClassDB::bind_method(D_METHOD("get_string_size", "text", "size", "alignment", "width", "flags"), &Font::get_string_size, DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
- ClassDB::bind_method(D_METHOD("get_multiline_string_size", "text", "width", "size", "flags"), &Font::get_multiline_string_size, DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("set_opentype_features", "features"), &FontVariation::set_opentype_features);
- ClassDB::bind_method(D_METHOD("draw_string", "canvas_item", "pos", "text", "alignment", "width", "size", "modulate", "outline_size", "outline_modulate", "flags"), &Font::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
- ClassDB::bind_method(D_METHOD("draw_multiline_string", "canvas_item", "pos", "text", "alignment", "width", "max_lines", "size", "modulate", "outline_size", "outline_modulate", "flags"), &Font::draw_multiline_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &FontVariation::set_spacing);
- ClassDB::bind_method(D_METHOD("get_char_size", "char", "next", "size"), &Font::get_char_size, DEFVAL(0), DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "next", "size", "modulate", "outline_size", "outline_modulate"), &Font::draw_char, DEFVAL(0), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)));
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_base_font", "get_base_font");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), "set_fallbacks", "get_fallbacks");
- ClassDB::bind_method(D_METHOD("has_char", "char"), &Font::has_char);
- ClassDB::bind_method(D_METHOD("get_supported_chars"), &Font::get_supported_chars);
+ ADD_GROUP("Variation", "variation");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "variation_opentype"), "set_variation_opentype", "get_variation_opentype");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "variation_face_index"), "set_variation_face_index", "get_variation_face_index");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "variation_embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), "set_variation_embolden", "get_variation_embolden");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "variation_transform", PROPERTY_HINT_NONE, "suffix:px"), "set_variation_transform", "get_variation_transform");
- ClassDB::bind_method(D_METHOD("update_changes"), &Font::update_changes);
-
- ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids);
-}
+ ADD_GROUP("OpenType Features", "opentype");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_features"), "set_opentype_features", "get_opentype_features");
-bool Font::_set(const StringName &p_name, const Variant &p_value) {
- Vector<String> tokens = p_name.operator String().split("/");
-#ifndef DISABLE_DEPRECATED
- if (tokens.size() == 1 && tokens[0] == "font_data") {
- // Compatibility, DynamicFont main data.
- Ref<FontData> fd = p_value;
- if (fd.is_valid()) {
- add_data(fd);
- return true;
- }
- return false;
- } else if (tokens.size() == 2 && tokens[0] == "fallback") {
- // Compatibility, DynamicFont fallback data.
- Ref<FontData> fd = p_value;
- if (fd.is_valid()) {
- add_data(fd);
- return true;
- }
- return false;
- } else if (tokens.size() == 1 && tokens[0] == "fallback") {
- // Compatibility, BitmapFont fallback data.
- Ref<Font> f = p_value;
- if (f.is_valid()) {
- for (int i = 0; i < f->get_data_count(); i++) {
- add_data(f->get_data(i));
- }
- return true;
- }
- return false;
- }
-#endif /* DISABLE_DEPRECATED */
- if (tokens.size() == 2 && tokens[0] == "data") {
- int idx = tokens[1].to_int();
- Ref<FontData> fd = p_value;
- if (fd.is_valid()) {
- if (idx == data.size()) {
- add_data(fd);
- return true;
- } else if (idx >= 0 && idx < data.size()) {
- set_data(idx, fd);
- return true;
- } else {
- return false;
- }
- } else if (idx >= 0 && idx < data.size()) {
- remove_data(idx);
- return true;
- }
- }
- return false;
+ ADD_GROUP("Extra Spacing", "spacing");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_glyph", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_GLYPH);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_space", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_SPACE);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_BOTTOM);
}
-bool Font::_get(const StringName &p_name, Variant &r_ret) const {
- Vector<String> tokens = p_name.operator String().split("/");
- if (tokens.size() == 2 && tokens[0] == "data") {
- int idx = tokens[1].to_int();
+void FontVariation::_update_rids() const {
+ Ref<Font> f = _get_base_font_or_default();
- if (idx == data.size()) {
- r_ret = Ref<FontData>();
- return true;
- } else if (idx >= 0 && idx < data.size()) {
- r_ret = get_data(idx);
- return true;
+ rids.clear();
+ if (fallbacks.is_empty() && f.is_valid()) {
+ RID rid = _get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
}
- }
-
- return false;
-}
-void Font::_get_property_list(List<PropertyInfo> *p_list) const {
- for (int i = 0; i < data.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
+ const TypedArray<Font> &base_fallbacks = f->get_fallbacks();
+ for (int i = 0; i < base_fallbacks.size(); i++) {
+ _update_rids_fb(base_fallbacks[i], 0);
+ }
+ } else {
+ _update_rids_fb(const_cast<FontVariation *>(this), 0);
}
- p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
+ dirty_rids = false;
}
-void Font::reset_state() {
- for (int i = 0; i < data.size(); i++) {
- if (data[i].is_valid()) {
- data.write[i]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- }
+void FontVariation::reset_state() {
+ if (base_font.is_valid()) {
+ base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font.unref();
}
- cache.clear();
- cache_wrap.clear();
- data.clear();
- rids.clear();
- variation_coordinates.clear();
- spacing_bottom = 0;
- spacing_top = 0;
-}
-
-Dictionary Font::get_feature_list() const {
- Dictionary out;
- for (int i = 0; i < data.size(); i++) {
- Dictionary data_ftrs = data[i]->get_supported_feature_list();
- for (const Variant *ftr = data_ftrs.next(nullptr); ftr != nullptr; ftr = data_ftrs.next(ftr)) {
- out[*ftr] = data_ftrs[*ftr];
- }
+ if (theme_font.is_valid()) {
+ theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ theme_font.unref();
}
- return out;
-}
-void Font::add_data(const Ref<FontData> &p_data) {
- ERR_FAIL_COND(p_data.is_null());
- data.push_back(p_data);
- rids.push_back(RID());
+ variation = Variation();
+ opentype_features = Dictionary();
- if (data[data.size() - 1].is_valid()) {
- data.write[data.size() - 1]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- Dictionary data_var_list = p_data->get_supported_variation_list();
- for (int j = 0; j < data_var_list.size(); j++) {
- int32_t tag = data_var_list.get_key_at_index(j);
- Vector3i value = data_var_list.get_value_at_index(j);
- if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
- variation_coordinates[TS->tag_to_name(tag)] = value.z;
- }
- }
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ extra_spacing[i] = 0;
}
- cache.clear();
- cache_wrap.clear();
-
- emit_changed();
- notify_property_list_changed();
+ Font::reset_state();
}
-void Font::set_data(int p_idx, const Ref<FontData> &p_data) {
- ERR_FAIL_COND(p_data.is_null());
- ERR_FAIL_INDEX(p_idx, data.size());
-
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
- }
-
- data.write[p_idx] = p_data;
- rids.write[p_idx] = RID();
- Dictionary data_var_list = p_data->get_supported_variation_list();
- for (int j = 0; j < data_var_list.size(); j++) {
- int32_t tag = data_var_list.get_key_at_index(j);
- Vector3i value = data_var_list.get_value_at_index(j);
- if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
- variation_coordinates[TS->tag_to_name(tag)] = value.z;
+void FontVariation::set_base_font(const Ref<Font> &p_font) {
+ if (base_font != p_font) {
+ if (base_font.is_valid()) {
+ base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
}
+ base_font = p_font;
+ if (base_font.is_valid()) {
+ base_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ _invalidate_rids();
+ notify_property_list_changed();
}
-
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- }
-
- cache.clear();
- cache_wrap.clear();
-
- emit_changed();
- notify_property_list_changed();
-}
-
-int Font::get_data_count() const {
- return data.size();
-}
-
-Ref<FontData> Font::get_data(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, data.size(), Ref<FontData>());
- return data[p_idx];
}
-RID Font::get_data_rid(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, data.size(), RID());
- _ensure_rid(p_idx);
- return rids[p_idx];
+Ref<Font> FontVariation::get_base_font() const {
+ return base_font;
}
-void Font::clear_data() {
- for (int i = 0; i < data.size(); i++) {
- if (data[i].is_valid()) {
- data.write[i]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- }
+Ref<Font> FontVariation::_get_base_font_or_default() const {
+ if (theme_font.is_valid()) {
+ theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids));
+ theme_font.unref();
}
- data.clear();
- rids.clear();
-}
-void Font::remove_data(int p_idx) {
- ERR_FAIL_INDEX(p_idx, data.size());
-
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
+ if (base_font.is_valid()) {
+ return base_font;
}
- data.remove_at(p_idx);
- rids.remove_at(p_idx);
-
- cache.clear();
- cache_wrap.clear();
+ // Check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ List<StringName> theme_types;
+ Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
- emit_changed();
- notify_property_list_changed();
-}
+ for (const StringName &E : theme_types) {
+ if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
+ }
+ }
+ }
-void Font::set_variation_coordinates(const Dictionary &p_variation_coordinates) {
- _data_changed();
- variation_coordinates = p_variation_coordinates;
-}
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ if (Theme::get_default().is_valid()) {
+ List<StringName> theme_types;
+ Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
-Dictionary Font::get_variation_coordinates() const {
- return variation_coordinates;
-}
+ for (const StringName &E : theme_types) {
+ if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
+ }
+ }
-void Font::set_spacing(TextServer::SpacingType p_spacing, int p_value) {
- _data_changed();
- switch (p_spacing) {
- case TextServer::SPACING_TOP: {
- spacing_top = p_value;
- } break;
- case TextServer::SPACING_BOTTOM: {
- spacing_bottom = p_value;
- } break;
- default: {
- ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing));
- } break;
+ // If they don't exist, use any type to return the default/empty value.
+ Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
-}
-int Font::get_spacing(TextServer::SpacingType p_spacing) const {
- switch (p_spacing) {
- case TextServer::SPACING_TOP: {
- return spacing_top;
- } break;
- case TextServer::SPACING_BOTTOM: {
- return spacing_bottom;
- } break;
- default: {
- ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing));
- } break;
- }
+ return Ref<Font>();
}
-real_t Font::get_height(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_ascent(rids[i], p_size) + TS->font_get_descent(rids[i], p_size));
+void FontVariation::set_variation_opentype(const Dictionary &p_coords) {
+ if (variation.opentype != p_coords) {
+ variation.opentype = p_coords;
+ _invalidate_rids();
}
- return ret + spacing_bottom + spacing_top;
}
-real_t Font::get_ascent(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_ascent(rids[i], p_size));
- }
- return ret + spacing_top;
+Dictionary FontVariation::get_variation_opentype() const {
+ return variation.opentype;
}
-real_t Font::get_descent(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_descent(rids[i], p_size));
+void FontVariation::set_variation_embolden(float p_strength) {
+ if (variation.embolden != p_strength) {
+ variation.embolden = p_strength;
+ _invalidate_rids();
}
- return ret + spacing_bottom;
}
-real_t Font::get_underline_position(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_underline_position(rids[i], p_size));
- }
- return ret + spacing_top;
+float FontVariation::get_variation_embolden() const {
+ return variation.embolden;
}
-real_t Font::get_underline_thickness(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_underline_thickness(rids[i], p_size));
+void FontVariation::set_variation_transform(Transform2D p_transform) {
+ if (variation.transform != p_transform) {
+ variation.transform = p_transform;
+ _invalidate_rids();
}
- return ret;
}
-Size2 Font::get_string_size(const String &p_text, int p_size, HorizontalAlignment p_alignment, float p_width, uint16_t p_flags) const {
- ERR_FAIL_COND_V(data.is_empty(), Size2());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_flags, hash);
- }
- hash = hash_djb2_one_64(p_size, hash);
-
- Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
- } else {
- buffer.instantiate();
- buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- cache.insert(hash, buffer);
- }
- return buffer->get_size();
+Transform2D FontVariation::get_variation_transform() const {
+ return variation.transform;
}
-Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p_size, uint16_t p_flags) const {
- ERR_FAIL_COND_V(data.is_empty(), Size2());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
+void FontVariation::set_variation_face_index(int p_face_index) {
+ if (variation.face_index != p_face_index) {
+ variation.face_index = p_face_index;
+ _invalidate_rids();
}
-
- uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- wrp_hash = hash_djb2_one_64(p_flags, wrp_hash);
- wrp_hash = hash_djb2_one_64(p_size, wrp_hash);
-
- Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(wrp_hash)) {
- lines_buffer = cache_wrap.get(wrp_hash);
- } else {
- lines_buffer.instantiate();
- lines_buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- lines_buffer->set_width(p_width);
- lines_buffer->set_flags(p_flags);
- cache_wrap.insert(wrp_hash, lines_buffer);
- }
-
- Size2 ret;
- for (int i = 0; i < lines_buffer->get_line_count(); i++) {
- Size2 line_size = lines_buffer->get_line_size(i);
- if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- ret.x = MAX(ret.x, line_size.x);
- ret.y += line_size.y;
- } else {
- ret.y = MAX(ret.y, line_size.y);
- ret.x += line_size.x;
- }
- }
- return ret;
}
-void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
- ERR_FAIL_COND(data.is_empty());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_flags, hash);
- }
- hash = hash_djb2_one_64(p_size, hash);
-
- Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
- } else {
- buffer.instantiate();
- buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- cache.insert(hash, buffer);
- }
-
- Vector2 ofs = p_pos;
- if (buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y -= buffer->get_line_ascent();
- } else {
- ofs.x -= buffer->get_line_ascent();
- }
-
- buffer->set_width(p_width);
- buffer->set_horizontal_alignment(p_alignment);
- buffer->set_flags(p_flags);
-
- if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) {
- buffer->draw_outline(p_canvas_item, ofs, p_outline_size, p_outline_modulate);
- }
- buffer->draw(p_canvas_item, ofs, p_modulate);
+int FontVariation::get_variation_face_index() const {
+ return variation.face_index;
}
-void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
- ERR_FAIL_COND(data.is_empty());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- wrp_hash = hash_djb2_one_64(p_flags, wrp_hash);
- wrp_hash = hash_djb2_one_64(p_size, wrp_hash);
-
- Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(wrp_hash)) {
- lines_buffer = cache_wrap.get(wrp_hash);
- } else {
- lines_buffer.instantiate();
- lines_buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- lines_buffer->set_width(p_width);
- lines_buffer->set_flags(p_flags);
- cache_wrap.insert(wrp_hash, lines_buffer);
- }
-
- lines_buffer->set_alignment(p_alignment);
-
- Vector2 lofs = p_pos;
- for (int i = 0; i < lines_buffer->get_line_count(); i++) {
- if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- if (i == 0) {
- lofs.y -= lines_buffer->get_line_ascent(0);
- }
- } else {
- if (i == 0) {
- lofs.x -= lines_buffer->get_line_ascent(0);
- }
- }
- if (p_width > 0) {
- lines_buffer->set_alignment(p_alignment);
- }
-
- if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) {
- lines_buffer->draw_line_outline(p_canvas_item, lofs, i, p_outline_size, p_outline_modulate);
- }
- lines_buffer->draw_line(p_canvas_item, lofs, i, p_modulate);
-
- Size2 line_size = lines_buffer->get_line_size(i);
- if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- lofs.y += line_size.y;
- } else {
- lofs.x += line_size.x;
- }
-
- if ((p_max_lines > 0) && (i >= p_max_lines)) {
- return;
- }
+void FontVariation::set_opentype_features(const Dictionary &p_features) {
+ if (opentype_features != p_features) {
+ opentype_features = p_features;
+ _invalidate_rids();
}
}
-Size2 Font::get_char_size(char32_t p_char, char32_t p_next, int p_size) const {
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- if (data[i]->has_char(p_char)) {
- int32_t glyph_a = TS->font_get_glyph_index(rids[i], p_size, p_char, 0);
- Size2 ret = Size2(TS->font_get_glyph_advance(rids[i], p_size, glyph_a).x, TS->font_get_ascent(rids[i], p_size) + TS->font_get_descent(rids[i], p_size));
- if ((p_next != 0) && data[i]->has_char(p_next)) {
- int32_t glyph_b = TS->font_get_glyph_index(rids[i], p_size, p_next, 0);
- ret.x -= TS->font_get_kerning(rids[i], p_size, Vector2i(glyph_a, glyph_b)).x;
- }
- return ret;
- }
- }
- return Size2();
+Dictionary FontVariation::get_opentype_features() const {
+ return opentype_features;
}
-real_t Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- if (data[i]->has_char(p_char)) {
- int32_t glyph_a = TS->font_get_glyph_index(rids[i], p_size, p_char, 0);
- real_t ret = TS->font_get_glyph_advance(rids[i], p_size, glyph_a).x;
- if ((p_next != 0) && data[i]->has_char(p_next)) {
- int32_t glyph_b = TS->font_get_glyph_index(rids[i], p_size, p_next, 0);
- ret -= TS->font_get_kerning(rids[i], p_size, Vector2i(glyph_a, glyph_b)).x;
- }
-
- if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) {
- TS->font_draw_glyph_outline(rids[i], p_canvas_item, p_size, p_outline_size, p_pos, glyph_a, p_outline_modulate);
- }
- TS->font_draw_glyph(rids[i], p_canvas_item, p_size, p_pos, glyph_a, p_modulate);
- return ret;
- }
+void FontVariation::set_spacing(TextServer::SpacingType p_spacing, int p_value) {
+ ERR_FAIL_INDEX((int)p_spacing, TextServer::SPACING_MAX);
+ if (extra_spacing[p_spacing] != p_value) {
+ extra_spacing[p_spacing] = p_value;
+ _invalidate_rids();
}
- return 0;
}
-bool Font::has_char(char32_t p_char) const {
- for (int i = 0; i < data.size(); i++) {
- if (data[i]->has_char(p_char)) {
- return true;
- }
- }
- return false;
+int FontVariation::get_spacing(TextServer::SpacingType p_spacing) const {
+ ERR_FAIL_INDEX_V((int)p_spacing, TextServer::SPACING_MAX, 0);
+ return extra_spacing[p_spacing];
}
-String Font::get_supported_chars() const {
- String chars;
- for (int i = 0; i < data.size(); i++) {
- String data_chars = data[i]->get_supported_chars();
- for (int j = 0; j < data_chars.length(); j++) {
- if (chars.find_char(data_chars[j]) == -1) {
- chars += data_chars[j];
- }
- }
+RID FontVariation::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform) const {
+ Ref<Font> f = _get_base_font_or_default();
+ if (f.is_valid()) {
+ return f->find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform);
}
- return chars;
+ return RID();
}
-Array Font::get_rids() const {
- Array _rids;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- if (rids[i].is_valid()) {
- _rids.push_back(rids[i]);
- }
+RID FontVariation::_get_rid() const {
+ Ref<Font> f = _get_base_font_or_default();
+ if (f.is_valid()) {
+ return f->find_variation(variation.opentype, variation.face_index, variation.embolden, variation.transform);
}
- return _rids;
-}
-
-void Font::update_changes() {
- emit_changed();
+ return RID();
}
-Font::Font() {
- cache.set_capacity(128);
- cache_wrap.set_capacity(32);
+FontVariation::FontVariation() {
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ extra_spacing[i] = 0;
+ }
}
-Font::~Font() {
- clear_data();
- cache.clear();
- cache_wrap.clear();
+FontVariation::~FontVariation() {
+ reset_state();
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 950959e054..40b223b0f5 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -37,16 +37,108 @@
#include "scene/resources/texture.h"
#include "servers/text_server.h"
+class TextLine;
+class TextParagraph;
+
+/*************************************************************************/
+/* Font */
+/*************************************************************************/
+
+class Font : public Resource {
+ GDCLASS(Font, Resource);
+
+ // Shaped string cache.
+ mutable LRUCache<uint64_t, Ref<TextLine>> cache;
+ mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
+
+protected:
+ // Output.
+ mutable TypedArray<RID> rids;
+ mutable bool dirty_rids = true;
+
+ // Fallbacks.
+ static constexpr int MAX_FALLBACK_DEPTH = 64;
+ TypedArray<Font> fallbacks;
+
+ static void _bind_methods();
+
+ virtual void _update_rids_fb(const Ref<Font> &p_f, int p_depth) const;
+ virtual void _update_rids() const;
+ virtual bool _is_cyclic(const Ref<Font> &p_f, int p_depth) const;
+
+ virtual void reset_state() override;
+
+public:
+ virtual void _invalidate_rids();
+
+ static constexpr int DEFAULT_FONT_SIZE = 16;
+
+ // Fallbacks.
+ virtual void set_fallbacks(const TypedArray<Font> &p_fallbacks);
+ virtual TypedArray<Font> get_fallbacks() const;
+
+ // Output.
+ virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const { return RID(); };
+ virtual RID _get_rid() const { return RID(); };
+ virtual TypedArray<RID> get_rids() const;
+
+ // Font metrics.
+ virtual real_t get_height(int p_font_size) const;
+ virtual real_t get_ascent(int p_font_size) const;
+ virtual real_t get_descent(int p_font_size) const;
+ virtual real_t get_underline_position(int p_font_size) const;
+ virtual real_t get_underline_thickness(int p_font_size) const;
+
+ virtual String get_font_name() const;
+ virtual String get_font_style_name() const;
+ virtual uint32_t get_font_style() const;
+
+ virtual int get_spacing(TextServer::SpacingType p_spacing) const { return 0; };
+ virtual Dictionary get_opentype_features() const;
+
+ // Drawing string.
+ virtual void set_cache_capacity(int p_single_line, int p_multi_line);
+
+ virtual Size2 get_string_size(const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+ virtual Size2 get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_max_lines = -1, uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+
+ virtual void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0), uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+ virtual void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_max_lines = -1, const Color &p_modulate = Color(1.0, 1.0, 1.0), uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+
+ virtual void draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0), uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+ virtual void draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_max_lines = -1, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0), uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+
+ // Drawing char.
+ virtual Size2 get_char_size(char32_t p_char, int p_font_size = DEFAULT_FONT_SIZE) const;
+ virtual real_t draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0)) const;
+ virtual real_t draw_char_outline(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size = DEFAULT_FONT_SIZE, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0)) const;
+
+ // Helper functions.
+ virtual bool has_char(char32_t p_char) const;
+ virtual String get_supported_chars() const;
+
+ virtual bool is_language_supported(const String &p_language) const;
+ virtual bool is_script_supported(const String &p_script) const;
+
+ virtual Dictionary get_supported_feature_list() const;
+ virtual Dictionary get_supported_variation_list() const;
+ virtual int64_t get_face_count() const;
+
+ Font();
+ ~Font();
+};
+
+/*************************************************************************/
+/* FontFile */
/*************************************************************************/
-class FontData : public Resource {
- GDCLASS(FontData, Resource);
+class FontFile : public Font {
+ GDCLASS(FontFile, Font);
RES_BASE_EXTENSION("fontdata");
// Font source data.
const uint8_t *data_ptr = nullptr;
size_t data_size = 0;
- int face_index = 0;
PackedByteArray data;
bool antialiased = true;
@@ -59,8 +151,11 @@ class FontData : public Resource {
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
real_t oversampling = 0.f;
- real_t embolden = 0.f;
- Transform2D transform;
+
+#ifndef DISABLE_DEPRECATED
+ real_t bmp_height = 0.0;
+ real_t bmp_ascent = 0.0;
+#endif
// Cache.
mutable Vector<RID> cache;
@@ -92,20 +187,10 @@ public:
virtual void set_data(const PackedByteArray &p_data);
virtual PackedByteArray get_data() const;
- virtual void set_face_index(int64_t p_index);
- virtual int64_t get_face_index() const;
-
- virtual int64_t get_face_count() const;
-
// Common properties.
virtual void set_font_name(const String &p_name);
- virtual String get_font_name() const;
-
virtual void set_font_style_name(const String &p_name);
- virtual String get_font_style_name() const;
-
virtual void set_font_style(uint32_t p_style);
- virtual uint32_t get_font_style() const;
virtual void set_antialiased(bool p_antialiased);
virtual bool is_antialiased() const;
@@ -134,17 +219,12 @@ public:
virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel);
virtual TextServer::SubpixelPositioning get_subpixel_positioning() const;
- virtual void set_embolden(float p_strength);
- virtual float get_embolden() const;
-
- virtual void set_transform(Transform2D p_transform);
- virtual Transform2D get_transform() const;
-
virtual void set_oversampling(real_t p_oversampling);
virtual real_t get_oversampling() const;
// Cache.
- virtual RID find_cache(const Dictionary &p_variation_coordinates) const;
+ virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const override;
+ virtual RID _get_rid() const override;
virtual int get_cache_count() const;
virtual void clear_cache();
@@ -157,23 +237,29 @@ public:
virtual void set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates);
virtual Dictionary get_variation_coordinates(int p_cache_index) const;
- virtual void set_ascent(int p_cache_index, int p_size, real_t p_ascent);
- virtual real_t get_ascent(int p_cache_index, int p_size) const;
+ virtual void set_embolden(int p_cache_index, float p_strength);
+ virtual float get_embolden(int p_cache_index) const;
+
+ virtual void set_transform(int p_cache_index, Transform2D p_transform);
+ virtual Transform2D get_transform(int p_cache_index) const;
+
+ virtual void set_face_index(int p_cache_index, int64_t p_index);
+ virtual int64_t get_face_index(int p_cache_index) const;
- virtual void set_descent(int p_cache_index, int p_size, real_t p_descent);
- virtual real_t get_descent(int p_cache_index, int p_size) const;
+ virtual void set_cache_ascent(int p_cache_index, int p_size, real_t p_ascent);
+ virtual real_t get_cache_ascent(int p_cache_index, int p_size) const;
- virtual void set_underline_position(int p_cache_index, int p_size, real_t p_underline_position);
- virtual real_t get_underline_position(int p_cache_index, int p_size) const;
+ virtual void set_cache_descent(int p_cache_index, int p_size, real_t p_descent);
+ virtual real_t get_cache_descent(int p_cache_index, int p_size) const;
- virtual void set_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness);
- virtual real_t get_underline_thickness(int p_cache_index, int p_size) const;
+ virtual void set_cache_underline_position(int p_cache_index, int p_size, real_t p_underline_position);
+ virtual real_t get_cache_underline_position(int p_cache_index, int p_size) const;
- virtual void set_scale(int p_cache_index, int p_size, real_t p_scale); // Rendering scale for bitmap fonts (e.g. emoji fonts).
- virtual real_t get_scale(int p_cache_index, int p_size) const;
+ virtual void set_cache_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness);
+ virtual real_t get_cache_underline_thickness(int p_cache_index, int p_size) const;
- virtual void set_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing, int p_value);
- virtual int get_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing) const;
+ virtual void set_cache_scale(int p_cache_index, int p_size, real_t p_scale); // Rendering scale for bitmap fonts (e.g. emoji fonts).
+ virtual real_t get_cache_scale(int p_cache_index, int p_size) const;
virtual int get_texture_count(int p_cache_index, const Vector2i &p_size) const;
virtual void clear_textures(int p_cache_index, const Vector2i &p_size);
@@ -214,16 +300,12 @@ public:
virtual void render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end);
virtual void render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index);
- virtual RID get_cache_rid(int p_cache_index) const;
-
// Language/script support override.
- virtual bool is_language_supported(const String &p_language) const;
virtual void set_language_support_override(const String &p_language, bool p_supported);
virtual bool get_language_support_override(const String &p_language) const;
virtual void remove_language_support_override(const String &p_language);
virtual Vector<String> get_language_support_overrides() const;
- virtual bool is_script_supported(const String &p_script) const;
virtual void set_script_support_override(const String &p_script, bool p_supported);
virtual bool get_script_support_override(const String &p_script) const;
virtual void remove_script_support_override(const String &p_script);
@@ -233,100 +315,70 @@ public:
virtual Dictionary get_opentype_feature_overrides() const;
// Base font properties.
- virtual bool has_char(char32_t p_char) const;
- virtual String get_supported_chars() const;
-
virtual int32_t get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector = 0x0000) const;
- virtual Dictionary get_supported_feature_list() const;
- virtual Dictionary get_supported_variation_list() const;
-
- FontData();
- ~FontData();
+ FontFile();
+ ~FontFile();
};
/*************************************************************************/
+/* FontVariation */
+/*************************************************************************/
-class TextLine;
-class TextParagraph;
+class FontVariation : public Font {
+ GDCLASS(FontVariation, Font);
-class Font : public Resource {
- GDCLASS(Font, Resource);
+ struct Variation {
+ Dictionary opentype;
+ real_t embolden = 0.f;
+ int face_index = 0;
+ Transform2D transform;
+ };
- // Shaped string cache.
- mutable LRUCache<uint64_t, Ref<TextLine>> cache;
- mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
-
- // Font data cache.
- Vector<Ref<FontData>> data;
- mutable Vector<RID> rids;
+ mutable Ref<Font> theme_font;
- // Font config.
- Dictionary variation_coordinates;
- int spacing_bottom = 0;
- int spacing_top = 0;
+ Ref<Font> base_font;
- _FORCE_INLINE_ void _data_changed();
- _FORCE_INLINE_ void _ensure_rid(int p_index) const; // Find or create cache record.
+ Variation variation;
+ Dictionary opentype_features;
+ int extra_spacing[TextServer::SPACING_MAX];
protected:
static void _bind_methods();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void _update_rids() const override;
virtual void reset_state() override;
public:
- static const int DEFAULT_FONT_SIZE = 16;
-
- Dictionary get_feature_list() const;
+ virtual void set_base_font(const Ref<Font> &p_font);
+ virtual Ref<Font> get_base_font() const;
+ virtual Ref<Font> _get_base_font_or_default() const;
- // Font data.
- virtual void add_data(const Ref<FontData> &p_data);
- virtual void set_data(int p_idx, const Ref<FontData> &p_data);
- virtual int get_data_count() const;
- virtual Ref<FontData> get_data(int p_idx) const;
- virtual RID get_data_rid(int p_idx) const;
- virtual void clear_data();
- virtual void remove_data(int p_idx);
+ virtual void set_variation_opentype(const Dictionary &p_coords);
+ virtual Dictionary get_variation_opentype() const;
- // Font configuration.
- virtual void set_variation_coordinates(const Dictionary &p_variation_coordinates);
- virtual Dictionary get_variation_coordinates() const;
+ virtual void set_variation_embolden(float p_strength);
+ virtual float get_variation_embolden() const;
- virtual void set_spacing(TextServer::SpacingType p_spacing, int p_value);
- virtual int get_spacing(TextServer::SpacingType p_spacing) const;
-
- // Font metrics.
- virtual real_t get_height(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_ascent(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_descent(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_underline_position(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_underline_thickness(int p_size = DEFAULT_FONT_SIZE) const;
+ virtual void set_variation_transform(Transform2D p_transform);
+ virtual Transform2D get_variation_transform() const;
- // Drawing string.
- virtual Size2 get_string_size(const String &p_text, int p_size = DEFAULT_FONT_SIZE, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- virtual Size2 get_multiline_string_size(const String &p_text, float p_width = -1, int p_size = DEFAULT_FONT_SIZE, uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND) const;
+ virtual void set_variation_face_index(int p_face_index);
+ virtual int get_variation_face_index() const;
- virtual void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- virtual void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ virtual void set_opentype_features(const Dictionary &p_features);
+ virtual Dictionary get_opentype_features() const override;
- // Helper functions.
- virtual bool has_char(char32_t p_char) const;
- virtual String get_supported_chars() const;
-
- // Drawing char.
- virtual Size2 get_char_size(char32_t p_char, char32_t p_next = 0, int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, int p_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
-
- Array get_rids() const;
+ virtual void set_spacing(TextServer::SpacingType p_spacing, int p_value);
+ virtual int get_spacing(TextServer::SpacingType p_spacing) const override;
- void update_changes();
+ // Output.
+ virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const override;
+ virtual RID _get_rid() const override;
- Font();
- ~Font();
+ FontVariation();
+ ~FontVariation();
};
#endif /* FONT_H */
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index a3d3449099..2b04ead0af 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -92,10 +92,6 @@ public:
void set_interpolation_mode(InterpolationMode p_interp_mode);
InterpolationMode get_interpolation_mode();
- _FORCE_INLINE_ float cubic_interpolate(float p0, float p1, float p2, float p3, float x) {
- return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
- }
-
_FORCE_INLINE_ Color get_color_at_offset(float p_offset) {
if (points.is_empty()) {
return Color(0, 0, 0, 1);
@@ -161,10 +157,10 @@ public:
const Point &pointP3 = points[p3];
float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset);
- float r = cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
- float g = cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
- float b = cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
- float a = cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
+ float r = Math::cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
+ float g = Math::cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
+ float b = Math::cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
+ float a = Math::cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
return Color(r, g, b, a);
} break;
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 0fbd29b1a6..293fdd6f05 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -331,6 +331,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
bool is_uvs_close = (!uvs_ptr || uvs_ptr[j].distance_squared_to(uvs_ptr[idx.second]) < CMP_EPSILON2);
bool is_uv2s_close = (!uv2s_ptr || uv2s_ptr[j].distance_squared_to(uv2s_ptr[idx.second]) < CMP_EPSILON2);
+ ERR_FAIL_INDEX(idx.second, normals.size());
bool is_normals_close = normals[idx.second].dot(n) > normal_merge_threshold;
if (is_uvs_close && is_uv2s_close && is_normals_close) {
vertex_remap.push_back(idx.first);
@@ -1046,6 +1047,10 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
+ if (!rnormals.size()) {
+ continue;
+ }
+
int vertex_ofs = vertices.size() / 3;
vertices.resize((vertex_ofs + vc) * 3);
@@ -1086,6 +1091,9 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
} else {
for (int j = 0; j < ic / 3; j++) {
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 0], rvertices.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 1], rvertices.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 2], rvertices.size(), ERR_INVALID_DATA);
Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
@@ -1185,7 +1193,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
surfaces_tools[i]->index();
Array arrays = surfaces_tools[i]->commit_to_arrays();
- add_surface(surfaces_tools[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
+ add_surface(surfaces_tools[i]->get_primitive_type(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
}
set_lightmap_size_hint(Size2(size_x, size_y));
@@ -1238,6 +1246,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
+ ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle"), &ImporterMesh::generate_lods);
ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index fb50b2d779..b7a3b677f5 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -472,24 +472,33 @@ void BaseMaterial3D::_update_shader() {
}
String texfilter_str;
+ // Force linear filtering for the heightmap texture, as the heightmap effect
+ // looks broken with nearest-neighbor filtering (with and without Deep Parallax).
+ String texfilter_height_str;
switch (texture_filter) {
case TEXTURE_FILTER_NEAREST:
texfilter_str = "filter_nearest";
+ texfilter_height_str = "filter_linear";
break;
case TEXTURE_FILTER_LINEAR:
texfilter_str = "filter_linear";
+ texfilter_height_str = "filter_linear";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
texfilter_str = "filter_nearest_mipmap";
+ texfilter_height_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
texfilter_str = "filter_linear_mipmap";
+ texfilter_height_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC:
texfilter_str = "filter_nearest_mipmap_anisotropic";
+ texfilter_height_str = "filter_linear_mipmap_anisotropic";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC:
texfilter_str = "filter_linear_mipmap_anisotropic";
+ texfilter_height_str = "filter_linear_mipmap_anisotropic";
break;
case TEXTURE_FILTER_MAX:
break; // Internal value, skip.
@@ -497,8 +506,10 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_USE_TEXTURE_REPEAT]) {
texfilter_str += ",repeat_enable";
+ texfilter_height_str += ",repeat_enable";
} else {
texfilter_str += ",repeat_disable";
+ texfilter_height_str += ",repeat_disable";
}
//must create a shader!
@@ -763,7 +774,7 @@ void BaseMaterial3D::_update_shader() {
}
if (features[FEATURE_HEIGHT_MAPPING]) {
- code += "uniform sampler2D texture_heightmap : hint_default_black," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_heightmap : hint_default_black," + texfilter_height_str + ";\n";
code += "uniform float heightmap_scale;\n";
code += "uniform int heightmap_min_layers;\n";
code += "uniform int heightmap_max_layers;\n";
@@ -2198,7 +2209,7 @@ Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transpar
if (p_fixed_size) {
hash |= 1 << 9;
}
- hash = hash_djb2_one_64(p_filter, hash);
+ hash = hash_murmur3_one_64(p_filter, hash);
if (materials_for_2d.has(hash)) {
if (r_shader_rid) {
@@ -2655,14 +2666,14 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_DETAIL_NORMAL);
ADD_GROUP("UV1", "uv1_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale"), "set_uv1_scale", "get_uv1_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale", PROPERTY_HINT_LINK), "set_uv1_scale", "get_uv1_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_offset"), "set_uv1_offset", "get_uv1_offset");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_TRIPLANAR);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv1_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv1_triplanar_blend_sharpness", "get_uv1_triplanar_blend_sharpness");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_world_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_WORLD_TRIPLANAR);
ADD_GROUP("UV2", "uv2_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale"), "set_uv2_scale", "get_uv2_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale", PROPERTY_HINT_LINK), "set_uv2_scale", "get_uv2_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_offset"), "set_uv2_offset", "get_uv2_offset");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_TRIPLANAR);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv2_triplanar_blend_sharpness", "get_uv2_triplanar_blend_sharpness");
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index b8c83ac89e..3e7b0a2808 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -188,7 +188,10 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
Vector<Vector3> faces;
faces.resize(faces_size);
+ Vector<int32_t> surface_indices;
+ surface_indices.resize(faces_size / 3);
Vector3 *facesw = faces.ptrw();
+ int32_t *surface_indicesw = surface_indices.ptrw();
int widx = 0;
@@ -210,6 +213,8 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
Vector<Vector3> vertices = a[ARRAY_VERTEX];
const Vector3 *vr = vertices.ptr();
+ int32_t from_index = widx / 3;
+
if (surface_get_format(i) & ARRAY_FORMAT_INDEX) {
int ic = surface_get_array_index_len(i);
Vector<int> indices = a[ARRAY_INDEX];
@@ -241,6 +246,12 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
}
}
}
+
+ int32_t to_index = widx / 3;
+
+ for (int j = from_index; j < to_index; j++) {
+ surface_indicesw[j] = i;
+ }
}
triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 784ecc3a4d..a808ead66b 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -272,6 +272,24 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
return filter_walkable_low_height_spans;
}
+void NavigationMesh::set_filter_baking_aabb(const AABB &p_aabb) {
+ filter_baking_aabb = p_aabb;
+ notify_property_list_changed();
+}
+
+AABB NavigationMesh::get_filter_baking_aabb() const {
+ return filter_baking_aabb;
+}
+
+void NavigationMesh::set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset) {
+ filter_baking_aabb_offset = p_aabb_offset;
+ notify_property_list_changed();
+}
+
+Vector3 NavigationMesh::get_filter_baking_aabb_offset() const {
+ return filter_baking_aabb_offset;
+}
+
void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) {
vertices = p_vertices;
notify_property_list_changed();
@@ -469,6 +487,10 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_filter_walkable_low_height_spans", "filter_walkable_low_height_spans"), &NavigationMesh::set_filter_walkable_low_height_spans);
ClassDB::bind_method(D_METHOD("get_filter_walkable_low_height_spans"), &NavigationMesh::get_filter_walkable_low_height_spans);
+ ClassDB::bind_method(D_METHOD("set_filter_baking_aabb", "baking_aabb"), &NavigationMesh::set_filter_baking_aabb);
+ ClassDB::bind_method(D_METHOD("get_filter_baking_aabb"), &NavigationMesh::get_filter_baking_aabb);
+ ClassDB::bind_method(D_METHOD("set_filter_baking_aabb_offset", "baking_aabb_offset"), &NavigationMesh::set_filter_baking_aabb_offset);
+ ClassDB::bind_method(D_METHOD("get_filter_baking_aabb_offset"), &NavigationMesh::get_filter_baking_aabb_offset);
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMesh::set_vertices);
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMesh::get_vertices);
@@ -516,6 +538,8 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "filter_baking_aabb"), "set_filter_baking_aabb", "get_filter_baking_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "filter_baking_aabb_offset"), "set_filter_baking_aabb_offset", "get_filter_baking_aabb_offset");
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED);
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE);
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 93c1c11876..40b275c792 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -117,6 +117,8 @@ protected:
bool filter_low_hanging_obstacles = false;
bool filter_ledge_spans = false;
bool filter_walkable_low_height_spans = false;
+ AABB filter_baking_aabb;
+ Vector3 filter_baking_aabb_offset;
public:
// Recast settings
@@ -186,6 +188,12 @@ public:
void set_filter_walkable_low_height_spans(bool p_value);
bool get_filter_walkable_low_height_spans() const;
+ void set_filter_baking_aabb(const AABB &p_aabb);
+ AABB get_filter_baking_aabb() const;
+
+ void set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset);
+ Vector3 get_filter_baking_aabb_offset() const;
+
void create_from_mesh(const Ref<Mesh> &p_mesh);
void set_vertices(const Vector<Vector3> &p_vertices);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index b90f396110..2c58aa83a9 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -35,6 +35,7 @@
#include "core/core_string_names.h"
#include "core/io/missing_resource.h"
#include "core/io/resource_loader.h"
+#include "core/templates/local_vector.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/node_3d.h"
#include "scene/gui/control.h"
@@ -43,7 +44,7 @@
#include "scene/property_utils.h"
#define PACKED_SCENE_VERSION 2
-
+#define META_POINTER_PROPERTY_BASE "metadata/_editor_prop_ptr_"
bool SceneState::can_instantiate() const {
return nodes.size() > 0;
}
@@ -108,6 +109,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
+ LocalVector<DeferredNodePathProperties> deferred_node_paths;
+
for (int i = 0; i < nc; i++) {
const NodeData &n = nd[i];
@@ -230,9 +233,28 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
for (int j = 0; j < nprop_count; j++) {
bool valid;
- ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+
ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
+ if (nprops[j].name & FLAG_PATH_PROPERTY_IS_NODE) {
+ uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1);
+ ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // If editor, just set the metadata and be it
+ node->set(META_POINTER_PROPERTY_BASE + String(snames[name_idx]), props[nprops[j].value]);
+ } else {
+ // Do an actual deferred sed of the property path.
+ DeferredNodePathProperties dnp;
+ dnp.path = props[nprops[j].value];
+ dnp.base = node;
+ dnp.property = snames[name_idx];
+ deferred_node_paths.push_back(dnp);
+ }
+ continue;
+ }
+
+ ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+
if (snames[nprops[j].name] == CoreStringNames::get_singleton()->_script) {
//work around to avoid old script variables from disappearing, should be the proper fix to:
//https://github.com/godotengine/godot/issues/2958
@@ -369,6 +391,12 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
}
+ for (uint32_t i = 0; i < deferred_node_paths.size(); i++) {
+ const DeferredNodePathProperties &dnp = deferred_node_paths[i];
+ Node *other = dnp.base->get_node_or_null(dnp.path);
+ dnp.base->set(dnp.property, other);
+ }
+
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
E.value->setup_local_to_scene();
}
@@ -532,6 +560,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
if (E.name == META_PROPERTY_MISSING_RESOURCES) {
continue; // Ignore this property when packing.
}
+ if (E.name.begins_with(META_POINTER_PROPERTY_BASE)) {
+ continue; // do not save.
+ }
// If instance or inheriting, not saving if property requested so.
if (!states_stack.is_empty()) {
@@ -542,8 +573,15 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
StringName name = E.name;
Variant value = p_node->get(name);
+ bool use_deferred_node_path_bit = false;
- if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
+ if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) {
+ value = p_node->get(META_POINTER_PROPERTY_BASE + E.name);
+ if (value.get_type() != Variant::NODE_PATH) {
+ continue; //was never set, ignore.
+ }
+ use_deferred_node_path_bit = true;
+ } else if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
// Was this missing resource overridden? If so do not save the old value.
Ref<Resource> ures = value;
if (ures.is_null()) {
@@ -562,6 +600,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
NodeData::Property prop;
prop.name = _nm_get_string(name, name_map);
prop.value = _vm_get_variant(value, variant_map);
+ if (use_deferred_node_path_bit) {
+ prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
+ }
nd.properties.push_back(prop);
}
@@ -1018,7 +1059,7 @@ Variant SceneState::get_property_value(int p_node, const StringName &p_property,
const NodeData::Property *p = nodes[p_node].properties.ptr();
for (int i = 0; i < pc; i++) {
- if (p_property == namep[p[i].name]) {
+ if (p_property == namep[p[i].name & FLAG_PROP_NAME_MASK]) {
found = true;
return variants[p[i].value];
}
@@ -1409,7 +1450,19 @@ int SceneState::get_node_property_count(int p_idx) const {
StringName SceneState::get_node_property_name(int p_idx, int p_prop) const {
ERR_FAIL_INDEX_V(p_idx, nodes.size(), StringName());
ERR_FAIL_INDEX_V(p_prop, nodes[p_idx].properties.size(), StringName());
- return names[nodes[p_idx].properties[p_prop].name];
+ return names[nodes[p_idx].properties[p_prop].name & FLAG_PROP_NAME_MASK];
+}
+
+Vector<String> SceneState::get_node_deferred_nodepath_properties(int p_idx) const {
+ Vector<String> ret;
+ ERR_FAIL_INDEX_V(p_idx, nodes.size(), ret);
+ for (int i = 0; i < nodes[p_idx].properties.size(); i++) {
+ uint32_t idx = nodes[p_idx].properties[i].name;
+ if (idx & FLAG_PATH_PROPERTY_IS_NODE) {
+ ret.push_back(names[idx & FLAG_PROP_NAME_MASK]);
+ }
+ }
+ return ret;
}
Variant SceneState::get_node_property_value(int p_idx, int p_prop) const {
@@ -1555,13 +1608,16 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
return nodes.size() - 1;
}
-void SceneState::add_node_property(int p_node, int p_name, int p_value) {
+void SceneState::add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path) {
ERR_FAIL_INDEX(p_node, nodes.size());
ERR_FAIL_INDEX(p_name, names.size());
ERR_FAIL_INDEX(p_value, variants.size());
NodeData::Property prop;
prop.name = p_name;
+ if (p_deferred_node_path) {
+ prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
+ }
prop.value = p_value;
nodes.write[p_node].properties.push_back(prop);
}
@@ -1599,6 +1655,10 @@ void SceneState::add_editable_instance(const NodePath &p_path) {
editable_instances.push_back(p_path);
}
+String SceneState::get_meta_pointer_property(const String &p_property) {
+ return META_POINTER_PROPERTY_BASE + p_property;
+}
+
Vector<String> SceneState::_get_node_groups(int p_idx) const {
Vector<StringName> groups = get_node_groups(p_idx);
Vector<String> ret;
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 05abb23284..5f8001c871 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -69,6 +69,12 @@ class SceneState : public RefCounted {
Vector<int> groups;
};
+ struct DeferredNodePathProperties {
+ Node *base = nullptr;
+ StringName property;
+ NodePath path;
+ };
+
Vector<NodeData> nodes;
struct ConnectionData {
@@ -104,6 +110,8 @@ public:
FLAG_ID_IS_PATH = (1 << 30),
TYPE_INSTANCED = 0x7FFFFFFF,
FLAG_INSTANCE_IS_PLACEHOLDER = (1 << 30),
+ FLAG_PATH_PROPERTY_IS_NODE = (1 << 30),
+ FLAG_PROP_NAME_MASK = FLAG_PATH_PROPERTY_IS_NODE - 1,
FLAG_MASK = (1 << 24) - 1,
};
@@ -157,6 +165,7 @@ public:
int get_node_property_count(int p_idx) const;
StringName get_node_property_name(int p_idx, int p_prop) const;
Variant get_node_property_value(int p_idx, int p_prop) const;
+ Vector<String> get_node_deferred_nodepath_properties(int p_idx) const;
int get_connection_count() const;
NodePath get_connection_source(int p_idx) const;
@@ -177,7 +186,7 @@ public:
int add_value(const Variant &p_value);
int add_node_path(const NodePath &p_path);
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
- void add_node_property(int p_node, int p_name, int p_value);
+ void add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path = false);
void add_node_group(int p_node, int p_group);
void set_base_scene(int p_idx);
void add_connection(int p_from, int p_to, int p_signal, int p_method, int p_flags, int p_unbinds, const Vector<int> &p_binds);
@@ -186,6 +195,9 @@ public:
virtual void set_last_modified_time(uint64_t p_time) { last_modified_time = p_time; }
uint64_t get_last_modified_time() const { return last_modified_time; }
+ // Used when saving pointers (saves a path property instead).
+ static String get_meta_pointer_property(const String &p_property);
+
SceneState();
};
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index c4b15df6bb..7a49b9b515 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -488,6 +488,12 @@ void ParticlesMaterial::_update_shader() {
code += " float degree_to_rad = pi / 180.0;\n";
code += "\n";
+ if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
+ code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
+ code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
+ code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
+ }
+
code += " CUSTOM.y += DELTA / LIFETIME;\n";
code += " float tv = CUSTOM.y / CUSTOM.w;\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 24341d964d..af45593f38 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -110,7 +110,7 @@ private:
uint32_t key = 0;
static uint32_t hash(const MaterialKey &p_key) {
- return hash_djb2_one_32(p_key.key);
+ return hash_murmur3_one_32(p_key.key);
}
bool operator==(const MaterialKey &p_key) const {
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index f8fb51ae42..68441afb1c 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -439,12 +439,15 @@ void CapsuleMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+
+ ADD_LINKED_PROPERTY("radius", "height");
+ ADD_LINKED_PROPERTY("height", "radius");
}
void CapsuleMesh::set_radius(const float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
- radius = height * 0.5;
+ height = radius * 2.0;
}
_request_update();
}
@@ -456,7 +459,7 @@ float CapsuleMesh::get_radius() const {
void CapsuleMesh::set_height(const float p_height) {
height = p_height;
if (radius > height * 0.5) {
- height = radius * 2;
+ radius = height * 0.5;
}
_request_update();
}
@@ -2187,12 +2190,12 @@ RibbonTrailMesh::RibbonTrailMesh() {
/* TextMesh */
/*************************************************************************/
-void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) const {
- if (cache.has(p_hash)) {
+void TextMesh::_generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_gl) const {
+ if (cache.has(p_key)) {
return;
}
- GlyphMeshData &gl_data = cache[p_hash];
+ GlyphMeshData &gl_data = cache[p_key];
Dictionary d = TS->font_get_glyph_contours(p_gl.font_rid, p_gl.font_size, p_gl.index);
Vector2 origin = Vector2(p_gl.x_off, p_gl.y_off) * pixel_size;
@@ -2373,7 +2376,10 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
TS->shaped_text_set_direction(text_rid, text_direction);
String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
- TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, language);
+ TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, font->get_opentype_features(), language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
+ }
Array stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
@@ -2391,7 +2397,10 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
} else if (dirty_font) {
int spans = TS->shaped_get_span_count(text_rid);
for (int i = 0; i < spans; i++) {
- TS->shaped_set_span_update_font(text_rid, i, font->get_rids(), font_size, opentype_features);
+ TS->shaped_set_span_update_font(text_rid, i, font->get_rids(), font_size, font->get_opentype_features());
+ }
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
dirty_font = false;
@@ -2434,11 +2443,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
continue;
}
if (glyphs[i].font_rid != RID()) {
- uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
- hash = hash_djb2_one_32(glyphs[i].index, hash);
-
- _generate_glyph_mesh_data(hash, glyphs[i]);
- GlyphMeshData &gl_data = cache[hash];
+ GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
+ _generate_glyph_mesh_data(key, glyphs[i]);
+ GlyphMeshData &gl_data = cache[key];
p_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
i_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
@@ -2493,10 +2500,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
continue;
}
if (glyphs[i].font_rid != RID()) {
- uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
- hash = hash_djb2_one_32(glyphs[i].index, hash);
-
- const GlyphMeshData &gl_data = cache[hash];
+ GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
+ _generate_glyph_mesh_data(key, glyphs[i]);
+ const GlyphMeshData &gl_data = cache[key];
int64_t ts = gl_data.triangles.size();
const Vector2 *ts_ptr = gl_data.triangles.ptr();
@@ -2679,10 +2685,6 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &TextMesh::set_text_direction);
ClassDB::bind_method(D_METHOD("get_text_direction"), &TextMesh::get_text_direction);
- ClassDB::bind_method(D_METHOD("set_opentype_feature", "tag", "value"), &TextMesh::set_opentype_feature);
- ClassDB::bind_method(D_METHOD("get_opentype_feature", "tag"), &TextMesh::get_opentype_feature);
- ClassDB::bind_method(D_METHOD("clear_opentype_features"), &TextMesh::clear_opentype_features);
-
ClassDB::bind_method(D_METHOD("set_language", "language"), &TextMesh::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &TextMesh::get_language);
@@ -2701,11 +2703,9 @@ void TextMesh::_bind_methods() {
ADD_GROUP("Text", "");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,127,1,suffix:px"), "set_font_size", "get_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
ADD_GROUP("Mesh", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001,suffix:m"), "set_pixel_size", "get_pixel_size");
@@ -2713,9 +2713,11 @@ void TextMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.0,100.0,0.001,or_greater,suffix:m"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:m"), "set_width", "get_width");
- ADD_GROUP("Locale", "");
+ ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
}
void TextMesh::_notification(int p_what) {
@@ -2732,56 +2734,6 @@ void TextMesh::_notification(int p_what) {
}
}
-bool TextMesh::_set(const StringName &p_name, const Variant &p_value) {
- String str = p_name;
- if (str.begins_with("opentype_features/")) {
- String name = str.get_slicec('/', 1);
- int32_t tag = TS->name_to_tag(name);
- int value = p_value;
- if (value == -1) {
- if (opentype_features.has(tag)) {
- opentype_features.erase(tag);
- dirty_font = true;
- _request_update();
- }
- } else {
- if (!opentype_features.has(tag) || (int)opentype_features[tag] != value) {
- opentype_features[tag] = value;
- dirty_font = true;
- _request_update();
- }
- }
- notify_property_list_changed();
- return true;
- }
-
- return false;
-}
-
-bool TextMesh::_get(const StringName &p_name, Variant &r_ret) const {
- String str = p_name;
- if (str.begins_with("opentype_features/")) {
- String name = str.get_slicec('/', 1);
- int32_t tag = TS->name_to_tag(name);
- if (opentype_features.has(tag)) {
- r_ret = opentype_features[tag];
- return true;
- } else {
- r_ret = -1;
- return true;
- }
- }
- return false;
-}
-
-void TextMesh::_get_property_list(List<PropertyInfo> *p_list) const {
- for (const Variant *ftr = opentype_features.next(nullptr); ftr != nullptr; ftr = opentype_features.next(ftr)) {
- String name = TS->tag_to_name(*ftr);
- p_list->push_back(PropertyInfo(Variant::INT, "opentype_features/" + name));
- }
- p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
-}
-
TextMesh::TextMesh() {
primitive_type = PRIMITIVE_TRIANGLES;
text_rid = TS->create_shaped_text();
@@ -2845,7 +2797,7 @@ Ref<Font> TextMesh::get_font() const {
}
Ref<Font> TextMesh::_get_font_or_default() const {
- if (font_override.is_valid() && font_override->get_data_count() > 0) {
+ if (font_override.is_valid()) {
return font_override;
}
@@ -2952,29 +2904,6 @@ TextServer::Direction TextMesh::get_text_direction() const {
return text_direction;
}
-void TextMesh::clear_opentype_features() {
- opentype_features.clear();
- dirty_font = true;
- _request_update();
-}
-
-void TextMesh::set_opentype_feature(const String &p_name, int p_value) {
- int32_t tag = TS->name_to_tag(p_name);
- if (!opentype_features.has(tag) || (int)opentype_features[tag] != p_value) {
- opentype_features[tag] = p_value;
- dirty_font = true;
- _request_update();
- }
-}
-
-int TextMesh::get_opentype_feature(const String &p_name) const {
- int32_t tag = TS->name_to_tag(p_name);
- if (!opentype_features.has(tag)) {
- return -1;
- }
- return opentype_features[tag];
-}
-
void TextMesh::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 38cc7db5fe..cb93211756 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -475,6 +475,7 @@ private:
sharp = p_sharp;
};
};
+
struct ContourInfo {
real_t length = 0.0;
bool ccw = true;
@@ -484,6 +485,27 @@ private:
ccw = p_ccw;
}
};
+
+ struct GlyphMeshKey {
+ uint64_t font_id;
+ uint32_t gl_id;
+
+ bool operator==(const GlyphMeshKey &p_b) const {
+ return (font_id == p_b.font_id) && (gl_id == p_b.gl_id);
+ }
+
+ GlyphMeshKey(uint64_t p_font_id, uint32_t p_gl_id) {
+ font_id = p_font_id;
+ gl_id = p_gl_id;
+ }
+ };
+
+ struct GlyphMeshKeyHasher {
+ _FORCE_INLINE_ static uint32_t hash(const GlyphMeshKey &p_a) {
+ return hash_murmur3_buffer(&p_a, sizeof(GlyphMeshKey));
+ }
+ };
+
struct GlyphMeshData {
Vector<Vector2> triangles;
Vector<Vector<ContourPoint>> contours;
@@ -491,7 +513,7 @@ private:
Vector2 min_p = Vector2(INFINITY, INFINITY);
Vector2 max_p = Vector2(-INFINITY, -INFINITY);
};
- mutable HashMap<uint32_t, GlyphMeshData> cache;
+ mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache;
RID text_rid;
String text;
@@ -503,7 +525,6 @@ private:
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
bool uppercase = false;
- Dictionary opentype_features;
String language;
TextServer::Direction text_direction = TextServer::DIRECTION_AUTO;
TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
@@ -517,7 +538,7 @@ private:
mutable bool dirty_font = true;
mutable bool dirty_cache = true;
- void _generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_glyph) const;
+ void _generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_glyph) const;
void _font_changed();
protected:
@@ -526,10 +547,6 @@ protected:
virtual void _create_mesh_array(Array &p_arr) const override;
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
public:
GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
@@ -552,10 +569,6 @@ public:
void set_text_direction(TextServer::Direction p_text_direction);
TextServer::Direction get_text_direction() const;
- void set_opentype_feature(const String &p_name, int p_value);
- int get_opentype_feature(const String &p_name) const;
- void clear_opentype_features();
-
void set_language(const String &p_language);
String get_language() const;
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 9d586c6f03..66afb001fb 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -40,6 +40,8 @@
// Version 3: new string ID for ext/subresources, breaks forward compat.
#define FORMAT_VERSION 3
+#define BINARY_FORMAT_VERSION 4
+
#include "core/io/dir_access.h"
#include "core/version.h"
@@ -66,12 +68,8 @@ Error ResourceLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, Varia
String unique_id = token.value;
if (!p_data->resource_map.has(unique_id)) {
- Ref<DummyResource> dr;
- dr.instantiate();
- dr->set_scene_unique_id(unique_id);
- p_data->resource_map[unique_id] = dr;
- uint32_t im_size = p_data->resource_index_map.size();
- p_data->resource_index_map.insert(dr, im_size);
+ r_err_str = "Found unique_id reference before mapping, sub-resources stored out of order in resource file";
+ return ERR_PARSE_ERROR;
}
r_res = p_data->resource_map[unique_id];
@@ -214,6 +212,15 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated
}
+ HashSet<StringName> path_properties;
+
+ if (next_tag.fields.has("node_paths")) {
+ Vector<String> paths = next_tag.fields["node_paths"];
+ for (int i = 0; i < paths.size(); i++) {
+ path_properties.insert(paths[i]);
+ }
+ }
+
if (next_tag.fields.has("instance")) {
instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
@@ -278,9 +285,10 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
}
if (!assign.is_empty()) {
- int nameidx = packed_scene->get_state()->add_name(assign);
+ StringName assign_name = assign;
+ int nameidx = packed_scene->get_state()->add_name(assign_name);
int valueidx = packed_scene->get_state()->add_value(value);
- packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx);
+ packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx, path_properties.has(assign_name));
//it's assignment
} else if (!next_tag.name.is_empty()) {
break;
@@ -528,9 +536,9 @@ Error ResourceLoaderText::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//reuse existing
- Resource *r = ResourceCache::get(path);
- if (r && r->get_class() == type) {
- res = Ref<Resource>(r);
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache.is_valid() && cache->get_class() == type) {
+ res = cache;
res->reset_state();
do_assign = true;
}
@@ -539,10 +547,10 @@ Error ResourceLoaderText::load() {
MissingResource *missing_resource = nullptr;
if (res.is_null()) { //not reuse
- if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist
//cached, do not assign
- Resource *r = ResourceCache::get(path);
- res = Ref<Resource>(r);
+ res = cache;
} else {
//create
@@ -652,12 +660,10 @@ Error ResourceLoaderText::load() {
return error;
}
- if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) {
- Resource *r = ResourceCache::get(local_path);
- if (r->get_class() == res_type) {
- r->reset_state();
- resource = Ref<Resource>(r);
- }
+ Ref<Resource> cache = ResourceCache::get_ref(local_path);
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) {
+ cache->reset_state();
+ resource = cache;
}
MissingResource *missing_resource = nullptr;
@@ -1078,7 +1084,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
wf->store_32(0); //64 bits file, false for now
wf->store_32(VERSION_MAJOR);
wf->store_32(VERSION_MINOR);
- static const int save_format_version = 3; //use format version 3 for saving
+ static const int save_format_version = BINARY_FORMAT_VERSION;
wf->store_32(save_format_version);
bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type);
@@ -1176,7 +1182,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
String type;
- int id = -1;
+ String id;
bool main_res;
if (next_tag.name == "sub_resource") {
@@ -1197,15 +1203,26 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
type = next_tag.fields["type"];
id = next_tag.fields["id"];
main_res = false;
+
+ if (!dummy_read.resource_map.has(id)) {
+ Ref<DummyResource> dr;
+ dr.instantiate();
+ dr->set_scene_unique_id(id);
+ dummy_read.resource_map[id] = dr;
+ uint32_t im_size = dummy_read.resource_index_map.size();
+ dummy_read.resource_index_map.insert(dr, im_size);
+ }
+
} else {
type = res_type;
- id = 0; //used for last anyway
+ String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid);
+ id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0");
main_res = true;
}
local_offsets.push_back(wf2->get_position());
- bs_save_unicode_string(wf, "local://" + itos(id));
+ bs_save_unicode_string(wf, "local://" + id);
local_pointers_pos.push_back(wf->get_position());
wf->store_64(0); //temp local offset
@@ -1274,7 +1291,8 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
List<PropertyInfo> props;
packed_scene->get_property_list(&props);
- bs_save_unicode_string(wf, "local://0");
+ String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0");
+ bs_save_unicode_string(wf, "local://" + id);
local_pointers_pos.push_back(wf->get_position());
wf->store_64(0); //temp local offset
@@ -1564,17 +1582,17 @@ String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Res
String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) {
if (external_resources.has(res)) {
- return "ExtResource( \"" + external_resources[res] + "\" )";
+ return "ExtResource(\"" + external_resources[res] + "\")";
} else {
if (internal_resources.has(res)) {
- return "SubResource( \"" + internal_resources[res] + "\" )";
+ return "SubResource(\"" + internal_resources[res] + "\")";
} else if (!res->is_built_in()) {
if (res->get_path() == local_path) { //circular reference attempt
return "null";
}
//external resource
String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path();
- return "Resource( \"" + path + "\" )";
+ return "Resource(\"" + path + "\")";
} else {
ERR_FAIL_V_MSG("null", "Resource was not pre cached for the resource section, bug?");
//internal resource
@@ -1931,6 +1949,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
Ref<PackedScene> instance = state->get_node_instance(i);
String instance_placeholder = state->get_node_instance_placeholder(i);
Vector<StringName> groups = state->get_node_groups(i);
+ Vector<String> deferred_node_paths = state->get_node_deferred_nodepath_properties(i);
String header = "[node";
header += " name=\"" + String(name).c_escape() + "\"";
@@ -1947,6 +1966,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
header += " index=\"" + itos(index) + "\"";
}
+ if (deferred_node_paths.size()) {
+ header += " node_paths=" + Variant(deferred_node_paths).get_construct_string();
+ }
+
if (groups.size()) {
// Write all groups on the same line as they're part of a section header.
// This improves readability while not impacting VCS friendliness too much,
diff --git a/scene/resources/scene_replication_config.cpp b/scene/resources/scene_replication_config.cpp
index 4aea04bf87..6789f9f7d5 100644
--- a/scene/resources/scene_replication_config.cpp
+++ b/scene/resources/scene_replication_config.cpp
@@ -52,11 +52,19 @@ bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_val
ReplicationProperty &prop = properties[idx];
if (what == "sync") {
prop.sync = p_value;
- sync_props.push_back(prop.name);
+ if (prop.sync) {
+ sync_props.push_back(prop.name);
+ } else {
+ sync_props.erase(prop.name);
+ }
return true;
} else if (what == "spawn") {
prop.spawn = p_value;
- spawn_props.push_back(prop.name);
+ if (prop.spawn) {
+ spawn_props.push_back(prop.name);
+ } else {
+ spawn_props.erase(prop.name);
+ }
return true;
}
}
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
new file mode 100644
index 0000000000..05d48f9545
--- /dev/null
+++ b/scene/resources/skeleton_profile.cpp
@@ -0,0 +1,514 @@
+/*************************************************************************/
+/* skeleton_profile.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_profile.h"
+
+bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
+ ERR_FAIL_COND_V(is_read_only, false);
+ String path = p_path;
+
+ if (path.begins_with("group/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, groups.size(), false);
+
+ if (what == "group_name") {
+ set_group_name(which, p_value);
+ } else if (what == "texture") {
+ set_texture(which, p_value);
+ }
+ return true;
+ }
+
+ if (path.begins_with("bone/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, bones.size(), false);
+
+ if (what == "bone_name") {
+ set_bone_name(which, p_value);
+ } else if (what == "handle_offset") {
+ set_handle_offset(which, p_value);
+ } else if (what == "group") {
+ set_group(which, p_value);
+ }
+ return true;
+ }
+ return true;
+}
+
+bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("group/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, groups.size(), false);
+
+ if (what == "group_name") {
+ r_ret = get_group_name(which);
+ } else if (what == "texture") {
+ r_ret = get_texture(which);
+ }
+ return true;
+ }
+
+ if (path.begins_with("bone/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, bones.size(), false);
+
+ if (what == "bone_name") {
+ r_ret = get_bone_name(which);
+ } else if (what == "handle_offset") {
+ r_ret = get_handle_offset(which);
+ } else if (what == "group") {
+ r_ret = get_group(which);
+ }
+ return true;
+ }
+ return true;
+}
+
+void SkeletonProfile::_validate_property(PropertyInfo &property) const {
+ if (is_read_only) {
+ if (property.name == ("group_size") || property.name == ("bone_size")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+ }
+}
+
+void SkeletonProfile::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (is_read_only) {
+ return;
+ }
+ String group_names = "";
+ for (int i = 0; i < groups.size(); i++) {
+ String path = "group/" + itos(i) + "/";
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group_name"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, path + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
+ if (i > 0) {
+ group_names = group_names + ",";
+ }
+ group_names = group_names + groups[i].group_name;
+ }
+ for (int i = 0; i < bones.size(); i++) {
+ String path = "bone/" + itos(i) + "/";
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_name"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, path + "handle_offset"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group", PROPERTY_HINT_ENUM, group_names));
+ }
+}
+
+int SkeletonProfile::get_group_size() {
+ return groups.size();
+}
+
+void SkeletonProfile::set_group_size(int p_size) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_COND(p_size < 0);
+ groups.resize(p_size);
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+StringName SkeletonProfile::get_group_name(int p_group_idx) const {
+ ERR_FAIL_INDEX_V(p_group_idx, groups.size(), StringName());
+ return groups[p_group_idx].group_name;
+}
+
+void SkeletonProfile::set_group_name(int p_group_idx, const StringName p_group_name) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_group_idx, groups.size());
+ groups.write[p_group_idx].group_name = p_group_name;
+ emit_signal("profile_updated");
+}
+
+Ref<Texture2D> SkeletonProfile::get_texture(int p_group_idx) const {
+ ERR_FAIL_INDEX_V(p_group_idx, groups.size(), Ref<Texture2D>());
+ return groups[p_group_idx].texture;
+}
+
+void SkeletonProfile::set_texture(int p_group_idx, const Ref<Texture2D> &p_texture) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_group_idx, groups.size());
+ groups.write[p_group_idx].texture = p_texture;
+ emit_signal("profile_updated");
+}
+
+int SkeletonProfile::get_bone_size() {
+ return bones.size();
+}
+
+void SkeletonProfile::set_bone_size(int p_size) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_COND(p_size < 0);
+ bones.resize(p_size);
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+StringName SkeletonProfile::get_bone_name(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_name;
+}
+
+void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName p_bone_name) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_name = p_bone_name;
+ emit_signal("profile_updated");
+}
+
+Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Vector2());
+ return bones[p_bone_idx].handle_offset;
+}
+
+void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].handle_offset = p_handle_offset;
+ emit_signal("profile_updated");
+}
+
+StringName SkeletonProfile::get_group(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].group;
+}
+
+void SkeletonProfile::set_group(int p_bone_idx, const StringName p_group) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].group = p_group;
+ emit_signal("profile_updated");
+}
+
+bool SkeletonProfile::has_bone(StringName p_bone_name) {
+ bool is_found = false;
+ for (int i = 0; i < bones.size(); i++) {
+ if (bones[i].bone_name == p_bone_name) {
+ is_found = true;
+ break;
+ }
+ }
+ return is_found;
+}
+
+void SkeletonProfile::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_group_size", "size"), &SkeletonProfile::set_group_size);
+ ClassDB::bind_method(D_METHOD("get_group_size"), &SkeletonProfile::get_group_size);
+
+ ClassDB::bind_method(D_METHOD("get_group_name", "group_idx"), &SkeletonProfile::get_group_name);
+ ClassDB::bind_method(D_METHOD("set_group_name", "group_idx", "group_name"), &SkeletonProfile::set_group_name);
+
+ ClassDB::bind_method(D_METHOD("get_texture", "group_idx"), &SkeletonProfile::get_texture);
+ ClassDB::bind_method(D_METHOD("set_texture", "group_idx", "texture"), &SkeletonProfile::set_texture);
+
+ ClassDB::bind_method(D_METHOD("set_bone_size", "size"), &SkeletonProfile::set_bone_size);
+ ClassDB::bind_method(D_METHOD("get_bone_size"), &SkeletonProfile::get_bone_size);
+
+ ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &SkeletonProfile::get_bone_name);
+ ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "bone_name"), &SkeletonProfile::set_bone_name);
+
+ ClassDB::bind_method(D_METHOD("get_handle_offset", "bone_idx"), &SkeletonProfile::get_handle_offset);
+ ClassDB::bind_method(D_METHOD("set_handle_offset", "bone_idx", "handle_offset"), &SkeletonProfile::set_handle_offset);
+
+ ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group);
+ ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "group_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Groups,group/"), "set_group_size", "get_group_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Bones,bone/"), "set_bone_size", "get_bone_size");
+
+ ADD_SIGNAL(MethodInfo("profile_updated"));
+}
+
+SkeletonProfile::SkeletonProfile() {
+}
+
+SkeletonProfile::~SkeletonProfile() {
+}
+
+SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
+ is_read_only = true;
+
+ groups.resize(4);
+
+ groups.write[0].group_name = "Body";
+ groups.write[1].group_name = "Face";
+ groups.write[2].group_name = "LeftHand";
+ groups.write[3].group_name = "RightHand";
+
+ bones.resize(56);
+
+ bones.write[0].bone_name = "Root";
+ bones.write[0].handle_offset = Vector2(0.5, 0.91);
+ bones.write[0].group = "Body";
+
+ bones.write[1].bone_name = "Hips";
+ bones.write[1].handle_offset = Vector2(0.5, 0.5);
+ bones.write[1].group = "Body";
+
+ bones.write[2].bone_name = "Spine";
+ bones.write[2].handle_offset = Vector2(0.5, 0.43);
+ bones.write[2].group = "Body";
+
+ bones.write[3].bone_name = "Chest";
+ bones.write[3].handle_offset = Vector2(0.5, 0.36);
+ bones.write[3].group = "Body";
+
+ bones.write[4].bone_name = "UpperChest";
+ bones.write[4].handle_offset = Vector2(0.5, 0.29);
+ bones.write[4].group = "Body";
+
+ bones.write[5].bone_name = "Neck";
+ bones.write[5].handle_offset = Vector2(0.5, 0.23);
+ bones.write[5].group = "Body";
+
+ bones.write[6].bone_name = "Head";
+ bones.write[6].handle_offset = Vector2(0.5, 0.18);
+ bones.write[6].group = "Body";
+
+ bones.write[7].bone_name = "LeftEye";
+ bones.write[7].handle_offset = Vector2(0.6, 0.46);
+ bones.write[7].group = "Face";
+
+ bones.write[8].bone_name = "RightEye";
+ bones.write[8].handle_offset = Vector2(0.37, 0.46);
+ bones.write[8].group = "Face";
+
+ bones.write[9].bone_name = "Jaw";
+ bones.write[9].handle_offset = Vector2(0.46, 0.75);
+ bones.write[9].group = "Face";
+
+ bones.write[10].bone_name = "LeftShoulder";
+ bones.write[10].handle_offset = Vector2(0.55, 0.235);
+ bones.write[10].group = "Body";
+
+ bones.write[11].bone_name = "LeftUpperArm";
+ bones.write[11].handle_offset = Vector2(0.6, 0.24);
+ bones.write[11].group = "Body";
+
+ bones.write[12].bone_name = "LeftLowerArm";
+ bones.write[12].handle_offset = Vector2(0.7, 0.24);
+ bones.write[12].group = "Body";
+
+ bones.write[13].bone_name = "LeftHand";
+ bones.write[13].handle_offset = Vector2(0.82, 0.235);
+ bones.write[13].group = "Body";
+
+ bones.write[14].bone_name = "LeftThumbProximal";
+ bones.write[14].handle_offset = Vector2(0.4, 0.8);
+ bones.write[14].group = "LeftHand";
+
+ bones.write[15].bone_name = "LeftThumbIntermediate";
+ bones.write[15].handle_offset = Vector2(0.3, 0.69);
+ bones.write[15].group = "LeftHand";
+
+ bones.write[16].bone_name = "LeftThumbDistal";
+ bones.write[16].handle_offset = Vector2(0.23, 0.555);
+ bones.write[16].group = "LeftHand";
+
+ bones.write[17].bone_name = "LeftIndexProximal";
+ bones.write[17].handle_offset = Vector2(0.413, 0.52);
+ bones.write[17].group = "LeftHand";
+
+ bones.write[18].bone_name = "LeftIndexIntermediate";
+ bones.write[18].handle_offset = Vector2(0.403, 0.36);
+ bones.write[18].group = "LeftHand";
+
+ bones.write[19].bone_name = "LeftIndexDistal";
+ bones.write[19].handle_offset = Vector2(0.403, 0.255);
+ bones.write[19].group = "LeftHand";
+
+ bones.write[20].bone_name = "LeftMiddleProximal";
+ bones.write[20].handle_offset = Vector2(0.5, 0.51);
+ bones.write[20].group = "LeftHand";
+
+ bones.write[21].bone_name = "LeftMiddleIntermediate";
+ bones.write[21].handle_offset = Vector2(0.5, 0.345);
+ bones.write[21].group = "LeftHand";
+
+ bones.write[22].bone_name = "LeftMiddleDistal";
+ bones.write[22].handle_offset = Vector2(0.5, 0.22);
+ bones.write[22].group = "LeftHand";
+
+ bones.write[23].bone_name = "LeftRingProximal";
+ bones.write[23].handle_offset = Vector2(0.586, 0.52);
+ bones.write[23].group = "LeftHand";
+
+ bones.write[24].bone_name = "LeftRingIntermediate";
+ bones.write[24].handle_offset = Vector2(0.59, 0.36);
+ bones.write[24].group = "LeftHand";
+
+ bones.write[25].bone_name = "LeftRingDistal";
+ bones.write[25].handle_offset = Vector2(0.591, 0.25);
+ bones.write[25].group = "LeftHand";
+
+ bones.write[26].bone_name = "LeftLittleProximal";
+ bones.write[26].handle_offset = Vector2(0.663, 0.543);
+ bones.write[26].group = "LeftHand";
+
+ bones.write[27].bone_name = "LeftLittleIntermediate";
+ bones.write[27].handle_offset = Vector2(0.672, 0.415);
+ bones.write[27].group = "LeftHand";
+
+ bones.write[28].bone_name = "LeftLittleDistal";
+ bones.write[28].handle_offset = Vector2(0.672, 0.32);
+ bones.write[28].group = "LeftHand";
+
+ bones.write[29].bone_name = "RightShoulder";
+ bones.write[29].handle_offset = Vector2(0.45, 0.235);
+ bones.write[29].group = "Body";
+
+ bones.write[30].bone_name = "RightUpperArm";
+ bones.write[30].handle_offset = Vector2(0.4, 0.24);
+ bones.write[30].group = "Body";
+
+ bones.write[31].bone_name = "RightLowerArm";
+ bones.write[31].handle_offset = Vector2(0.3, 0.24);
+ bones.write[31].group = "Body";
+
+ bones.write[32].bone_name = "RightHand";
+ bones.write[32].handle_offset = Vector2(0.18, 0.235);
+ bones.write[32].group = "Body";
+
+ bones.write[33].bone_name = "RightThumbProximal";
+ bones.write[33].handle_offset = Vector2(0.6, 0.8);
+ bones.write[33].group = "RightHand";
+
+ bones.write[34].bone_name = "RightThumbIntermediate";
+ bones.write[34].handle_offset = Vector2(0.7, 0.69);
+ bones.write[34].group = "RightHand";
+
+ bones.write[35].bone_name = "RightThumbDistal";
+ bones.write[35].handle_offset = Vector2(0.77, 0.555);
+ bones.write[35].group = "RightHand";
+
+ bones.write[36].bone_name = "RightIndexProximal";
+ bones.write[36].handle_offset = Vector2(0.587, 0.52);
+ bones.write[36].group = "RightHand";
+
+ bones.write[37].bone_name = "RightIndexIntermediate";
+ bones.write[37].handle_offset = Vector2(0.597, 0.36);
+ bones.write[37].group = "RightHand";
+
+ bones.write[38].bone_name = "RightIndexDistal";
+ bones.write[38].handle_offset = Vector2(0.597, 0.255);
+ bones.write[38].group = "RightHand";
+
+ bones.write[39].bone_name = "RightMiddleProximal";
+ bones.write[39].handle_offset = Vector2(0.5, 0.51);
+ bones.write[39].group = "RightHand";
+
+ bones.write[40].bone_name = "RightMiddleIntermediate";
+ bones.write[40].handle_offset = Vector2(0.5, 0.345);
+ bones.write[40].group = "RightHand";
+
+ bones.write[41].bone_name = "RightMiddleDistal";
+ bones.write[41].handle_offset = Vector2(0.5, 0.22);
+ bones.write[41].group = "RightHand";
+
+ bones.write[42].bone_name = "RightRingProximal";
+ bones.write[42].handle_offset = Vector2(0.414, 0.52);
+ bones.write[42].group = "RightHand";
+
+ bones.write[43].bone_name = "RightRingIntermediate";
+ bones.write[43].handle_offset = Vector2(0.41, 0.36);
+ bones.write[43].group = "RightHand";
+
+ bones.write[44].bone_name = "RightRingDistal";
+ bones.write[44].handle_offset = Vector2(0.409, 0.25);
+ bones.write[44].group = "RightHand";
+
+ bones.write[45].bone_name = "RightLittleProximal";
+ bones.write[45].handle_offset = Vector2(0.337, 0.543);
+ bones.write[45].group = "RightHand";
+
+ bones.write[46].bone_name = "RightLittleIntermediate";
+ bones.write[46].handle_offset = Vector2(0.328, 0.415);
+ bones.write[46].group = "RightHand";
+
+ bones.write[47].bone_name = "RightLittleDistal";
+ bones.write[47].handle_offset = Vector2(0.328, 0.32);
+ bones.write[47].group = "RightHand";
+
+ bones.write[48].bone_name = "LeftUpperLeg";
+ bones.write[48].handle_offset = Vector2(0.549, 0.49);
+ bones.write[48].group = "Body";
+
+ bones.write[49].bone_name = "LeftLowerLeg";
+ bones.write[49].handle_offset = Vector2(0.548, 0.683);
+ bones.write[49].group = "Body";
+
+ bones.write[50].bone_name = "LeftFoot";
+ bones.write[50].handle_offset = Vector2(0.545, 0.9);
+ bones.write[50].group = "Body";
+
+ bones.write[51].bone_name = "LeftToes";
+ bones.write[51].handle_offset = Vector2(0.545, 0.95);
+ bones.write[51].group = "Body";
+
+ bones.write[52].bone_name = "RightUpperLeg";
+ bones.write[52].handle_offset = Vector2(0.451, 0.49);
+ bones.write[52].group = "Body";
+
+ bones.write[53].bone_name = "RightLowerLeg";
+ bones.write[53].handle_offset = Vector2(0.452, 0.683);
+ bones.write[53].group = "Body";
+
+ bones.write[54].bone_name = "RightFoot";
+ bones.write[54].handle_offset = Vector2(0.455, 0.9);
+ bones.write[54].group = "Body";
+
+ bones.write[55].bone_name = "RightToes";
+ bones.write[55].handle_offset = Vector2(0.455, 0.95);
+ bones.write[55].group = "Body";
+}
+
+SkeletonProfileHumanoid::~SkeletonProfileHumanoid() {
+}
+
+//////////////////////////////////////
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
new file mode 100644
index 0000000000..920aaa2b8d
--- /dev/null
+++ b/scene/resources/skeleton_profile.h
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* skeleton_profile.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETON_PROFILE_H
+#define SKELETON_PROFILE_H
+
+#include "texture.h"
+
+class SkeletonProfile : public Resource {
+ GDCLASS(SkeletonProfile, Resource);
+
+protected:
+ // Note: SkeletonProfileHumanoid which extends SkeletonProfile exists to unify standard bone names.
+ // That is what is_read_only is for, so don't make it public.
+ bool is_read_only = false;
+
+ struct SkeletonProfileGroup {
+ StringName group_name;
+ Ref<Texture2D> texture;
+ };
+
+ struct SkeletonProfileBone {
+ StringName bone_name;
+ Vector2 handle_offset;
+ StringName group;
+ };
+
+ Vector<SkeletonProfileGroup> groups;
+ Vector<SkeletonProfileBone> bones;
+
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ virtual void _validate_property(PropertyInfo &property) const override;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ static void _bind_methods();
+
+public:
+ int get_group_size();
+ void set_group_size(int p_size);
+
+ StringName get_group_name(int p_group_idx) const;
+ void set_group_name(int p_group_idx, const StringName p_group_name);
+
+ Ref<Texture2D> get_texture(int p_group_idx) const;
+ void set_texture(int p_group_idx, const Ref<Texture2D> &p_texture);
+
+ int get_bone_size();
+ void set_bone_size(int p_size);
+
+ StringName get_bone_name(int p_bone_idx) const;
+ void set_bone_name(int p_bone_idx, const StringName p_bone_name);
+
+ Vector2 get_handle_offset(int p_bone_idx) const;
+ void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset);
+
+ StringName get_group(int p_bone_idx) const;
+ void set_group(int p_bone_idx, const StringName p_group);
+
+ bool has_bone(StringName p_bone_name);
+
+ SkeletonProfile();
+ ~SkeletonProfile();
+};
+
+class SkeletonProfileHumanoid : public SkeletonProfile {
+ GDCLASS(SkeletonProfileHumanoid, SkeletonProfile);
+
+public:
+ SkeletonProfileHumanoid();
+ ~SkeletonProfileHumanoid();
+};
+
+#endif // SKELETON_PROFILE_H
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 0e41eed570..9829c7e86b 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -141,7 +141,8 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h);
h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h);
h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h);
- h = hash_djb2_one_32(p_vtx.smooth_group, h);
+ h = hash_murmur3_one_32(p_vtx.smooth_group, h);
+ h = hash_fmix32(h);
return h;
}
@@ -315,19 +316,17 @@ void SurfaceTool::set_uv2(const Vector2 &p_uv2) {
last_uv2 = p_uv2;
}
-void SurfaceTool::set_custom(int p_index, const Color &p_custom) {
- ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+void SurfaceTool::set_custom(int p_channel_index, const Color &p_custom) {
+ ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT);
ERR_FAIL_COND(!begun);
- ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX);
+ ERR_FAIL_COND(last_custom_format[p_channel_index] == CUSTOM_MAX);
static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
- static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
- ERR_FAIL_COND(!first && !(format & mask[p_index]));
+ ERR_FAIL_COND(!first && !(format & mask[p_channel_index]));
if (first) {
- format |= mask[p_index];
- format |= last_custom_format[p_index] << shift[p_index];
+ format |= mask[p_channel_index];
}
- last_custom[p_index] = p_custom;
+ last_custom[p_channel_index] = p_custom;
}
void SurfaceTool::set_bones(const Vector<int> &p_bones) {
@@ -689,7 +688,7 @@ Array SurfaceTool::commit_to_arrays() {
return a;
}
-Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) {
+Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_compress_flags) {
Ref<ArrayMesh> mesh;
if (p_existing.is_valid()) {
mesh = p_existing;
@@ -707,7 +706,15 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_
Array a = commit_to_arrays();
- mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), p_flags);
+ uint32_t compress_flags = (p_compress_flags >> RS::ARRAY_COMPRESS_FLAGS_BASE) << RS::ARRAY_COMPRESS_FLAGS_BASE;
+ static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ if (last_custom_format[i] != CUSTOM_MAX) {
+ compress_flags |= last_custom_format[i] << shift[i];
+ }
+ }
+
+ mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), compress_flags);
if (material.is_valid()) {
mesh->surface_set_material(surface, material);
@@ -988,9 +995,6 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) {
if (format & custom_mask[j]) {
CustomFormat new_format = (CustomFormat)((format >> custom_shift[j]) & RS::ARRAY_FORMAT_CUSTOM_MASK);
- if (last_custom_format[j] != CUSTOM_MAX && last_custom_format[j] != new_format) {
- WARN_PRINT(vformat("Custom %d format %d mismatch when appending format %d", j, last_custom_format[j], new_format));
- }
last_custom_format[j] = new_format;
}
}
@@ -1220,22 +1224,24 @@ SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const {
return skin_weights;
}
-void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
- ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
- ERR_FAIL_COND(begun);
- last_custom_format[p_index] = p_format;
+void SurfaceTool::set_custom_format(int p_channel_index, CustomFormat p_format) {
+ ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT);
+ ERR_FAIL_COND(!begun);
+ ERR_FAIL_INDEX(p_format, CUSTOM_MAX + 1);
+ last_custom_format[p_channel_index] = p_format;
}
-Mesh::PrimitiveType SurfaceTool::get_primitive() const {
+Mesh::PrimitiveType SurfaceTool::get_primitive_type() const {
return primitive;
}
-SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
- return last_custom_format[p_index];
+SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_channel_index) const {
+ ERR_FAIL_INDEX_V(p_channel_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
+ return last_custom_format[p_channel_index];
}
void SurfaceTool::optimize_indices_for_cache() {
ERR_FAIL_COND(optimize_vertex_cache_func == nullptr);
ERR_FAIL_COND(index_array.size() == 0);
+ ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES);
ERR_FAIL_COND(index_array.size() % 3 != 0);
LocalVector old_index_array = index_array;
@@ -1243,8 +1249,8 @@ void SurfaceTool::optimize_indices_for_cache() {
optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size());
}
-float SurfaceTool::get_max_axis_length() const {
- ERR_FAIL_COND_V(vertex_array.size() == 0, 0);
+AABB SurfaceTool::get_aabb() const {
+ ERR_FAIL_COND_V(vertex_array.size() == 0, AABB());
AABB aabb;
for (uint32_t i = 0; i < vertex_array.size(); i++) {
@@ -1255,7 +1261,7 @@ float SurfaceTool::get_max_axis_length() const {
}
}
- return aabb.get_longest_axis_size();
+ return aabb;
}
Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) {
Vector<int> lod;
@@ -1288,8 +1294,8 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count);
ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count);
- ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format);
- ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format);
+ ClassDB::bind_method(D_METHOD("set_custom_format", "channel_index", "format"), &SurfaceTool::set_custom_format);
+ ClassDB::bind_method(D_METHOD("get_custom_format", "channel_index"), &SurfaceTool::get_custom_format);
ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin);
@@ -1301,7 +1307,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2);
ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones);
ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights);
- ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom);
+ ClassDB::bind_method(D_METHOD("set_custom", "channel_index", "custom_color"), &SurfaceTool::set_custom);
ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group);
ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
@@ -1315,11 +1321,11 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache);
- ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length);
+ ClassDB::bind_method(D_METHOD("get_aabb"), &SurfaceTool::get_aabb);
ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
- ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive);
+ ClassDB::bind_method(D_METHOD("get_primitive_type"), &SurfaceTool::get_primitive_type);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index bf4332ad2a..2d399ca3bf 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -154,10 +154,10 @@ public:
void set_skin_weight_count(SkinWeightCount p_weights);
SkinWeightCount get_skin_weight_count() const;
- void set_custom_format(int p_index, CustomFormat p_format);
- CustomFormat get_custom_format(int p_index) const;
+ void set_custom_format(int p_channel_index, CustomFormat p_format);
+ CustomFormat get_custom_format(int p_channel_index) const;
- Mesh::PrimitiveType get_primitive() const;
+ Mesh::PrimitiveType get_primitive_type() const;
void begin(Mesh::PrimitiveType p_primitive);
@@ -166,7 +166,7 @@ public:
void set_tangent(const Plane &p_tangent);
void set_uv(const Vector2 &p_uv);
void set_uv2(const Vector2 &p_uv2);
- void set_custom(int p_index, const Color &p_custom);
+ void set_custom(int p_channel_index, const Color &p_custom);
void set_bones(const Vector<int> &p_bones);
void set_weights(const Vector<float> &p_weights);
void set_smooth_group(uint32_t p_group);
@@ -183,7 +183,7 @@ public:
void generate_tangents();
void optimize_indices_for_cache();
- float get_max_axis_length() const;
+ AABB get_aabb() const;
Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
void set_material(const Ref<Material> &p_material);
@@ -199,7 +199,7 @@ public:
void create_from(const Ref<Mesh> &p_existing, int p_surface);
void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform3D &p_xform);
- Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0);
+ Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_compress_flags = 0);
SurfaceTool();
};
diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp
index 96a47c37c4..0404e1f79b 100644
--- a/scene/resources/text_file.cpp
+++ b/scene/resources/text_file.cpp
@@ -64,7 +64,7 @@ Error TextFile::load_text(const String &p_path) {
w[len] = 0;
String s;
- ERR_FAIL_COND_V_MSG(s.parse_utf8((const char *)w), ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
+ ERR_FAIL_COND_V_MSG(s.parse_utf8((const char *)w) != OK, ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
text = s;
path = p_path;
return OK;
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index f9390ca528..f32b7feb4b 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -55,7 +55,7 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::set_bidi_override);
- ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_string", "text", "font", "font_size", "language", "meta"), &TextLine::add_string, DEFVAL(""), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
@@ -98,12 +98,6 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color"), &TextLine::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextLine::hit_test);
-
- BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextLine::_shape() {
@@ -112,26 +106,26 @@ void TextLine::_shape() {
TS->shaped_text_tab_align(rid, tab_stops);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_WORD:
+ case TextServer::OVERRUN_TRIM_WORD:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
break;
- case OVERRUN_TRIM_CHAR:
+ case TextServer::OVERRUN_TRIM_CHAR:
overrun_flags |= TextServer::OVERRUN_TRIM;
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
@@ -155,8 +149,6 @@ RID TextLine::get_rid() const {
void TextLine::clear() {
TS->shaped_text_clear(rid);
- spacing_top = 0;
- spacing_bottom = 0;
}
void TextLine::set_preserve_invalid(bool p_enabled) {
@@ -200,11 +192,12 @@ void TextLine::set_bidi_override(const Array &p_override) {
dirty = true;
}
-bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
- bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+bool TextLine::add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, const Variant &p_meta) {
+ ERR_FAIL_COND_V(p_font.is_null(), false);
+ bool res = TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language, p_meta);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
dirty = true;
return res;
}
@@ -259,20 +252,20 @@ uint16_t TextLine::get_flags() const {
return flags;
}
-void TextLine::set_text_overrun_behavior(TextLine::OverrunBehavior p_behavior) {
+void TextLine::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
if (overrun_behavior != p_behavior) {
overrun_behavior = p_behavior;
dirty = true;
}
}
-TextLine::OverrunBehavior TextLine::get_text_overrun_behavior() const {
+TextServer::OverrunBehavior TextLine::get_text_overrun_behavior() const {
return overrun_behavior;
}
void TextLine::set_width(float p_width) {
width = p_width;
- if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != OVERRUN_NO_TRIMMING) {
+ if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
dirty = true;
}
}
@@ -284,20 +277,20 @@ float TextLine::get_width() const {
Size2 TextLine::get_size() const {
const_cast<TextLine *>(this)->_shape();
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
} else {
- return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
}
}
float TextLine::get_line_ascent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_ascent(rid) + spacing_top;
+ return TS->shaped_text_get_ascent(rid);
}
float TextLine::get_line_descent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_descent(rid) + spacing_bottom;
+ return TS->shaped_text_get_descent(rid);
}
float TextLine::get_line_width() const {
@@ -353,10 +346,10 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) co
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color);
@@ -400,10 +393,10 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color);
@@ -415,11 +408,14 @@ int TextLine::hit_test(float p_coords) const {
return TS->shaped_text_hit_test_position(rid, p_coords);
}
-TextLine::TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+TextLine::TextLine(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
- TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ if (p_font.is_valid()) {
+ TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
+ }
}
TextLine::TextLine() {
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index c5762db0f2..2d1548d079 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -39,26 +39,15 @@
class TextLine : public RefCounted {
GDCLASS(TextLine, RefCounted);
-public:
- enum OverrunBehavior {
- OVERRUN_NO_TRIMMING,
- OVERRUN_TRIM_CHAR,
- OVERRUN_TRIM_WORD,
- OVERRUN_TRIM_ELLIPSIS,
- OVERRUN_TRIM_WORD_ELLIPSIS,
- };
-
private:
RID rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
bool dirty = true;
float width = -1.0;
uint16_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
- OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
+ TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_TRIM_ELLIPSIS;
Vector<float> tab_stops;
@@ -86,7 +75,7 @@ public:
void set_preserve_control(bool p_enabled);
bool get_preserve_control() const;
- bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant());
+ bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
@@ -98,8 +87,8 @@ public:
void set_flags(uint16_t p_flags);
uint16_t get_flags() const;
- void set_text_overrun_behavior(OverrunBehavior p_behavior);
- OverrunBehavior get_text_overrun_behavior() const;
+ void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
+ TextServer::OverrunBehavior get_text_overrun_behavior() const;
void set_width(float p_width);
float get_width() const;
@@ -120,11 +109,9 @@ public:
int hit_test(float p_coords) const;
- TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
+ TextLine(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextLine();
~TextLine();
};
-VARIANT_ENUM_CAST(TextLine::OverrunBehavior);
-
#endif // TEXT_LINE_H
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 477b41efaa..c8b9e895fc 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -60,10 +60,10 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextParagraph::set_bidi_override);
- ClassDB::bind_method(D_METHOD("set_dropcap", "text", "fonts", "size", "dropcap_margins", "opentype_features", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(Dictionary()), DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("set_dropcap", "text", "font", "font_size", "dropcap_margins", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(""));
ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap);
- ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_string", "text", "font", "font_size", "language", "meta"), &TextParagraph::add_string, DEFVAL(""), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
@@ -113,9 +113,6 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_underline_position", "line"), &TextParagraph::get_line_underline_position);
ClassDB::bind_method(D_METHOD("get_line_underline_thickness", "line"), &TextParagraph::get_line_underline_thickness);
- ClassDB::bind_method(D_METHOD("get_spacing_top"), &TextParagraph::get_spacing_top);
- ClassDB::bind_method(D_METHOD("get_spacing_bottom"), &TextParagraph::get_spacing_bottom);
-
ClassDB::bind_method(D_METHOD("get_dropcap_size"), &TextParagraph::get_dropcap_size);
ClassDB::bind_method(D_METHOD("get_dropcap_lines"), &TextParagraph::get_dropcap_lines);
@@ -129,12 +126,6 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test);
-
- BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextParagraph::_shape_lines() {
@@ -190,26 +181,26 @@ void TextParagraph::_shape_lines() {
lines_rid.push_back(line);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_WORD:
+ case TextServer::OVERRUN_TRIM_WORD:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
break;
- case OVERRUN_TRIM_CHAR:
+ case TextServer::OVERRUN_TRIM_CHAR:
overrun_flags |= TextServer::OVERRUN_TRIM;
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
}
@@ -272,8 +263,6 @@ RID TextParagraph::get_dropcap_rid() const {
void TextParagraph::clear() {
_THREAD_SAFE_METHOD_
- spacing_top = 0;
- spacing_bottom = 0;
for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
@@ -353,44 +342,37 @@ TextServer::Orientation TextParagraph::get_orientation() const {
return TS->shaped_text_get_orientation(rid);
}
-bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
+bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_font, int p_font_size, const Rect2 &p_dropcap_margins, const String &p_language) {
_THREAD_SAFE_METHOD_
-
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
+ ERR_FAIL_COND_V(p_font.is_null(), false);
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
- bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(dropcap_rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
lines_dirty = true;
return res;
}
void TextParagraph::clear_dropcap() {
_THREAD_SAFE_METHOD_
-
dropcap_margins = Rect2();
TS->shaped_text_clear(dropcap_rid);
lines_dirty = true;
}
-bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, const Variant &p_meta) {
_THREAD_SAFE_METHOD_
-
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
- bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+ ERR_FAIL_COND_V(p_font.is_null(), false);
+ bool res = TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language, p_meta);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
lines_dirty = true;
return res;
}
-int TextParagraph::get_spacing_top() const {
- return spacing_top;
-}
-
-int TextParagraph::get_spacing_bottom() const {
- return spacing_bottom;
-}
-
void TextParagraph::set_bidi_override(const Array &p_override) {
_THREAD_SAFE_METHOD_
@@ -451,7 +433,7 @@ uint16_t TextParagraph::get_flags() const {
return flags;
}
-void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
+void TextParagraph::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
_THREAD_SAFE_METHOD_
if (overrun_behavior != p_behavior) {
@@ -460,7 +442,7 @@ void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_b
}
}
-TextParagraph::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
+TextServer::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
return overrun_behavior;
}
@@ -482,9 +464,9 @@ Size2 TextParagraph::get_non_wrapped_size() const {
const_cast<TextParagraph *>(this)->_shape_lines();
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
} else {
- return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
}
}
@@ -498,9 +480,9 @@ Size2 TextParagraph::get_size() const {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
size.x = MAX(size.x, lsize.x);
- size.y += lsize.y + spacing_top + spacing_bottom;
+ size.y += lsize.y;
} else {
- size.x += lsize.x + spacing_top + spacing_bottom;
+ size.x += lsize.x;
size.y = MAX(size.y, lsize.y);
}
}
@@ -544,9 +526,9 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
for (int i = 0; i < p_line; i++) {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- xrect.position.y += lsize.y + spacing_top + spacing_bottom;
+ xrect.position.y += lsize.y;
} else {
- xrect.position.x += lsize.x + spacing_top + spacing_bottom;
+ xrect.position.x += lsize.x;
}
}
return xrect;
@@ -558,9 +540,9 @@ Size2 TextParagraph::get_line_size(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Size2());
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y);
} else {
- return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines_rid[p_line]).y);
+ return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y);
}
}
@@ -577,7 +559,7 @@ float TextParagraph::get_line_ascent(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
- return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ return TS->shaped_text_get_ascent(lines_rid[p_line]);
}
float TextParagraph::get_line_descent(int p_line) const {
@@ -585,7 +567,7 @@ float TextParagraph::get_line_descent(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
- return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
+ return TS->shaped_text_get_descent(lines_rid[p_line]);
}
float TextParagraph::get_line_width(int p_line) const {
@@ -653,7 +635,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -662,7 +644,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
}
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -717,10 +699,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
}
}
}
@@ -755,7 +737,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -764,7 +746,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -819,10 +801,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
}
}
}
@@ -846,12 +828,12 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) {
return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x);
}
- ofs.y += TS->shaped_text_get_size(lines_rid[i]).y + spacing_bottom + spacing_top;
+ ofs.y += TS->shaped_text_get_size(lines_rid[i]).y;
} else {
if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines_rid[i]).x)) {
return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.y);
}
- ofs.y += TS->shaped_text_get_size(lines_rid[i]).x + spacing_bottom + spacing_top;
+ ofs.y += TS->shaped_text_get_size(lines_rid[i]).x;
}
}
return TS->shaped_text_get_range(rid).y;
@@ -914,9 +896,9 @@ void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, co
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]);
} else {
- ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]);
}
return TS->shaped_text_draw(lines_rid[p_line], p_canvas, ofs, -1, -1, p_color);
}
@@ -929,18 +911,21 @@ void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]);
} else {
- ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]);
}
return TS->shaped_text_draw_outline(lines_rid[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color);
}
-TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
- TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+ if (p_font.is_valid()) {
+ TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
+ }
width = p_width;
}
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 4f1aad16b5..f161cb5b8c 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -41,15 +41,6 @@ class TextParagraph : public RefCounted {
GDCLASS(TextParagraph, RefCounted);
_THREAD_SAFE_CLASS_
-public:
- enum OverrunBehavior {
- OVERRUN_NO_TRIMMING,
- OVERRUN_TRIM_CHAR,
- OVERRUN_TRIM_WORD,
- OVERRUN_TRIM_ELLIPSIS,
- OVERRUN_TRIM_WORD_ELLIPSIS,
- };
-
private:
RID dropcap_rid;
int dropcap_lines = 0;
@@ -57,8 +48,6 @@ private:
RID rid;
LocalVector<RID> lines_rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
bool lines_dirty = true;
@@ -66,7 +55,7 @@ private:
int max_lines_visible = -1;
uint16_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
- OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
+ TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -101,10 +90,10 @@ public:
void set_custom_punctuation(const String &p_punct);
String get_custom_punctuation() const;
- bool set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "");
+ bool set_dropcap(const String &p_text, const Ref<Font> &p_font, int p_font_size, const Rect2 &p_dropcap_margins = Rect2(), const String &p_language = "");
void clear_dropcap();
- bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant());
+ bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
@@ -116,8 +105,8 @@ public:
void set_flags(uint16_t p_flags);
uint16_t get_flags() const;
- void set_text_overrun_behavior(OverrunBehavior p_behavior);
- OverrunBehavior get_text_overrun_behavior() const;
+ void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
+ TextServer::OverrunBehavior get_text_overrun_behavior() const;
void set_width(float p_width);
float get_width() const;
@@ -160,11 +149,9 @@ public:
Mutex &get_mutex() const { return _thread_safe_; };
- TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
+ TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextParagraph();
~TextParagraph();
};
-VARIANT_ENUM_CAST(TextParagraph::OverrunBehavior);
-
#endif // TEXT_PARAGRAPH_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index f31a71eada..e58ef68388 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -3016,12 +3016,12 @@ Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) {
}
void ImageTextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) {
- ERR_FAIL_COND(texture.is_valid());
- ERR_FAIL_COND(p_image.is_null());
- ERR_FAIL_COND(p_image->get_format() != format);
- ERR_FAIL_COND(p_image->get_width() != width || p_image->get_height() != height);
- ERR_FAIL_INDEX(p_layer, layers);
- ERR_FAIL_COND(p_image->has_mipmaps() != mipmaps);
+ ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized.");
+ ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image.");
+ ERR_FAIL_COND_MSG(p_image->get_format() != format, "Image format must match texture's image format.");
+ ERR_FAIL_COND_MSG(p_image->get_width() != width || p_image->get_height() != height, "Image size must match texture's image size.");
+ ERR_FAIL_COND_MSG(p_image->has_mipmaps() != mipmaps, "Image mipmap configuration must match texture's image mipmap configuration.");
+ ERR_FAIL_INDEX_MSG(p_layer, layers, "Layer index is out of bounds.");
RS::get_singleton()->texture_2d_update(texture, p_image, p_layer);
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 9d2d4cdb20..13b671e562 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -236,6 +236,9 @@ bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_patte
return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
}
}
+ if (terrain != p_terrains_pattern.terrain) {
+ return terrain < p_terrains_pattern.terrain;
+ }
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
return bits[i] < p_terrains_pattern.bits[i];
@@ -253,10 +256,23 @@ bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_patt
return false;
}
}
+ if (terrain != p_terrains_pattern.terrain) {
+ return false;
+ }
return true;
}
-void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
+void TileSet::TerrainsPattern::set_terrain(int p_terrain) {
+ ERR_FAIL_COND(p_terrain < -1);
+
+ terrain = p_terrain;
+}
+
+int TileSet::TerrainsPattern::get_terrain() const {
+ return terrain;
+}
+
+void TileSet::TerrainsPattern::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
ERR_FAIL_COND(p_terrain < -1);
@@ -271,25 +287,27 @@ void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit,
bits[p_peering_bit] = p_terrain;
}
-int TileSet::TerrainsPattern::get_terrain(TileSet::CellNeighbor p_peering_bit) const {
+int TileSet::TerrainsPattern::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
return bits[p_peering_bit];
}
-void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) {
- int in_array_index = 0;
+void TileSet::TerrainsPattern::from_array(Array p_terrains) {
+ set_terrain(p_terrains[0]);
+ int in_array_index = 1;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
ERR_FAIL_INDEX(in_array_index, p_terrains.size());
- set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
+ set_terrain_peering_bit(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
in_array_index++;
}
}
}
-Array TileSet::TerrainsPattern::get_terrains_as_array() const {
+Array TileSet::TerrainsPattern::as_array() const {
Array output;
+ output.push_back(get_terrain());
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
output.push_back(bits[i]);
@@ -297,10 +315,11 @@ Array TileSet::TerrainsPattern::get_terrains_as_array() const {
}
return output;
}
+
TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
ERR_FAIL_COND(p_terrain_set < 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- is_valid_bit[i] = (p_tile_set->is_valid_peering_bit_terrain(p_terrain_set, TileSet::CellNeighbor(i)));
+ is_valid_bit[i] = (p_tile_set->is_valid_terrain_peering_bit(p_terrain_set, TileSet::CellNeighbor(i)));
bits[i] = -1;
}
valid = true;
@@ -410,11 +429,16 @@ void TileSet::_update_terrains_cache() {
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
+ // Main terrain.
+ if (terrains_pattern.get_terrain() >= 0) {
+ per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
+ }
+
// Terrain bits.
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_terrain(terrain_set, bit)) {
- int terrain = terrains_pattern.get_terrain(bit);
+ if (is_valid_terrain_peering_bit(terrain_set, bit)) {
+ int terrain = terrains_pattern.get_terrain_peering_bit(bit);
if (terrain >= 0) {
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
}
@@ -822,7 +846,7 @@ Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
}
-bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
+bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
@@ -905,13 +929,13 @@ bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode,
return false;
}
-bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
+bool TileSet::is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
return false;
}
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
- return is_valid_peering_bit_for_mode(terrain_mode, p_peering_bit);
+ return is_valid_terrain_peering_bit_for_mode(terrain_mode, p_peering_bit);
}
// Navigation
@@ -1494,26 +1518,48 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform
}
}
-Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ return _get_square_terrain_polygon(tile_size);
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ return _get_isometric_terrain_polygon(tile_size);
+ } else {
+ float overlap = 0.0;
+ switch (tile_shape) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ return _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
+ }
+ return Vector<Point2>();
+}
+
+Vector<Point2> TileSet::get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>());
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_square_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_square_corner_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_corner_terrain_peering_bit_polygon(tile_size, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_square_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_side_terrain_peering_bit_polygon(tile_size, p_bit);
}
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_isometric_corner_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_corner_terrain_peering_bit_polygon(tile_size, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_isometric_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_side_terrain_peering_bit_polygon(tile_size, p_bit);
}
} else {
float overlap = 0.0;
@@ -1528,11 +1574,11 @@ Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::Cell
break;
}
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_half_offset_corner_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_half_offset_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
}
}
}
@@ -1544,30 +1590,68 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
if (terrain_bits_meshes_dirty) {
// Recompute the meshes.
- terrain_bits_meshes.clear();
+ terrain_peering_bits_meshes.clear();
for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) {
TerrainMode terrain_mode = TerrainMode(terrain_mode_index);
+
+ // Center terrain
+ Vector<Vector2> polygon;
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ polygon = _get_square_terrain_polygon(tile_size);
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ polygon = _get_isometric_terrain_polygon(tile_size);
+ } else {
+ float overlap = 0.0;
+ switch (tile_shape) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ polygon = _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
+ }
+ {
+ Ref<ArrayMesh> mesh;
+ mesh.instantiate();
+ Vector<Vector2> uvs;
+ uvs.resize(polygon.size());
+ Vector<Color> colors;
+ colors.resize(polygon.size());
+ colors.fill(Color(1.0, 1.0, 1.0, 1.0));
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = polygon;
+ a[Mesh::ARRAY_TEX_UV] = uvs;
+ a[Mesh::ARRAY_COLOR] = colors;
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+ terrain_meshes[terrain_mode] = mesh;
+ }
+ // Peering bits
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_for_mode(terrain_mode, bit)) {
- Vector<Vector2> polygon;
+ if (is_valid_terrain_peering_bit_for_mode(terrain_mode, bit)) {
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_square_corner_or_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_square_corner_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_corner_terrain_peering_bit_polygon(tile_size, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_square_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_side_terrain_peering_bit_polygon(tile_size, bit);
}
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_isometric_corner_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_corner_terrain_peering_bit_polygon(tile_size, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_isometric_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_side_terrain_peering_bit_polygon(tile_size, bit);
}
} else {
float overlap = 0.0;
@@ -1582,29 +1666,30 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
break;
}
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_half_offset_corner_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_half_offset_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
}
}
-
- Ref<ArrayMesh> mesh;
- mesh.instantiate();
- Vector<Vector2> uvs;
- uvs.resize(polygon.size());
- Vector<Color> colors;
- colors.resize(polygon.size());
- colors.fill(Color(1.0, 1.0, 1.0, 1.0));
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = polygon;
- a[Mesh::ARRAY_TEX_UV] = uvs;
- a[Mesh::ARRAY_COLOR] = colors;
- a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
- terrain_bits_meshes[terrain_mode][bit] = mesh;
+ {
+ Ref<ArrayMesh> mesh;
+ mesh.instantiate();
+ Vector<Vector2> uvs;
+ uvs.resize(polygon.size());
+ Vector<Color> colors;
+ colors.resize(polygon.size());
+ colors.fill(Color(1.0, 1.0, 1.0, 1.0));
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = polygon;
+ a[Mesh::ARRAY_TEX_UV] = uvs;
+ a[Mesh::ARRAY_COLOR] = colors;
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+ terrain_peering_bits_meshes[terrain_mode][bit] = mesh;
+ }
}
}
}
@@ -1618,14 +1703,21 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set);
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ int terrain_id = p_tile_data->get_terrain();
+ if (terrain_id >= 0) {
+ Color color = get_terrain_color(terrain_set, terrain_id);
+ color.a = TERRAIN_ALPHA;
+ p_canvas_item->draw_mesh(terrain_meshes[terrain_mode], Ref<Texture2D>(), Transform2D(), color);
+ }
+
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_terrain(terrain_set, bit)) {
- int terrain_id = p_tile_data->get_peering_bit_terrain(bit);
+ if (is_valid_terrain_peering_bit(terrain_set, bit)) {
+ terrain_id = p_tile_data->get_terrain_peering_bit(bit);
if (terrain_id >= 0) {
Color color = get_terrain_color(terrain_set, terrain_id);
color.a = TERRAIN_ALPHA;
- p_canvas_item->draw_mesh(terrain_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
+ p_canvas_item->draw_mesh(terrain_peering_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
}
}
}
@@ -1670,13 +1762,16 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
bit_counts[terrain] = 0;
}
+ if (tile_data->get_terrain() >= 0) {
+ bit_counts[tile_data->get_terrain()] += 10;
+ }
for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) {
TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit);
- if (is_valid_peering_bit_terrain(terrain_set, cell_neighbor)) {
- int terrain = tile_data->get_peering_bit_terrain(cell_neighbor);
+ if (is_valid_terrain_peering_bit(terrain_set, cell_neighbor)) {
+ int terrain = tile_data->get_terrain_peering_bit(cell_neighbor);
if (terrain >= 0) {
if (terrain >= (int)bit_counts.size()) {
- WARN_PRINT(vformat("Invalid peering bit terrain: %d", terrain));
+ WARN_PRINT(vformat("Invalid terrain peering bit: %d", terrain));
} else {
bit_counts[terrain] += 1;
}
@@ -1730,7 +1825,17 @@ void TileSet::_source_changed() {
emit_changed();
}
-Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_terrain_polygon(Vector2i p_size) {
+ Rect2 rect(-Vector2(p_size) / 6.0, Vector2(p_size) / 3.0);
+ return {
+ rect.position,
+ Vector2(rect.get_end().x, rect.position.y),
+ rect.get_end(),
+ Vector2(rect.position.x, rect.get_end().y)
+ };
+}
+
+Vector<Point2> TileSet::_get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Rect2 bit_rect;
bit_rect.size = Vector2(p_size) / 3;
switch (p_bit) {
@@ -1773,7 +1878,7 @@ Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i
return polygon;
}
-Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1815,7 +1920,7 @@ Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size,
return polygon;
}
-Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1849,7 +1954,17 @@ Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, Ti
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_terrain_polygon(Vector2i p_size) {
+ Vector2 unit = Vector2(p_size) / 6.0;
+ return {
+ Vector2(1, 0) * unit,
+ Vector2(0, 1) * unit,
+ Vector2(-1, 0) * unit,
+ Vector2(0, -1) * unit,
+ };
+}
+
+Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1907,7 +2022,7 @@ Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1949,7 +2064,7 @@ Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_siz
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1983,7 +2098,30 @@ Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size,
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+ Vector2 unit = Vector2(p_size) / 6.0;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ return {
+ Vector2(1, 1.0 - p_overlap * 2.0) * unit,
+ Vector2(0, 1) * unit,
+ Vector2(-1, 1.0 - p_overlap * 2.0) * unit,
+ Vector2(-1, -1.0 + p_overlap * 2.0) * unit,
+ Vector2(0, -1) * unit,
+ Vector2(1, -1.0 + p_overlap * 2.0) * unit,
+ };
+ } else {
+ return {
+ Vector2(1, 0) * unit,
+ Vector2(1.0 - p_overlap * 2.0, -1) * unit,
+ Vector2(-1.0 + p_overlap * 2.0, -1) * unit,
+ Vector2(-1, 0) * unit,
+ Vector2(-1.0 + p_overlap * 2.0, 1) * unit,
+ Vector2(1.0 - p_overlap * 2.0, 1) * unit,
+ };
+ }
+}
+
+Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
@@ -2006,12 +2144,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
polygon.push_back(point_list[17]);
@@ -2071,10 +2208,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
@@ -2144,7 +2279,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, 0),
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
@@ -2161,12 +2296,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
polygon.push_back(point_list[0]);
@@ -2202,10 +2336,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
@@ -2251,7 +2383,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
Vector2(0, 3),
@@ -2262,12 +2394,11 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
polygon.push_back(point_list[5]);
@@ -2297,10 +2428,8 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
@@ -4929,11 +5058,11 @@ Vector2i TileData::get_texture_offset() const {
return tex_offset;
}
-void TileData::set_material(Ref<ShaderMaterial> p_material) {
+void TileData::set_material(Ref<Material> p_material) {
material = p_material;
emit_signal(SNAME("changed"));
}
-Ref<ShaderMaterial> TileData::get_material() const {
+Ref<Material> TileData::get_material() const {
return material;
}
@@ -5114,36 +5243,51 @@ int TileData::get_terrain_set() const {
return terrain_set;
}
-void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
+void TileData::set_terrain(int p_terrain) {
+ ERR_FAIL_COND(terrain_set < 0);
+ ERR_FAIL_COND(p_terrain < -1);
+ if (tile_set) {
+ ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
+ }
+ terrain = p_terrain;
+ emit_signal(SNAME("changed"));
+}
+
+int TileData::get_terrain() const {
+ return terrain;
+}
+
+void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain_index < -1);
if (tile_set) {
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
- ERR_FAIL_COND(!is_valid_peering_bit_terrain(p_peering_bit));
+ ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
}
terrain_peering_bits[p_peering_bit] = p_terrain_index;
emit_signal(SNAME("changed"));
}
-int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
- ERR_FAIL_COND_V(!is_valid_peering_bit_terrain(p_peering_bit), -1);
+int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
+ ERR_FAIL_COND_V(!is_valid_terrain_peering_bit(p_peering_bit), -1);
return terrain_peering_bits[p_peering_bit];
}
-bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
+bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(!tile_set, false);
- return tile_set->is_valid_peering_bit_terrain(terrain_set, p_peering_bit);
+ return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
}
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
ERR_FAIL_COND_V(!tile_set, TileSet::TerrainsPattern());
TileSet::TerrainsPattern output(tile_set, terrain_set);
+ output.set_terrain(terrain);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- if (tile_set->is_valid_peering_bit_terrain(terrain_set, TileSet::CellNeighbor(i))) {
- output.set_terrain(TileSet::CellNeighbor(i), get_peering_bit_terrain(TileSet::CellNeighbor(i)));
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, TileSet::CellNeighbor(i))) {
+ output.set_terrain_peering_bit(TileSet::CellNeighbor(i), get_terrain_peering_bit(TileSet::CellNeighbor(i)));
}
}
return output;
@@ -5293,7 +5437,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
- set_peering_bit_terrain(bit, p_value);
+ set_terrain_peering_bit(bit, p_value);
return true;
}
}
@@ -5455,9 +5599,9 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (is_valid_peering_bit_terrain(bit)) {
+ if (is_valid_terrain_peering_bit(bit)) {
property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
- if (get_peering_bit_terrain(bit) == -1) {
+ if (get_terrain_peering_bit(bit) == -1) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
p_list->push_back(property_info);
@@ -5531,8 +5675,10 @@ void TileData::_bind_methods() {
// Terrain
ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
- ClassDB::bind_method(D_METHOD("set_peering_bit_terrain", "peering_bit", "terrain"), &TileData::set_peering_bit_terrain);
- ClassDB::bind_method(D_METHOD("get_peering_bit_terrain", "peering_bit"), &TileData::get_peering_bit_terrain);
+ ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &TileData::set_terrain);
+ ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
+ ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
+ ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
// Navigation
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
@@ -5554,12 +5700,13 @@ void TileData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material");
ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index");
ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin");
ADD_GROUP("Terrains", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain"), "set_terrain", "get_terrain");
ADD_GROUP("Miscellaneous", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 615ab35615..7368d2bd87 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -164,7 +164,7 @@ private:
String name;
Ref<Texture2D> texture;
Vector2 tex_offset;
- Ref<ShaderMaterial> material;
+ Ref<Material> material;
Rect2 region;
int tile_mode = 0;
Color modulate = Color(1, 1, 1);
@@ -265,6 +265,7 @@ public:
class TerrainsPattern {
bool valid = false;
+ int terrain = -1;
int bits[TileSet::CELL_NEIGHBOR_MAX];
bool is_valid_bit[TileSet::CELL_NEIGHBOR_MAX];
@@ -277,11 +278,14 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
- void set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain);
- int get_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ void set_terrain(int p_terrain);
+ int get_terrain() const;
- void set_terrains_from_array(Array p_terrains);
- Array get_terrains_as_array() const;
+ void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain);
+ int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
+
+ void from_array(Array p_terrains);
+ Array as_array() const;
TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set);
TerrainsPattern() {}
@@ -333,7 +337,8 @@ private:
};
Vector<TerrainSet> terrain_sets;
- HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_bits_meshes;
+ HashMap<TerrainMode, Ref<ArrayMesh>> terrain_meshes;
+ HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_peering_bits_meshes;
bool terrain_bits_meshes_dirty = true;
LocalVector<RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>>> per_terrain_pattern_tiles; // Cached data.
@@ -371,17 +376,20 @@ private:
RBMap<Array, Array> alternative_level_proxies;
// Helpers
- Vector<Point2> _get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_terrain_polygon(Vector2i p_size);
+ Vector<Point2> _get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_terrain_polygon(Vector2i p_size);
+ Vector<Point2> _get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- Vector<Point2> _get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- Vector<Point2> _get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ Vector<Point2> _get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ Vector<Point2> _get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
protected:
static void _bind_methods();
@@ -454,8 +462,8 @@ public:
String get_terrain_name(int p_terrain_set, int p_terrain_index) const;
void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color);
Color get_terrain_color(int p_terrain_set, int p_terrain_index) const;
- bool is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
- bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
// Navigation
int get_navigation_layers_count() const;
@@ -516,7 +524,8 @@ public:
Vector<Vector2> get_tile_shape_polygon();
void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
- Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
+ Vector<Point2> get_terrain_polygon(int p_terrain_set);
+ Vector<Point2> get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data);
Vector<Vector<Ref<Texture2D>>> generate_terrains_icons(Size2i p_size);
@@ -774,7 +783,7 @@ private:
bool flip_v = false;
bool transpose = false;
Vector2i tex_offset = Vector2i();
- Ref<ShaderMaterial> material = Ref<ShaderMaterial>();
+ Ref<Material> material = Ref<Material>();
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
int z_index = 0;
int y_sort_origin = 0;
@@ -798,6 +807,7 @@ private:
// Terrain
int terrain_set = -1;
+ int terrain = -1;
int terrain_peering_bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
// Navigation
@@ -854,8 +864,8 @@ public:
void set_texture_offset(Vector2i p_texture_offset);
Vector2i get_texture_offset() const;
- void set_material(Ref<ShaderMaterial> p_material);
- Ref<ShaderMaterial> get_material() const;
+ void set_material(Ref<Material> p_material);
+ Ref<Material> get_material() const;
void set_modulate(Color p_modulate);
Color get_modulate() const;
void set_z_index(int p_z_index);
@@ -887,9 +897,11 @@ public:
// Terrain
void set_terrain_set(int p_terrain_id);
int get_terrain_set() const;
- void set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
- int get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
- bool is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ void set_terrain(int p_terrain_id);
+ int get_terrain() const;
+ void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
+ int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
TileSet::TerrainsPattern get_terrains_pattern() const; // Not exposed.
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 0ab9ef7e16..b8eac6de00 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -712,86 +712,6 @@ VisualShader::VaryingType VisualShader::get_varying_type(const String &p_name) {
return varyings[p_name].type;
}
-void VisualShader::set_engine_version(const Dictionary &p_engine_version) {
- ERR_FAIL_COND(!p_engine_version.has("major"));
- ERR_FAIL_COND(!p_engine_version.has("minor"));
- engine_version["major"] = p_engine_version["major"];
- engine_version["minor"] = p_engine_version["minor"];
-}
-
-Dictionary VisualShader::get_engine_version() const {
- return engine_version;
-}
-
-#ifndef DISABLE_DEPRECATED
-
-void VisualShader::update_engine_version(const Dictionary &p_new_version) {
- if (engine_version.is_empty()) { // before 4.0
- for (int i = 0; i < TYPE_MAX; i++) {
- for (KeyValue<int, Node> &E : graph[i].nodes) {
- Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(E.value.node.ptr());
- if (input.is_valid()) {
- if (input->get_input_name() == "side") {
- input->set_input_name("front_facing");
- }
- }
- Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(E.value.node.ptr());
- if (expression.is_valid()) {
- for (int j = 0; j < expression->get_input_port_count(); j++) {
- int type = expression->get_input_port_type(j);
- if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D
- type += 2;
- }
- expression->set_input_port_type(j, type);
- }
- for (int j = 0; j < expression->get_output_port_count(); j++) {
- int type = expression->get_output_port_type(j);
- if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D
- type += 2;
- }
- expression->set_output_port_type(j, type);
- }
- }
- Ref<VisualShaderNodeStep> step = Object::cast_to<VisualShaderNodeStep>(E.value.node.ptr());
- if (step.is_valid()) {
- int op_type = int(step->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- step->set_op_type(VisualShaderNodeStep::OpType(op_type));
- }
- Ref<VisualShaderNodeSmoothStep> sstep = Object::cast_to<VisualShaderNodeSmoothStep>(E.value.node.ptr());
- if (sstep.is_valid()) {
- int op_type = int(sstep->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- sstep->set_op_type(VisualShaderNodeSmoothStep::OpType(op_type));
- }
- Ref<VisualShaderNodeMix> mix = Object::cast_to<VisualShaderNodeMix>(E.value.node.ptr());
- if (mix.is_valid()) {
- int op_type = int(mix->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- mix->set_op_type(VisualShaderNodeMix::OpType(op_type));
- }
- Ref<VisualShaderNodeCompare> compare = Object::cast_to<VisualShaderNodeCompare>(E.value.node.ptr());
- if (compare.is_valid()) {
- int ctype = int(compare->get_comparison_type());
- if (int(ctype) > 0) { // + CTYPE_SCALAR_INT + CTYPE_VECTOR_2D
- ctype += 2;
- }
- compare->set_comparison_type(VisualShaderNodeCompare::ComparisonType(ctype));
- }
- }
- }
- }
- set_engine_version(p_new_version);
-}
-
-#endif /* DISABLE_DEPRECATED */
-
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_id < 2);
@@ -2628,9 +2548,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
- ClassDB::bind_method(D_METHOD("set_engine_version", "version"), &VisualShader::set_engine_version);
- ClassDB::bind_method(D_METHOD("get_engine_version"), &VisualShader::get_engine_version);
-
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
@@ -2641,7 +2558,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "engine_version", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_engine_version", "get_engine_version");
ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs.
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 925dff31af..afd84e49cc 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -44,8 +44,6 @@ class VisualShader : public Shader {
friend class VisualShaderNodeVersionChecker;
- Dictionary engine_version;
-
public:
enum Type {
TYPE_VERTEX,
@@ -177,14 +175,6 @@ public: // internal methods
void set_shader_type(Type p_type);
Type get_shader_type() const;
-public:
- void set_engine_version(const Dictionary &p_version);
- Dictionary get_engine_version() const;
-
-#ifndef DISABLE_DEPRECATED
- void update_engine_version(const Dictionary &p_new_version);
-#endif /* DISABLE_DEPRECATED */
-
enum {
NODE_ID_INVALID = -1,
NODE_ID_OUTPUT = 0,
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 9d8e0f7547..4dfbe5f079 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -73,8 +73,8 @@ World2D::World2D() {
// Create and configure space2D to be more friendly with pixels than meters
space = PhysicsServer2D::get_singleton()->space_create();
PhysicsServer2D::get_singleton()->space_set_active(space, true);
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 980.0));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1)));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/2d/default_gravity", 980.0));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/2d/default_gravity_vector", Vector2(0, 1)));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/2d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0));
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index eb0af63975..fb6dcd3d57 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -31,7 +31,6 @@
#include "world_3d.h"
#include "core/config/project_settings.h"
-#include "core/math/octree.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/visible_on_screen_notifier_3d.h"
#include "scene/scene_string_names.h"
@@ -141,8 +140,8 @@ World3D::World3D() {
scenario = RenderingServer::get_singleton()->scenario_create();
PhysicsServer3D::get_singleton()->space_set_active(space, true);
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/3d/default_gravity", 9.8));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1));