summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp60
-rw-r--r--scene/resources/animation.h4
-rw-r--r--scene/resources/animation_library.h2
-rw-r--r--scene/resources/audio_stream_wav.cpp (renamed from scene/resources/audio_stream_sample.cpp)170
-rw-r--r--scene/resources/audio_stream_wav.h (renamed from scene/resources/audio_stream_sample.h)38
-rw-r--r--scene/resources/bone_map.cpp181
-rw-r--r--scene/resources/bone_map.h (renamed from scene/resources/scene_replication_config.h)71
-rw-r--r--scene/resources/box_shape_3d.h6
-rw-r--r--scene/resources/capsule_shape_3d.h6
-rw-r--r--scene/resources/concave_polygon_shape_2d.h2
-rw-r--r--scene/resources/concave_polygon_shape_3d.h2
-rw-r--r--scene/resources/convex_polygon_shape_3d.h6
-rw-r--r--scene/resources/cylinder_shape_3d.h2
-rw-r--r--scene/resources/default_theme/default_theme.cpp59
-rw-r--r--scene/resources/default_theme/default_theme.h2
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/environment.h8
-rw-r--r--scene/resources/font.cpp2580
-rw-r--r--scene/resources/font.h328
-rw-r--r--scene/resources/gradient.h8
-rw-r--r--scene/resources/height_map_shape_3d.h6
-rw-r--r--scene/resources/immediate_mesh.h2
-rw-r--r--scene/resources/importer_mesh.h7
-rw-r--r--scene/resources/label_settings.cpp187
-rw-r--r--scene/resources/label_settings.h89
-rw-r--r--scene/resources/material.cpp120
-rw-r--r--scene/resources/material.h13
-rw-r--r--scene/resources/mesh.cpp66
-rw-r--r--scene/resources/mesh.h5
-rw-r--r--scene/resources/mesh_library.cpp2
-rw-r--r--scene/resources/multimesh.h2
-rw-r--r--scene/resources/navigation_mesh.cpp101
-rw-r--r--scene/resources/navigation_mesh.h4
-rw-r--r--scene/resources/packed_scene.cpp8
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--scene/resources/primitive_meshes.cpp118
-rw-r--r--scene/resources/primitive_meshes.h38
-rw-r--r--scene/resources/resource_format_text.cpp174
-rw-r--r--scene/resources/resource_format_text.h8
-rw-r--r--scene/resources/scene_replication_config.cpp205
-rw-r--r--scene/resources/separation_ray_shape_2d.cpp2
-rw-r--r--scene/resources/separation_ray_shape_3d.h8
-rw-r--r--scene/resources/shader.cpp57
-rw-r--r--scene/resources/shader.h10
-rw-r--r--scene/resources/shader_include.cpp144
-rw-r--r--scene/resources/shader_include.h71
-rw-r--r--scene/resources/shape_3d.h2
-rw-r--r--scene/resources/skeleton_modification_2d.h6
-rw-r--r--scene/resources/skeleton_modification_2d_ccdik.h6
-rw-r--r--scene/resources/skeleton_modification_2d_fabrik.h6
-rw-r--r--scene/resources/skeleton_modification_2d_jiggle.h6
-rw-r--r--scene/resources/skeleton_modification_2d_lookat.h6
-rw-r--r--scene/resources/skeleton_modification_2d_physicalbones.h6
-rw-r--r--scene/resources/skeleton_modification_2d_stackholder.h6
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.h6
-rw-r--r--scene/resources/skeleton_modification_3d.h6
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.h6
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.h6
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.h6
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.h6
-rw-r--r--scene/resources/skeleton_modification_3d_stackholder.h6
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.h6
-rw-r--r--scene/resources/skeleton_modification_stack_2d.h6
-rw-r--r--scene/resources/skeleton_modification_stack_3d.h6
-rw-r--r--scene/resources/skeleton_profile.cpp835
-rw-r--r--scene/resources/skeleton_profile.h140
-rw-r--r--scene/resources/sky_material.h2
-rw-r--r--scene/resources/sphere_shape_3d.h2
-rw-r--r--scene/resources/sprite_frames.cpp51
-rw-r--r--scene/resources/sprite_frames.h5
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/surface_tool.h2
-rw-r--r--scene/resources/syntax_highlighter.h2
-rw-r--r--scene/resources/text_file.cpp2
-rw-r--r--scene/resources/text_file.h6
-rw-r--r--scene/resources/text_line.cpp68
-rw-r--r--scene/resources/text_line.h12
-rw-r--r--scene/resources/text_paragraph.cpp167
-rw-r--r--scene/resources/text_paragraph.h18
-rw-r--r--scene/resources/texture.cpp42
-rw-r--r--scene/resources/texture.h7
-rw-r--r--scene/resources/theme.cpp8
-rw-r--r--scene/resources/theme.h2
-rw-r--r--scene/resources/tile_set.cpp105
-rw-r--r--scene/resources/tile_set.h11
-rw-r--r--scene/resources/video_stream.h4
-rw-r--r--scene/resources/visual_shader.cpp65
-rw-r--r--scene/resources/visual_shader.h11
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp6
-rw-r--r--scene/resources/visual_shader_particle_nodes.h2
-rw-r--r--scene/resources/world_3d.cpp1
-rw-r--r--scene/resources/world_boundary_shape_3d.h3
92 files changed, 4630 insertions, 2041 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 7183accc66..69b30b72b0 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1563,33 +1563,35 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
return -1;
}
-void Animation::track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition) {
- ERR_FAIL_INDEX(p_track, tracks.size());
+int Animation::track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition) {
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
+ int ret = -1;
+
switch (t->type) {
case TYPE_POSITION_3D: {
- ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I));
- int idx = position_track_insert_key(p_track, p_time, p_key);
- track_set_key_transition(p_track, idx, p_transition);
+ ERR_FAIL_COND_V((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I), -1);
+ ret = position_track_insert_key(p_track, p_time, p_key);
+ track_set_key_transition(p_track, ret, p_transition);
} break;
case TYPE_ROTATION_3D: {
- ERR_FAIL_COND((p_key.get_type() != Variant::QUATERNION) && (p_key.get_type() != Variant::BASIS));
- int idx = rotation_track_insert_key(p_track, p_time, p_key);
- track_set_key_transition(p_track, idx, p_transition);
+ ERR_FAIL_COND_V((p_key.get_type() != Variant::QUATERNION) && (p_key.get_type() != Variant::BASIS), -1);
+ ret = rotation_track_insert_key(p_track, p_time, p_key);
+ track_set_key_transition(p_track, ret, p_transition);
} break;
case TYPE_SCALE_3D: {
- ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I));
- int idx = scale_track_insert_key(p_track, p_time, p_key);
- track_set_key_transition(p_track, idx, p_transition);
+ ERR_FAIL_COND_V((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I), -1);
+ ret = scale_track_insert_key(p_track, p_time, p_key);
+ track_set_key_transition(p_track, ret, p_transition);
} break;
case TYPE_BLEND_SHAPE: {
- ERR_FAIL_COND((p_key.get_type() != Variant::FLOAT) && (p_key.get_type() != Variant::INT));
- int idx = blend_shape_track_insert_key(p_track, p_time, p_key);
- track_set_key_transition(p_track, idx, p_transition);
+ ERR_FAIL_COND_V((p_key.get_type() != Variant::FLOAT) && (p_key.get_type() != Variant::INT), -1);
+ ret = blend_shape_track_insert_key(p_track, p_time, p_key);
+ track_set_key_transition(p_track, ret, p_transition);
} break;
case TYPE_VALUE: {
@@ -1599,17 +1601,17 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
k.time = p_time;
k.transition = p_transition;
k.value = p_key;
- _insert(p_time, vt->values, k);
+ ret = _insert(p_time, vt->values, k);
} break;
case TYPE_METHOD: {
MethodTrack *mt = static_cast<MethodTrack *>(t);
- ERR_FAIL_COND(p_key.get_type() != Variant::DICTIONARY);
+ ERR_FAIL_COND_V(p_key.get_type() != Variant::DICTIONARY, -1);
Dictionary d = p_key;
- ERR_FAIL_COND(!d.has("method") || (d["method"].get_type() != Variant::STRING_NAME && d["method"].get_type() != Variant::STRING));
- ERR_FAIL_COND(!d.has("args") || !d["args"].is_array());
+ ERR_FAIL_COND_V(!d.has("method") || (d["method"].get_type() != Variant::STRING_NAME && d["method"].get_type() != Variant::STRING), -1);
+ ERR_FAIL_COND_V(!d.has("args") || !d["args"].is_array(), -1);
MethodKey k;
@@ -1618,14 +1620,14 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
k.method = d["method"];
k.params = d["args"];
- _insert(p_time, mt->methods, k);
+ ret = _insert(p_time, mt->methods, k);
} break;
case TYPE_BEZIER: {
BezierTrack *bt = static_cast<BezierTrack *>(t);
Array arr = p_key;
- ERR_FAIL_COND(arr.size() != 6);
+ ERR_FAIL_COND_V(arr.size() != 6, -1);
TKey<BezierKey> k;
k.time = p_time;
@@ -1635,23 +1637,23 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
k.value.out_handle.x = arr[3];
k.value.out_handle.y = arr[4];
k.value.handle_mode = static_cast<HandleMode>((int)arr[5]);
- _insert(p_time, bt->values, k);
+ ret = _insert(p_time, bt->values, k);
} break;
case TYPE_AUDIO: {
AudioTrack *at = static_cast<AudioTrack *>(t);
Dictionary k = p_key;
- ERR_FAIL_COND(!k.has("start_offset"));
- ERR_FAIL_COND(!k.has("end_offset"));
- ERR_FAIL_COND(!k.has("stream"));
+ ERR_FAIL_COND_V(!k.has("start_offset"), -1);
+ ERR_FAIL_COND_V(!k.has("end_offset"), -1);
+ ERR_FAIL_COND_V(!k.has("stream"), -1);
TKey<AudioKey> ak;
ak.time = p_time;
ak.value.start_offset = k["start_offset"];
ak.value.end_offset = k["end_offset"];
ak.value.stream = k["stream"];
- _insert(p_time, at->values, ak);
+ ret = _insert(p_time, at->values, ak);
} break;
case TYPE_ANIMATION: {
@@ -1661,12 +1663,14 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
ak.time = p_time;
ak.value = p_key;
- _insert(p_time, at->values, ak);
+ ret = _insert(p_time, at->values, ak);
} break;
}
emit_changed();
+
+ return ret;
}
int Animation::track_get_key_count(int p_track) const {
@@ -2302,7 +2306,7 @@ Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a
}
Quaternion Animation::_cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const {
- return p_a.cubic_slerp(p_b, p_pre_a, p_post_b, p_c);
+ return p_a.spherical_cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
}
Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const {
@@ -2363,7 +2367,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Quaternion pa = p_pre_a;
Quaternion pb = p_post_b;
- return a.cubic_slerp(b, pa, pb, p_c);
+ return a.spherical_cubic_interpolate(b, pa, pb, p_c);
}
case Variant::AABB: {
AABB a = p_a;
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index b4528ccd3a..bf9f786a0d 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -392,7 +392,7 @@ public:
void track_set_enabled(int p_track, bool p_enabled);
bool track_is_enabled(int p_track) const;
- void track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition = 1);
+ int track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition = 1);
void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition);
void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value);
void track_set_key_time(int p_track, int p_key_idx, double p_time);
@@ -488,4 +488,4 @@ VARIANT_ENUM_CAST(Animation::UpdateMode);
VARIANT_ENUM_CAST(Animation::HandleMode);
VARIANT_ENUM_CAST(Animation::LoopMode);
-#endif
+#endif // ANIMATION_H
diff --git a/scene/resources/animation_library.h b/scene/resources/animation_library.h
index 7a69cd140a..d63807b6d7 100644
--- a/scene/resources/animation_library.h
+++ b/scene/resources/animation_library.h
@@ -63,4 +63,4 @@ public:
AnimationLibrary();
};
-#endif // ANIMATIONLIBRARY_H
+#endif // ANIMATION_LIBRARY_H
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_wav.cpp
index 30c222bdff..a87c8272ea 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* audio_stream_sample.cpp */
+/* audio_stream_wav.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "audio_stream_sample.h"
+#include "audio_stream_wav.h"
#include "core/io/file_access.h"
#include "core/io/marshalls.h"
-void AudioStreamPlaybackSample::start(float p_from_pos) {
- if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) {
+void AudioStreamPlaybackWAV::start(float p_from_pos) {
+ if (base->format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
//no seeking in IMA_ADPCM
for (int i = 0; i < 2; i++) {
ima_adpcm[i].step_index = 0;
@@ -55,24 +55,24 @@ void AudioStreamPlaybackSample::start(float p_from_pos) {
active = true;
}
-void AudioStreamPlaybackSample::stop() {
+void AudioStreamPlaybackWAV::stop() {
active = false;
}
-bool AudioStreamPlaybackSample::is_playing() const {
+bool AudioStreamPlaybackWAV::is_playing() const {
return active;
}
-int AudioStreamPlaybackSample::get_loop_count() const {
+int AudioStreamPlaybackWAV::get_loop_count() const {
return 0;
}
-float AudioStreamPlaybackSample::get_playback_position() const {
+float AudioStreamPlaybackWAV::get_playback_position() const {
return float(offset >> MIX_FRAC_BITS) / base->mix_rate;
}
-void AudioStreamPlaybackSample::seek(float p_time) {
- if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) {
+void AudioStreamPlaybackWAV::seek(float p_time) {
+ if (base->format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
return; //no seeking in ima-adpcm
}
@@ -87,7 +87,7 @@ void AudioStreamPlaybackSample::seek(float p_time) {
}
template <class Depth, bool is_stereo, bool is_ima_adpcm>
-void AudioStreamPlaybackSample::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &offset, int32_t &increment, uint32_t amount, IMA_ADPCM_State *ima_adpcm) {
+void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &offset, int32_t &increment, uint32_t amount, IMA_ADPCM_State *ima_adpcm) {
// this function will be compiled branchless by any decent compiler
int32_t final, final_r, next, next_r;
@@ -124,7 +124,7 @@ void AudioStreamPlaybackSample::do_resample(const Depth *p_src, AudioFrame *p_ds
ima_adpcm[i].last_nibble++;
const uint8_t *src_ptr = (const uint8_t *)base->data;
- src_ptr += AudioStreamSample::DATA_PAD;
+ src_ptr += AudioStreamWAV::DATA_PAD;
uint8_t nbb = src_ptr[(ima_adpcm[i].last_nibble >> 1) * (is_stereo ? 2 : 1) + i];
nibble = (ima_adpcm[i].last_nibble & 1) ? (nbb >> 4) : (nbb & 0xF);
@@ -221,7 +221,7 @@ void AudioStreamPlaybackSample::do_resample(const Depth *p_src, AudioFrame *p_ds
}
}
-int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
if (!base->data || !active) {
for (int i = 0; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0, 0);
@@ -231,13 +231,13 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
int len = base->data_bytes;
switch (base->format) {
- case AudioStreamSample::FORMAT_8_BITS:
+ case AudioStreamWAV::FORMAT_8_BITS:
len /= 1;
break;
- case AudioStreamSample::FORMAT_16_BITS:
+ case AudioStreamWAV::FORMAT_16_BITS:
len /= 2;
break;
- case AudioStreamSample::FORMAT_IMA_ADPCM:
+ case AudioStreamWAV::FORMAT_IMA_ADPCM:
len *= 2;
break;
}
@@ -251,13 +251,13 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
int64_t loop_begin_fp = ((int64_t)base->loop_begin << MIX_FRAC_BITS);
int64_t loop_end_fp = ((int64_t)base->loop_end << MIX_FRAC_BITS);
int64_t length_fp = ((int64_t)len << MIX_FRAC_BITS);
- int64_t begin_limit = (base->loop_mode != AudioStreamSample::LOOP_DISABLED) ? loop_begin_fp : 0;
- int64_t end_limit = (base->loop_mode != AudioStreamSample::LOOP_DISABLED) ? loop_end_fp : length_fp;
+ int64_t begin_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_begin_fp : 0;
+ int64_t end_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_end_fp : length_fp;
bool is_stereo = base->stereo;
int32_t todo = p_frames;
- if (base->loop_mode == AudioStreamSample::LOOP_BACKWARD) {
+ if (base->loop_mode == AudioStreamWAV::LOOP_BACKWARD) {
sign = -1;
}
@@ -271,20 +271,20 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
//looping
- AudioStreamSample::LoopMode loop_format = base->loop_mode;
- AudioStreamSample::Format format = base->format;
+ AudioStreamWAV::LoopMode loop_format = base->loop_mode;
+ AudioStreamWAV::Format format = base->format;
/* audio data */
uint8_t *dataptr = (uint8_t *)base->data;
- const void *data = dataptr + AudioStreamSample::DATA_PAD;
+ const void *data = dataptr + AudioStreamWAV::DATA_PAD;
AudioFrame *dst_buff = p_buffer;
- if (format == AudioStreamSample::FORMAT_IMA_ADPCM) {
- if (loop_format != AudioStreamSample::LOOP_DISABLED) {
+ if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
+ if (loop_format != AudioStreamWAV::LOOP_DISABLED) {
ima_adpcm[0].loop_pos = loop_begin_fp >> MIX_FRAC_BITS;
ima_adpcm[1].loop_pos = loop_begin_fp >> MIX_FRAC_BITS;
- loop_format = AudioStreamSample::LOOP_FORWARD;
+ loop_format = AudioStreamWAV::LOOP_FORWARD;
}
}
@@ -297,9 +297,9 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
if (increment < 0) {
/* going backwards */
- if (loop_format != AudioStreamSample::LOOP_DISABLED && offset < loop_begin_fp) {
+ if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset < loop_begin_fp) {
/* loopstart reached */
- if (loop_format == AudioStreamSample::LOOP_PINGPONG) {
+ if (loop_format == AudioStreamWAV::LOOP_PINGPONG) {
/* bounce ping pong */
offset = loop_begin_fp + (loop_begin_fp - offset);
increment = -increment;
@@ -317,10 +317,10 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
}
} else {
/* going forward */
- if (loop_format != AudioStreamSample::LOOP_DISABLED && offset >= loop_end_fp) {
+ if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset >= loop_end_fp) {
/* loopend reached */
- if (loop_format == AudioStreamSample::LOOP_PINGPONG) {
+ if (loop_format == AudioStreamWAV::LOOP_PINGPONG) {
/* bounce ping pong */
offset = loop_end_fp - (offset - loop_end_fp);
increment = -increment;
@@ -328,7 +328,7 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
} else {
/* go to loop-begin */
- if (format == AudioStreamSample::FORMAT_IMA_ADPCM) {
+ if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
for (int i = 0; i < 2; i++) {
ima_adpcm[i].step_index = ima_adpcm[i].loop_step_index;
ima_adpcm[i].predictor = ima_adpcm[i].loop_predictor;
@@ -366,14 +366,14 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
todo -= target;
switch (base->format) {
- case AudioStreamSample::FORMAT_8_BITS: {
+ case AudioStreamWAV::FORMAT_8_BITS: {
if (is_stereo) {
do_resample<int8_t, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
} else {
do_resample<int8_t, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
}
} break;
- case AudioStreamSample::FORMAT_16_BITS: {
+ case AudioStreamWAV::FORMAT_16_BITS: {
if (is_stereo) {
do_resample<int16_t, true, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm);
} else {
@@ -381,7 +381,7 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
}
} break;
- case AudioStreamSample::FORMAT_IMA_ADPCM: {
+ case AudioStreamWAV::FORMAT_IMA_ADPCM: {
if (is_stereo) {
do_resample<int8_t, true, true>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
} else {
@@ -406,69 +406,73 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int
return p_frames;
}
-AudioStreamPlaybackSample::AudioStreamPlaybackSample() {}
+void AudioStreamPlaybackWAV::tag_used_streams() {
+ base->tag_used(get_playback_position());
+}
+
+AudioStreamPlaybackWAV::AudioStreamPlaybackWAV() {}
/////////////////////
-void AudioStreamSample::set_format(Format p_format) {
+void AudioStreamWAV::set_format(Format p_format) {
format = p_format;
}
-AudioStreamSample::Format AudioStreamSample::get_format() const {
+AudioStreamWAV::Format AudioStreamWAV::get_format() const {
return format;
}
-void AudioStreamSample::set_loop_mode(LoopMode p_loop_mode) {
+void AudioStreamWAV::set_loop_mode(LoopMode p_loop_mode) {
loop_mode = p_loop_mode;
}
-AudioStreamSample::LoopMode AudioStreamSample::get_loop_mode() const {
+AudioStreamWAV::LoopMode AudioStreamWAV::get_loop_mode() const {
return loop_mode;
}
-void AudioStreamSample::set_loop_begin(int p_frame) {
+void AudioStreamWAV::set_loop_begin(int p_frame) {
loop_begin = p_frame;
}
-int AudioStreamSample::get_loop_begin() const {
+int AudioStreamWAV::get_loop_begin() const {
return loop_begin;
}
-void AudioStreamSample::set_loop_end(int p_frame) {
+void AudioStreamWAV::set_loop_end(int p_frame) {
loop_end = p_frame;
}
-int AudioStreamSample::get_loop_end() const {
+int AudioStreamWAV::get_loop_end() const {
return loop_end;
}
-void AudioStreamSample::set_mix_rate(int p_hz) {
+void AudioStreamWAV::set_mix_rate(int p_hz) {
ERR_FAIL_COND(p_hz == 0);
mix_rate = p_hz;
}
-int AudioStreamSample::get_mix_rate() const {
+int AudioStreamWAV::get_mix_rate() const {
return mix_rate;
}
-void AudioStreamSample::set_stereo(bool p_enable) {
+void AudioStreamWAV::set_stereo(bool p_enable) {
stereo = p_enable;
}
-bool AudioStreamSample::is_stereo() const {
+bool AudioStreamWAV::is_stereo() const {
return stereo;
}
-float AudioStreamSample::get_length() const {
+float AudioStreamWAV::get_length() const {
int len = data_bytes;
switch (format) {
- case AudioStreamSample::FORMAT_8_BITS:
+ case AudioStreamWAV::FORMAT_8_BITS:
len /= 1;
break;
- case AudioStreamSample::FORMAT_16_BITS:
+ case AudioStreamWAV::FORMAT_16_BITS:
len /= 2;
break;
- case AudioStreamSample::FORMAT_IMA_ADPCM:
+ case AudioStreamWAV::FORMAT_IMA_ADPCM:
len *= 2;
break;
}
@@ -480,11 +484,11 @@ float AudioStreamSample::get_length() const {
return float(len) / mix_rate;
}
-bool AudioStreamSample::is_monophonic() const {
+bool AudioStreamWAV::is_monophonic() const {
return false;
}
-void AudioStreamSample::set_data(const Vector<uint8_t> &p_data) {
+void AudioStreamWAV::set_data(const Vector<uint8_t> &p_data) {
AudioServer::get_singleton()->lock();
if (data) {
memfree(data);
@@ -506,7 +510,7 @@ void AudioStreamSample::set_data(const Vector<uint8_t> &p_data) {
AudioServer::get_singleton()->unlock();
}
-Vector<uint8_t> AudioStreamSample::get_data() const {
+Vector<uint8_t> AudioStreamWAV::get_data() const {
Vector<uint8_t> pv;
if (data) {
@@ -521,8 +525,8 @@ Vector<uint8_t> AudioStreamSample::get_data() const {
return pv;
}
-Error AudioStreamSample::save_to_wav(const String &p_path) {
- if (format == AudioStreamSample::FORMAT_IMA_ADPCM) {
+Error AudioStreamWAV::save_to_wav(const String &p_path) {
+ if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
WARN_PRINT("Saving IMA_ADPC samples are not supported yet");
return ERR_UNAVAILABLE;
}
@@ -540,13 +544,13 @@ Error AudioStreamSample::save_to_wav(const String &p_path) {
int byte_pr_sample = 0;
switch (format) {
- case AudioStreamSample::FORMAT_8_BITS:
+ case AudioStreamWAV::FORMAT_8_BITS:
byte_pr_sample = 1;
break;
- case AudioStreamSample::FORMAT_16_BITS:
+ case AudioStreamWAV::FORMAT_16_BITS:
byte_pr_sample = 2;
break;
- case AudioStreamSample::FORMAT_IMA_ADPCM:
+ case AudioStreamWAV::FORMAT_IMA_ADPCM:
byte_pr_sample = 4;
break;
}
@@ -579,19 +583,19 @@ Error AudioStreamSample::save_to_wav(const String &p_path) {
Vector<uint8_t> data = get_data();
const uint8_t *read_data = data.ptr();
switch (format) {
- case AudioStreamSample::FORMAT_8_BITS:
+ case AudioStreamWAV::FORMAT_8_BITS:
for (unsigned int i = 0; i < data_bytes; i++) {
uint8_t data_point = (read_data[i] + 128);
file->store_8(data_point);
}
break;
- case AudioStreamSample::FORMAT_16_BITS:
+ case AudioStreamWAV::FORMAT_16_BITS:
for (unsigned int i = 0; i < data_bytes / 2; i++) {
uint16_t data_point = decode_uint16(&read_data[i * 2]);
file->store_16(data_point);
}
break;
- case AudioStreamSample::FORMAT_IMA_ADPCM:
+ case AudioStreamWAV::FORMAT_IMA_ADPCM:
//Unimplemented
break;
}
@@ -599,40 +603,40 @@ Error AudioStreamSample::save_to_wav(const String &p_path) {
return OK;
}
-Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() {
- Ref<AudioStreamPlaybackSample> sample;
+Ref<AudioStreamPlayback> AudioStreamWAV::instantiate_playback() {
+ Ref<AudioStreamPlaybackWAV> sample;
sample.instantiate();
- sample->base = Ref<AudioStreamSample>(this);
+ sample->base = Ref<AudioStreamWAV>(this);
return sample;
}
-String AudioStreamSample::get_stream_name() const {
+String AudioStreamWAV::get_stream_name() const {
return "";
}
-void AudioStreamSample::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamSample::set_data);
- ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamSample::get_data);
+void AudioStreamWAV::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamWAV::set_data);
+ ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamWAV::get_data);
- ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioStreamSample::set_format);
- ClassDB::bind_method(D_METHOD("get_format"), &AudioStreamSample::get_format);
+ ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioStreamWAV::set_format);
+ ClassDB::bind_method(D_METHOD("get_format"), &AudioStreamWAV::get_format);
- ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AudioStreamSample::set_loop_mode);
- ClassDB::bind_method(D_METHOD("get_loop_mode"), &AudioStreamSample::get_loop_mode);
+ ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AudioStreamWAV::set_loop_mode);
+ ClassDB::bind_method(D_METHOD("get_loop_mode"), &AudioStreamWAV::get_loop_mode);
- ClassDB::bind_method(D_METHOD("set_loop_begin", "loop_begin"), &AudioStreamSample::set_loop_begin);
- ClassDB::bind_method(D_METHOD("get_loop_begin"), &AudioStreamSample::get_loop_begin);
+ ClassDB::bind_method(D_METHOD("set_loop_begin", "loop_begin"), &AudioStreamWAV::set_loop_begin);
+ ClassDB::bind_method(D_METHOD("get_loop_begin"), &AudioStreamWAV::get_loop_begin);
- ClassDB::bind_method(D_METHOD("set_loop_end", "loop_end"), &AudioStreamSample::set_loop_end);
- ClassDB::bind_method(D_METHOD("get_loop_end"), &AudioStreamSample::get_loop_end);
+ ClassDB::bind_method(D_METHOD("set_loop_end", "loop_end"), &AudioStreamWAV::set_loop_end);
+ ClassDB::bind_method(D_METHOD("get_loop_end"), &AudioStreamWAV::get_loop_end);
- ClassDB::bind_method(D_METHOD("set_mix_rate", "mix_rate"), &AudioStreamSample::set_mix_rate);
- ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamSample::get_mix_rate);
+ ClassDB::bind_method(D_METHOD("set_mix_rate", "mix_rate"), &AudioStreamWAV::set_mix_rate);
+ ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamWAV::get_mix_rate);
- ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamSample::set_stereo);
- ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamSample::is_stereo);
+ ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamWAV::set_stereo);
+ ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamWAV::is_stereo);
- ClassDB::bind_method(D_METHOD("save_to_wav", "path"), &AudioStreamSample::save_to_wav);
+ ClassDB::bind_method(D_METHOD("save_to_wav", "path"), &AudioStreamWAV::save_to_wav);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_data", "get_data");
ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format");
@@ -652,9 +656,9 @@ void AudioStreamSample::_bind_methods() {
BIND_ENUM_CONSTANT(LOOP_BACKWARD);
}
-AudioStreamSample::AudioStreamSample() {}
+AudioStreamWAV::AudioStreamWAV() {}
-AudioStreamSample::~AudioStreamSample() {
+AudioStreamWAV::~AudioStreamWAV() {
if (data) {
memfree(data);
data = nullptr;
diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_wav.h
index 357febc27a..d800388d96 100644
--- a/scene/resources/audio_stream_sample.h
+++ b/scene/resources/audio_stream_wav.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* audio_stream_sample.h */
+/* audio_stream_wav.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AUDIO_STREAM_SAMPLE_H
-#define AUDIO_STREAM_SAMPLE_H
+#ifndef AUDIO_STREAM_WAV_H
+#define AUDIO_STREAM_WAV_H
#include "servers/audio/audio_stream.h"
-class AudioStreamSample;
+class AudioStreamWAV;
-class AudioStreamPlaybackSample : public AudioStreamPlayback {
- GDCLASS(AudioStreamPlaybackSample, AudioStreamPlayback);
+class AudioStreamPlaybackWAV : public AudioStreamPlayback {
+ GDCLASS(AudioStreamPlaybackWAV, AudioStreamPlayback);
enum {
MIX_FRAC_BITS = 13,
MIX_FRAC_LEN = (1 << MIX_FRAC_BITS),
@@ -57,8 +57,8 @@ class AudioStreamPlaybackSample : public AudioStreamPlayback {
int64_t offset = 0;
int sign = 1;
bool active = false;
- friend class AudioStreamSample;
- Ref<AudioStreamSample> base;
+ friend class AudioStreamWAV;
+ Ref<AudioStreamWAV> base;
template <class Depth, bool is_stereo, bool is_ima_adpcm>
void do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &offset, int32_t &increment, uint32_t amount, IMA_ADPCM_State *ima_adpcm);
@@ -75,11 +75,13 @@ public:
virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
- AudioStreamPlaybackSample();
+ virtual void tag_used_streams() override;
+
+ AudioStreamPlaybackWAV();
};
-class AudioStreamSample : public AudioStream {
- GDCLASS(AudioStreamSample, AudioStream);
+class AudioStreamWAV : public AudioStream {
+ GDCLASS(AudioStreamWAV, AudioStream);
RES_BASE_EXTENSION("sample")
public:
@@ -98,7 +100,7 @@ public:
};
private:
- friend class AudioStreamPlaybackSample;
+ friend class AudioStreamPlaybackWAV;
enum {
DATA_PAD = 16 //padding for interpolation
@@ -144,14 +146,14 @@ public:
Error save_to_wav(const String &p_path);
- virtual Ref<AudioStreamPlayback> instance_playback() override;
+ virtual Ref<AudioStreamPlayback> instantiate_playback() override;
virtual String get_stream_name() const override;
- AudioStreamSample();
- ~AudioStreamSample();
+ AudioStreamWAV();
+ ~AudioStreamWAV();
};
-VARIANT_ENUM_CAST(AudioStreamSample::Format)
-VARIANT_ENUM_CAST(AudioStreamSample::LoopMode)
+VARIANT_ENUM_CAST(AudioStreamWAV::Format)
+VARIANT_ENUM_CAST(AudioStreamWAV::LoopMode)
-#endif // AUDIO_STREAM_SAMPLE_H
+#endif // AUDIO_STREAM_WAV_H
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
new file mode 100644
index 0000000000..aff917b2d4
--- /dev/null
+++ b/scene/resources/bone_map.cpp
@@ -0,0 +1,181 @@
+/*************************************************************************/
+/* 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;
+}
+
+void BoneMap::_get_property_list(List<PropertyInfo> *p_list) const {
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_map/" + E->key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ ++E;
+ }
+}
+
+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_ARRAY("bonemap", "bonemap");
+
+ 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/scene_replication_config.h b/scene/resources/bone_map.h
index ab3658d2a7..17452dfc73 100644
--- a/scene/resources/scene_replication_config.h
+++ b/scene/resources/bone_map.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scene_replication_config.h */
+/* bone_map.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,64 +28,43 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_REPLICATION_CONFIG_H
-#define SCENE_REPLICATION_CONFIG_H
+#ifndef BONE_MAP_H
+#define BONE_MAP_H
-#include "core/io/resource.h"
+#include "skeleton_profile.h"
-#include "core/variant/typed_array.h"
+class BoneMap : public Resource {
+ GDCLASS(BoneMap, Resource);
-class SceneReplicationConfig : public Resource {
- GDCLASS(SceneReplicationConfig, Resource);
- OBJ_SAVE_TYPE(SceneReplicationConfig);
- RES_BASE_EXTENSION("repl");
+ Ref<SkeletonProfile> profile;
+ HashMap<StringName, StringName> bone_map;
-private:
- struct ReplicationProperty {
- NodePath name;
- bool spawn = true;
- bool sync = true;
-
- bool operator==(const ReplicationProperty &p_to) {
- return name == p_to.name;
- }
-
- ReplicationProperty() {}
-
- ReplicationProperty(const NodePath &p_name) {
- name = p_name;
- }
- };
-
- List<ReplicationProperty> properties;
- List<NodePath> spawn_props;
- List<NodePath> sync_props;
+ void _update_profile();
+ void _validate_bone_map();
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;
+ 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:
- TypedArray<NodePath> get_properties() const;
+ int get_profile_type() const;
+ void set_profile_type(const int p_profile_type);
- void add_property(const NodePath &p_path, int p_index = -1);
- void remove_property(const NodePath &p_path);
- bool has_property(const NodePath &p_path) const;
+ Ref<SkeletonProfile> get_profile() const;
+ void set_profile(const Ref<SkeletonProfile> &p_profile);
- int property_get_index(const NodePath &p_path) const;
- bool property_get_spawn(const NodePath &p_path);
- void property_set_spawn(const NodePath &p_path, bool p_enabled);
+ int get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const;
- bool property_get_sync(const NodePath &p_path);
- void property_set_sync(const NodePath &p_path, bool p_enabled);
+ 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);
- const List<NodePath> &get_spawn_properties() { return spawn_props; }
- const List<NodePath> &get_sync_properties() { return sync_props; }
+ StringName find_profile_bone_name(StringName p_skeleton_bone_name) const;
- SceneReplicationConfig() {}
+ BoneMap();
+ ~BoneMap();
};
-#endif // SCENE_REPLICATION_CONFIG_H
+#endif // BONE_MAP_H
diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h
index 4e6db893af..3dd0bb6cb7 100644
--- a/scene/resources/box_shape_3d.h
+++ b/scene/resources/box_shape_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BOX_SHAPE_H
-#define BOX_SHAPE_H
+#ifndef BOX_SHAPE_3D_H
+#define BOX_SHAPE_3D_H
#include "scene/resources/shape_3d.h"
@@ -56,4 +56,4 @@ public:
BoxShape3D();
};
-#endif // BOX_SHAPE_H
+#endif // BOX_SHAPE_3D_H
diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h
index 4c039ab326..ad7f2e5b74 100644
--- a/scene/resources/capsule_shape_3d.h
+++ b/scene/resources/capsule_shape_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CAPSULE_SHAPE_H
-#define CAPSULE_SHAPE_H
+#ifndef CAPSULE_SHAPE_3D_H
+#define CAPSULE_SHAPE_3D_H
#include "scene/resources/shape_3d.h"
@@ -55,4 +55,4 @@ public:
CapsuleShape3D();
};
-#endif // CAPSULE_SHAPE_H
+#endif // CAPSULE_SHAPE_3D_H
diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h
index 0f49a0d80f..d350d753b0 100644
--- a/scene/resources/concave_polygon_shape_2d.h
+++ b/scene/resources/concave_polygon_shape_2d.h
@@ -52,4 +52,4 @@ public:
ConcavePolygonShape2D();
};
-#endif
+#endif // CONCAVE_POLYGON_SHAPE_2D_H
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index a265590edd..68feacfa25 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -77,4 +77,4 @@ public:
ConcavePolygonShape3D();
};
-#endif // CONCAVE_POLYGON_SHAPE_H
+#endif // CONCAVE_POLYGON_SHAPE_3D_H
diff --git a/scene/resources/convex_polygon_shape_3d.h b/scene/resources/convex_polygon_shape_3d.h
index 930edb015d..5ca4d2a713 100644
--- a/scene/resources/convex_polygon_shape_3d.h
+++ b/scene/resources/convex_polygon_shape_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CONVEX_POLYGON_SHAPE_H
-#define CONVEX_POLYGON_SHAPE_H
+#ifndef CONVEX_POLYGON_SHAPE_3D_H
+#define CONVEX_POLYGON_SHAPE_3D_H
#include "scene/resources/shape_3d.h"
@@ -52,4 +52,4 @@ public:
ConvexPolygonShape3D();
};
-#endif // CONVEX_POLYGON_SHAPE_H
+#endif // CONVEX_POLYGON_SHAPE_3D_H
diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h
index 65427423c8..f554358044 100644
--- a/scene/resources/cylinder_shape_3d.h
+++ b/scene/resources/cylinder_shape_3d.h
@@ -54,4 +54,4 @@ public:
CylinderShape3D();
};
-#endif // CYLINDER_SHAPE_H
+#endif // CYLINDER_SHAPE_3D_H
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 401aeb4889..520a0a04ed 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -76,7 +76,6 @@ static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float
// See also `editor_generate_icon()` in `editor/editor_themes.cpp`.
static Ref<ImageTexture> generate_icon(int p_index) {
- Ref<ImageTexture> icon = memnew(ImageTexture);
Ref<Image> img = memnew(Image);
#ifdef MODULE_SVG_ENABLED
@@ -87,9 +86,8 @@ static Ref<ImageTexture> generate_icon(int p_index) {
ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false);
#endif
- icon->create_from_image(img);
- return icon;
+ return ImageTexture::create_from_image(img);
}
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
@@ -467,6 +465,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));
@@ -917,8 +916,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));
@@ -938,7 +937,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);
@@ -1033,9 +1031,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()) {
@@ -1045,48 +1043,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/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index f777330a07..9b070a90cc 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -39,4 +39,4 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, bool p_font_antialiased = true, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
void clear_default_theme();
-#endif
+#endif // DEFAULT_THEME_H
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 854bd34d6a..a8d4903dad 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1423,7 +1423,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_fog_light_energy", "get_fog_light_energy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_scatter", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_fog_sun_scatter", "get_fog_sun_scatter");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_fog_density", "get_fog_density");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater,suffix:m"), "set_fog_height", "get_fog_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_lesser,or_greater"), "set_fog_height_density", "get_fog_height_density");
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index b71fe8904a..385d815230 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -175,10 +175,10 @@ private:
// Fog
bool fog_enabled = false;
- Color fog_light_color = Color(0.5, 0.6, 0.7);
+ Color fog_light_color = Color(0.518, 0.553, 0.608);
float fog_light_energy = 1.0;
float fog_sun_scatter = 0.0;
- float fog_density = 0.001;
+ float fog_density = 0.01;
float fog_height = 0.0;
float fog_height_density = 0.0; //can be negative to invert effect
float fog_aerial_perspective = 0.0;
@@ -194,8 +194,8 @@ private:
float volumetric_fog_anisotropy = 0.2;
float volumetric_fog_length = 64.0;
float volumetric_fog_detail_spread = 2.0;
- float volumetric_fog_gi_inject = 0.0;
- float volumetric_fog_ambient_inject = false;
+ float volumetric_fog_gi_inject = 1.0;
+ float volumetric_fog_ambient_inject = 0.0;
bool volumetric_fog_temporal_reproject = true;
float volumetric_fog_temporal_reproject_amount = 0.9;
void _update_volumetric_fog();
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 46f23424dd..619036d296 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,558 @@
#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);
+
+ // 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("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("get_spacing", "spacing"), &Font::get_spacing);
+ ClassDB::bind_method(D_METHOD("get_opentype_features"), &Font::get_opentype_features);
+
+ // Drawing string.
+ ClassDB::bind_method(D_METHOD("set_cache_capacity", "single_line", "multi_line"), &Font::set_cache_capacity);
-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);
+ ClassDB::bind_method(D_METHOD("get_string_size", "text", "alignment", "width", "font_size", "jst_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", "brk_flags", "jst_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::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
- 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("draw_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "modulate", "jst_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", "brk_flags", "jst_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), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
- 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("draw_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "size", "modulate", "jst_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", "brk_flags", "jst_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), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
- ClassDB::bind_method(D_METHOD("get_face_count"), &FontData::get_face_count);
+ // Drawing char.
+ ClassDB::bind_method(D_METHOD("get_char_size", "char", "font_size"), &Font::get_char_size);
+ ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "font_size", "modulate"), &Font::draw_char, DEFVAL(Color(1.0, 1.0, 1.0)));
+ ClassDB::bind_method(D_METHOD("draw_char_outline", "canvas_item", "pos", "char", "font_size", "size", "modulate"), &Font::draw_char_outline, DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)));
- ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
- ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
+ // 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_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("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_font_name", "name"), &FontData::set_font_name);
- ClassDB::bind_method(D_METHOD("get_font_name"), &FontData::get_font_name);
+ 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);
+}
- 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);
+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;
+}
- 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);
+void Font::_invalidate_rids() {
+ rids.clear();
+ dirty_rids = true;
- 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);
+ cache.clear();
+ cache_wrap.clear();
- 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);
+ emit_changed();
+}
- 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);
+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), CONNECT_REFERENCE_COUNTED);
+ }
+ }
+ _invalidate_rids();
+}
+
+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);
+BitField<TextServer::FontStyle> 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, BitField<TextServer::JustificationFlag> p_jst_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_jst_flags.operator uint32_t(), 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);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_horizontal_alignment(p_alignment);
+ buffer->set_width(p_width);
+ buffer->set_flags(p_jst_flags);
+ }
+ 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, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_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_brk_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), 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_break_flags(p_brk_flags);
+ lines_buffer->set_justification_flags(p_jst_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, BitField<TextServer::JustificationFlag> p_jst_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_jst_flags.operator uint32_t(), hash);
+ }
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, 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);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_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, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_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_brk_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), 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_break_flags(p_brk_flags);
+ lines_buffer->set_justification_flags(p_jst_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, BitField<TextServer::JustificationFlag> p_jst_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_jst_flags.operator uint32_t(), hash);
+ }
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, 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);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_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, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_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_brk_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), 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_break_flags(p_brk_flags);
+ lines_buffer->set_justification_flags(p_jst_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();
+}
+
+/*************************************************************************/
+/* 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();
+ }
+ }
}
-void FontData::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) {
+_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 +636,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 +736,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 +792,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 +821,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 +864,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_FLAGS, "Bold,Italic,Fixed Size", 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;
@@ -763,7 +1351,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
int height = 0;
int ascent = 0;
int outline = 0;
- uint32_t st_flags = 0;
+ BitField<TextServer::FontStyle> st_flags = 0;
String font_name;
bool packed = false;
@@ -789,10 +1377,10 @@ Error FontData::load_bitmap_font(const String &p_path) {
uint8_t flags = f->get_8();
ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
if (flags & (1 << 3)) {
- st_flags |= TextServer::FONT_BOLD;
+ st_flags.set_flag(TextServer::FONT_BOLD);
}
if (flags & (1 << 2)) {
- st_flags |= TextServer::FONT_ITALIC;
+ st_flags.set_flag(TextServer::FONT_ITALIC);
}
f->get_8(); // non-unicode charset, skip
f->get_16(); // stretch_h, skip
@@ -1019,12 +1607,12 @@ Error FontData::load_bitmap_font(const String &p_path) {
}
if (keys.has("bold")) {
if (keys["bold"].to_int()) {
- st_flags |= TextServer::FONT_BOLD;
+ st_flags.set_flag(TextServer::FONT_BOLD);
}
}
if (keys.has("italic")) {
if (keys["italic"].to_int()) {
- st_flags |= TextServer::FONT_ITALIC;
+ st_flags.set_flag(TextServer::FONT_ITALIC);
}
}
if (keys.has("face")) {
@@ -1209,13 +1797,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 +1812,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 +1826,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 +1840,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 +1849,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(BitField<TextServer::FontStyle> 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 +1875,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 +1890,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 +1905,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 +1920,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 +1935,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 +1950,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 +1965,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 +1980,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 +1995,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 +2010,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 +2059,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 +2089,978 @@ 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);
+ ADD_GROUP("OpenType Features", "opentype");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_features"), "set_opentype_features", "get_opentype_features");
- ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids);
+ 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::_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;
+void FontVariation::_update_rids() const {
+ Ref<Font> f = _get_base_font_or_default();
+
+ rids.clear();
+ if (fallbacks.is_empty() && f.is_valid()) {
+ RID rid = _get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
}
- 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;
+
+ 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);
}
- return false;
+ dirty_rids = false;
}
-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::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();
+ }
- if (idx == data.size()) {
- r_ret = Ref<FontData>();
- return true;
- } else if (idx >= 0 && idx < data.size()) {
- r_ret = get_data(idx);
- return true;
- }
+ 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 false;
-}
+ variation = Variation();
+ opentype_features = Dictionary();
-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"));
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ extra_spacing[i] = 0;
}
- p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
+
+ Font::reset_state();
}
-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::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), CONNECT_REFERENCE_COUNTED);
}
+ _invalidate_rids();
+ notify_property_list_changed();
}
- cache.clear();
- cache_wrap.clear();
- data.clear();
- rids.clear();
+}
- variation_coordinates.clear();
- spacing_bottom = 0;
- spacing_top = 0;
+Ref<Font> FontVariation::get_base_font() const {
+ return base_font;
}
-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];
- }
+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();
+ }
+
+ if (base_font.is_valid()) {
+ return base_font;
}
- 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());
+ // 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);
- 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 (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), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
}
}
- cache.clear();
- cache_wrap.clear();
-
- emit_changed();
- notify_property_list_changed();
-}
-
-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));
- }
+ // 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);
- 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;
+ 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), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
+ }
}
- }
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
+ // 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), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
- cache.clear();
- cache_wrap.clear();
+ return Ref<Font>();
+}
- emit_changed();
- notify_property_list_changed();
+void FontVariation::set_variation_opentype(const Dictionary &p_coords) {
+ if (variation.opentype != p_coords) {
+ variation.opentype = p_coords;
+ _invalidate_rids();
+ }
}
-int Font::get_data_count() const {
- return data.size();
+Dictionary FontVariation::get_variation_opentype() const {
+ return variation.opentype;
}
-Ref<FontData> Font::get_data(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, data.size(), Ref<FontData>());
- return data[p_idx];
+void FontVariation::set_variation_embolden(float p_strength) {
+ if (variation.embolden != p_strength) {
+ variation.embolden = p_strength;
+ _invalidate_rids();
+ }
}
-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];
+float FontVariation::get_variation_embolden() const {
+ return variation.embolden;
}
-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);
- }
+void FontVariation::set_variation_transform(Transform2D p_transform) {
+ if (variation.transform != p_transform) {
+ variation.transform = p_transform;
+ _invalidate_rids();
}
- data.clear();
- rids.clear();
}
-void Font::remove_data(int p_idx) {
- ERR_FAIL_INDEX(p_idx, data.size());
+Transform2D FontVariation::get_variation_transform() const {
+ return variation.transform;
+}
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
+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();
}
-
- data.remove_at(p_idx);
- rids.remove_at(p_idx);
-
- cache.clear();
- cache_wrap.clear();
-
- emit_changed();
- notify_property_list_changed();
}
-void Font::set_variation_coordinates(const Dictionary &p_variation_coordinates) {
- _data_changed();
- variation_coordinates = p_variation_coordinates;
+int FontVariation::get_variation_face_index() const {
+ return variation.face_index;
}
-Dictionary Font::get_variation_coordinates() const {
- return variation_coordinates;
+void FontVariation::set_opentype_features(const Dictionary &p_features) {
+ if (opentype_features != p_features) {
+ opentype_features = p_features;
+ _invalidate_rids();
+ }
}
-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;
- }
+Dictionary FontVariation::get_opentype_features() const {
+ return opentype_features;
}
-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;
+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();
}
}
-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));
- }
- return ret + spacing_bottom + spacing_top;
+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];
}
-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));
+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 ret + spacing_top;
+ return RID();
}
-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));
+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 ret + spacing_bottom;
+ return RID();
}
-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));
+FontVariation::FontVariation() {
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ extra_spacing[i] = 0;
}
- return ret + spacing_top;
}
-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));
- }
- return ret;
+FontVariation::~FontVariation() {
+ reset_state();
}
-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());
+/*************************************************************************/
+/* SystemFont */
+/*************************************************************************/
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
+void SystemFont::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &SystemFont::set_antialiased);
+ ClassDB::bind_method(D_METHOD("is_antialiased"), &SystemFont::is_antialiased);
- uint64_t hash = p_text.hash64();
- 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_size, hash);
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &SystemFont::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &SystemFont::get_generate_mipmaps);
- Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
+ ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &SystemFont::set_force_autohinter);
+ ClassDB::bind_method(D_METHOD("is_force_autohinter"), &SystemFont::is_force_autohinter);
+
+ ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &SystemFont::set_hinting);
+ ClassDB::bind_method(D_METHOD("get_hinting"), &SystemFont::get_hinting);
+
+ ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &SystemFont::set_subpixel_positioning);
+ ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &SystemFont::get_subpixel_positioning);
+
+ ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &SystemFont::set_oversampling);
+ ClassDB::bind_method(D_METHOD("get_oversampling"), &SystemFont::get_oversampling);
+
+ ClassDB::bind_method(D_METHOD("get_font_names"), &SystemFont::get_font_names);
+ ClassDB::bind_method(D_METHOD("set_font_names", "names"), &SystemFont::set_font_names);
+
+ ClassDB::bind_method(D_METHOD("set_font_style", "style"), &SystemFont::set_font_style);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "font_names"), "set_font_names", "get_font_names");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic"), "set_font_style", "get_font_style");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "is_antialiased");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "get_generate_mipmaps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), "set_subpixel_positioning", "get_subpixel_positioning");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), "set_oversampling", "get_oversampling");
+ 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");
+}
+
+void SystemFont::_update_rids() const {
+ Ref<Font> f = _get_base_font_or_default();
+
+ rids.clear();
+ if (fallbacks.is_empty() && f.is_valid()) {
+ RID rid = _get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
+ }
+
+ 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 {
- buffer.instantiate();
- buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- cache.insert(hash, buffer);
+ _update_rids_fb(const_cast<SystemFont *>(this), 0);
}
- return buffer->get_size();
+ dirty_rids = false;
}
-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 SystemFont::_update_base_font() {
+ if (base_font.is_valid()) {
+ base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font.unref();
}
- uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_murmur3_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);
+ face_indeces.clear();
+ ftr_weight = 0;
+ ftr_italic = 0;
+ for (const String &E : names) {
+ if (E.is_empty()) {
+ continue;
+ }
- 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);
- }
+ String path = OS::get_singleton()->get_system_font_path(E, style & TextServer::FONT_BOLD, style & TextServer::FONT_ITALIC);
+ if (path.is_empty()) {
+ continue;
+ }
+ Ref<FontFile> file;
+ file.instantiate();
+ Error err = file->load_dynamic_font(path);
+ if (err != OK) {
+ continue;
+ }
- 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;
+ // If it's a font collection check all faces to match requested style.
+ for (int i = 0; i < file->get_face_count(); i++) {
+ file->set_face_index(0, i);
+ if (((file->get_font_style() & TextServer::FONT_BOLD) == (style & TextServer::FONT_BOLD)) && ((file->get_font_style() & TextServer::FONT_ITALIC) == (style & TextServer::FONT_ITALIC))) {
+ face_indeces.push_back(i);
+ }
+ }
+ if (face_indeces.is_empty()) {
+ face_indeces.push_back(0);
+ }
+ file->set_face_index(0, face_indeces[0]);
+
+ // If it's a variable font, apply weight and italic coordinates to match requested style.
+ Dictionary ftr = file->get_supported_variation_list();
+ if ((style & TextServer::FONT_BOLD) && ftr.has(TS->name_to_tag("weight"))) {
+ ftr_weight = 700;
+ }
+ if ((style & TextServer::FONT_ITALIC) && ftr.has(TS->name_to_tag("italic"))) {
+ ftr_italic = 1;
}
- }
- 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());
+ // Apply font rendering settings.
+ file->set_antialiased(antialiased);
+ file->set_generate_mipmaps(mipmaps);
+ file->set_force_autohinter(force_autohinter);
+ file->set_hinting(hinting);
+ file->set_subpixel_positioning(subpixel_positioning);
+ file->set_oversampling(oversampling);
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
+ base_font = file;
}
- uint64_t hash = p_text.hash64();
- 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);
+ if (base_font.is_valid()) {
+ base_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
- 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);
+ _invalidate_rids();
+ notify_property_list_changed();
+}
+
+void SystemFont::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();
}
- Vector2 ofs = p_pos;
- if (buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y -= buffer->get_line_ascent();
- } else {
- ofs.x -= buffer->get_line_ascent();
+ if (theme_font.is_valid()) {
+ theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ theme_font.unref();
}
- buffer->set_width(p_width);
- buffer->set_horizontal_alignment(p_alignment);
- buffer->set_flags(p_flags);
+ names.clear();
+ face_indeces.clear();
+ ftr_weight = 0;
+ ftr_italic = 0;
+ style = 0;
+ antialiased = true;
+ mipmaps = false;
+ force_autohinter = false;
+ hinting = TextServer::HINTING_LIGHT;
+ subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
+ oversampling = 0.f;
- 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);
+ Font::reset_state();
}
-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());
+Ref<Font> SystemFont::_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<SystemFont *>(this)), &Font::_invalidate_rids));
+ theme_font.unref();
+ }
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
+ if (base_font.is_valid()) {
+ return base_font;
}
- uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_murmur3_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);
+ // 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);
- 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);
+ 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<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
+ }
+ }
}
- lines_buffer->set_alignment(p_alignment);
+ // 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);
- 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);
+ 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<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
}
- if (p_width > 0) {
- lines_buffer->set_alignment(p_alignment);
+
+ // 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<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
+ return f;
+ }
+
+ return Ref<Font>();
+}
- 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);
+void SystemFont::set_antialiased(bool p_antialiased) {
+ if (antialiased != p_antialiased) {
+ antialiased = p_antialiased;
+ if (base_font.is_valid()) {
+ base_font->set_antialiased(antialiased);
}
- lines_buffer->draw_line(p_canvas_item, lofs, i, p_modulate);
+ emit_changed();
+ }
+}
- 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;
+bool SystemFont::is_antialiased() const {
+ return antialiased;
+}
+
+void SystemFont::set_generate_mipmaps(bool p_generate_mipmaps) {
+ if (mipmaps != p_generate_mipmaps) {
+ mipmaps = p_generate_mipmaps;
+ if (base_font.is_valid()) {
+ base_font->set_generate_mipmaps(mipmaps);
}
+ emit_changed();
+ }
+}
+
+bool SystemFont::get_generate_mipmaps() const {
+ return mipmaps;
+}
- if ((p_max_lines > 0) && (i >= p_max_lines)) {
- return;
+void SystemFont::set_force_autohinter(bool p_force_autohinter) {
+ if (force_autohinter != p_force_autohinter) {
+ force_autohinter = p_force_autohinter;
+ if (base_font.is_valid()) {
+ base_font->set_force_autohinter(force_autohinter);
}
+ emit_changed();
}
}
-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;
+bool SystemFont::is_force_autohinter() const {
+ return force_autohinter;
+}
+
+void SystemFont::set_hinting(TextServer::Hinting p_hinting) {
+ if (hinting != p_hinting) {
+ hinting = p_hinting;
+ if (base_font.is_valid()) {
+ base_font->set_hinting(hinting);
}
+ emit_changed();
}
- return Size2();
}
-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;
- }
+TextServer::Hinting SystemFont::get_hinting() const {
+ return hinting;
+}
- 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 SystemFont::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
+ if (subpixel_positioning != p_subpixel) {
+ subpixel_positioning = p_subpixel;
+ if (base_font.is_valid()) {
+ base_font->set_subpixel_positioning(subpixel_positioning);
}
+ emit_changed();
}
- 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;
+TextServer::SubpixelPositioning SystemFont::get_subpixel_positioning() const {
+ return subpixel_positioning;
+}
+
+void SystemFont::set_oversampling(real_t p_oversampling) {
+ if (oversampling != p_oversampling) {
+ oversampling = p_oversampling;
+ if (base_font.is_valid()) {
+ base_font->set_oversampling(oversampling);
}
+ emit_changed();
}
- return false;
}
-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];
- }
+real_t SystemFont::get_oversampling() const {
+ return oversampling;
+}
+
+void SystemFont::set_font_names(const PackedStringArray &p_names) {
+ if (names != p_names) {
+ names = p_names;
+ _update_base_font();
+ }
+}
+
+PackedStringArray SystemFont::get_font_names() const {
+ return names;
+}
+
+void SystemFont::set_font_style(BitField<TextServer::FontStyle> p_style) {
+ if (style != p_style) {
+ style = p_style;
+ _update_base_font();
+ }
+}
+
+BitField<TextServer::FontStyle> SystemFont::get_font_style() const {
+ return style;
+}
+
+int SystemFont::get_spacing(TextServer::SpacingType p_spacing) const {
+ if (base_font.is_valid()) {
+ return base_font->get_spacing(p_spacing);
+ } else {
+ return 0;
+ }
+}
+
+RID SystemFont::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()) {
+ Dictionary var = p_variation_coordinates;
+ if (ftr_weight > 0 && !var.has(TS->name_to_tag("weight"))) {
+ var[TS->name_to_tag("weight")] = ftr_weight;
+ }
+ if (ftr_italic > 0 && !var.has(TS->name_to_tag("italic"))) {
+ var[TS->name_to_tag("italic")] = ftr_italic;
+ }
+
+ if (!face_indeces.is_empty()) {
+ int face_index = CLAMP(p_face_index, 0, face_indeces.size() - 1);
+ return f->find_variation(var, face_indeces[face_index], p_strength, p_transform);
+ } else {
+ return f->find_variation(var, 0, 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 SystemFont::_get_rid() const {
+ Ref<Font> f = _get_base_font_or_default();
+ if (f.is_valid()) {
+ if (!face_indeces.is_empty()) {
+ Dictionary var;
+ if (ftr_weight > 0) {
+ var[TS->name_to_tag("weight")] = ftr_weight;
+ }
+ if (ftr_italic > 0) {
+ var[TS->name_to_tag("italic")] = ftr_italic;
+ }
+ return f->find_variation(var, face_indeces[0]);
+ } else {
+ return f->_get_rid();
}
}
- return _rids;
+ return RID();
}
-void Font::update_changes() {
- emit_changed();
+int64_t SystemFont::get_face_count() const {
+ return face_indeces.size();
}
-Font::Font() {
- cache.set_capacity(128);
- cache_wrap.set_capacity(32);
+SystemFont::SystemFont() {
+ /* NOP */
}
-Font::~Font() {
- clear_data();
- cache.clear();
- cache_wrap.clear();
+SystemFont::~SystemFont() {
+ reset_state();
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 950959e054..260b4e521f 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 BitField<TextServer::FontStyle> 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, BitField<TextServer::JustificationFlag> p_jst_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, BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_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_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), BitField<TextServer::JustificationFlag> p_jst_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), BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_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_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), BitField<TextServer::JustificationFlag> p_jst_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), BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_flags = 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_font_style(BitField<TextServer::FontStyle> p_style);
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_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_face_index(int p_cache_index, int64_t p_index);
+ virtual int64_t get_face_index(int p_cache_index) 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_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_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_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_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_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_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_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_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,140 @@ 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 Font : public Resource {
- GDCLASS(Font, Resource);
+class FontVariation : public Font {
+ GDCLASS(FontVariation, Font);
- // Shaped string cache.
- mutable LRUCache<uint64_t, Ref<TextLine>> cache;
- mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
+ struct Variation {
+ Dictionary opentype;
+ real_t embolden = 0.f;
+ int face_index = 0;
+ Transform2D transform;
+ };
- // 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;
+ 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;
- Dictionary get_feature_list() const;
+ virtual void set_variation_opentype(const Dictionary &p_coords);
+ virtual Dictionary get_variation_opentype() 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_embolden(float p_strength);
+ virtual float get_variation_embolden() const;
- // Font configuration.
- virtual void set_variation_coordinates(const Dictionary &p_variation_coordinates);
- virtual Dictionary get_variation_coordinates() const;
+ virtual void set_variation_transform(Transform2D p_transform);
+ virtual Transform2D get_variation_transform() const;
+
+ virtual void set_variation_face_index(int p_face_index);
+ virtual int get_variation_face_index() const;
+
+ virtual void set_opentype_features(const Dictionary &p_features);
+ virtual Dictionary get_opentype_features() const override;
virtual void set_spacing(TextServer::SpacingType p_spacing, int p_value);
- virtual int get_spacing(TextServer::SpacingType p_spacing) const;
+ virtual int get_spacing(TextServer::SpacingType p_spacing) const override;
- // 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;
+ // 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;
- // 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;
+ FontVariation();
+ ~FontVariation();
+};
- 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;
+/*************************************************************************/
+/* SystemFont */
+/*************************************************************************/
- // Helper functions.
- virtual bool has_char(char32_t p_char) const;
- virtual String get_supported_chars() const;
+class SystemFont : public Font {
+ GDCLASS(SystemFont, Font);
- // 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;
+ PackedStringArray names;
+ BitField<TextServer::FontStyle> style = 0;
- Array get_rids() const;
+ mutable Ref<Font> theme_font;
- void update_changes();
+ Ref<FontFile> base_font;
+ Vector<int> face_indeces;
+ int ftr_weight = 0;
+ int ftr_italic = 0;
- Font();
- ~Font();
+ bool antialiased = true;
+ bool mipmaps = false;
+ bool force_autohinter = false;
+ TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
+ TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
+ real_t oversampling = 0.f;
+
+protected:
+ static void _bind_methods();
+
+ virtual void _update_base_font();
+ virtual void _update_rids() const override;
+
+ virtual void reset_state() override;
+
+public:
+ virtual Ref<Font> _get_base_font_or_default() const;
+
+ virtual void set_antialiased(bool p_antialiased);
+ virtual bool is_antialiased() const;
+
+ virtual void set_generate_mipmaps(bool p_generate_mipmaps);
+ virtual bool get_generate_mipmaps() const;
+
+ virtual void set_force_autohinter(bool p_force_autohinter);
+ virtual bool is_force_autohinter() const;
+
+ virtual void set_hinting(TextServer::Hinting p_hinting);
+ virtual TextServer::Hinting get_hinting() const;
+
+ virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel);
+ virtual TextServer::SubpixelPositioning get_subpixel_positioning() const;
+
+ virtual void set_oversampling(real_t p_oversampling);
+ virtual real_t get_oversampling() const;
+
+ virtual void set_font_names(const PackedStringArray &p_names);
+ virtual PackedStringArray get_font_names() const;
+
+ virtual void set_font_style(BitField<TextServer::FontStyle> p_style);
+ virtual BitField<TextServer::FontStyle> get_font_style() const override;
+
+ virtual int get_spacing(TextServer::SpacingType p_spacing) const override;
+
+ 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;
+
+ int64_t get_face_count() const override;
+
+ SystemFont();
+ ~SystemFont();
};
-#endif /* FONT_H */
+#endif // FONT_H
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index 2b04ead0af..e4bac15e4b 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -157,10 +157,10 @@ public:
const Point &pointP3 = points[p3];
float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset);
- 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);
+ float r = Math::cubic_interpolate(pointFirst.color.r, pointSecond.color.r, pointP0.color.r, pointP3.color.r, x);
+ float g = Math::cubic_interpolate(pointFirst.color.g, pointSecond.color.g, pointP0.color.g, pointP3.color.g, x);
+ float b = Math::cubic_interpolate(pointFirst.color.b, pointSecond.color.b, pointP0.color.b, pointP3.color.b, x);
+ float a = Math::cubic_interpolate(pointFirst.color.a, pointSecond.color.a, pointP0.color.a, pointP3.color.a, x);
return Color(r, g, b, a);
} break;
diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h
index 79d1b15674..633238030b 100644
--- a/scene/resources/height_map_shape_3d.h
+++ b/scene/resources/height_map_shape_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef HEIGHT_MAP_SHAPE_H
-#define HEIGHT_MAP_SHAPE_H
+#ifndef HEIGHT_MAP_SHAPE_3D_H
+#define HEIGHT_MAP_SHAPE_3D_H
#include "scene/resources/shape_3d.h"
@@ -60,4 +60,4 @@ public:
HeightMapShape3D();
};
-#endif /* !HEIGHT_MAP_SHAPE_H */
+#endif // HEIGHT_MAP_SHAPE_3D_H
diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h
index e5f627ae8e..de10fdbfbe 100644
--- a/scene/resources/immediate_mesh.h
+++ b/scene/resources/immediate_mesh.h
@@ -115,4 +115,4 @@ public:
~ImmediateMesh();
};
-#endif // IMMEDIATEMESH_H
+#endif // IMMEDIATE_MESH_H
diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h
index 8f77597a58..bf1d0301d1 100644
--- a/scene/resources/importer_mesh.h
+++ b/scene/resources/importer_mesh.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_IMPORTER_MESH_H
-#define SCENE_IMPORTER_MESH_H
+#ifndef IMPORTER_MESH_H
+#define IMPORTER_MESH_H
#include "core/io/resource.h"
#include "core/templates/local_vector.h"
@@ -130,4 +130,5 @@ public:
Ref<ArrayMesh> get_mesh(const Ref<ArrayMesh> &p_base = Ref<ArrayMesh>());
void clear();
};
-#endif // SCENE_IMPORTER_MESH_H
+
+#endif // IMPORTER_MESH_H
diff --git a/scene/resources/label_settings.cpp b/scene/resources/label_settings.cpp
new file mode 100644
index 0000000000..ef380a68f9
--- /dev/null
+++ b/scene/resources/label_settings.cpp
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* label_settings.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 "label_settings.h"
+
+#include "core/core_string_names.h"
+
+void LabelSettings::_font_changed() {
+ emit_changed();
+}
+
+void LabelSettings::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_line_spacing", "spacing"), &LabelSettings::set_line_spacing);
+ ClassDB::bind_method(D_METHOD("get_line_spacing"), &LabelSettings::get_line_spacing);
+
+ ClassDB::bind_method(D_METHOD("set_font", "font"), &LabelSettings::set_font);
+ ClassDB::bind_method(D_METHOD("get_font"), &LabelSettings::get_font);
+
+ ClassDB::bind_method(D_METHOD("set_font_size", "size"), &LabelSettings::set_font_size);
+ ClassDB::bind_method(D_METHOD("get_font_size"), &LabelSettings::get_font_size);
+
+ ClassDB::bind_method(D_METHOD("set_font_color", "color"), &LabelSettings::set_font_color);
+ ClassDB::bind_method(D_METHOD("get_font_color"), &LabelSettings::get_font_color);
+
+ ClassDB::bind_method(D_METHOD("set_outline_size", "size"), &LabelSettings::set_outline_size);
+ ClassDB::bind_method(D_METHOD("get_outline_size"), &LabelSettings::get_outline_size);
+
+ ClassDB::bind_method(D_METHOD("set_outline_color", "color"), &LabelSettings::set_outline_color);
+ ClassDB::bind_method(D_METHOD("get_outline_color"), &LabelSettings::get_outline_color);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &LabelSettings::set_shadow_size);
+ ClassDB::bind_method(D_METHOD("get_shadow_size"), &LabelSettings::get_shadow_size);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_color", "color"), &LabelSettings::set_shadow_color);
+ ClassDB::bind_method(D_METHOD("get_shadow_color"), &LabelSettings::get_shadow_color);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &LabelSettings::set_shadow_offset);
+ ClassDB::bind_method(D_METHOD("get_shadow_offset"), &LabelSettings::get_shadow_offset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
+
+ ADD_GROUP("Font", "font");
+ 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,1024,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "font_color"), "set_font_color", "get_font_color");
+
+ ADD_GROUP("Outline", "outline");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_outline_size", "get_outline_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color");
+
+ ADD_GROUP("Shadow", "shadow");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
+}
+
+void LabelSettings::set_line_spacing(real_t p_spacing) {
+ if (line_spacing != p_spacing) {
+ line_spacing = p_spacing;
+ emit_changed();
+ }
+}
+
+real_t LabelSettings::get_line_spacing() const {
+ return line_spacing;
+}
+
+void LabelSettings::set_font(const Ref<Font> &p_font) {
+ if (font != p_font) {
+ if (font.is_valid()) {
+ font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed));
+ }
+ font = p_font;
+ if (font.is_valid()) {
+ font->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed), CONNECT_REFERENCE_COUNTED);
+ }
+ emit_changed();
+ }
+}
+
+Ref<Font> LabelSettings::get_font() const {
+ return font;
+}
+
+void LabelSettings::set_font_size(int p_size) {
+ if (font_size != p_size) {
+ font_size = p_size;
+ emit_changed();
+ }
+}
+
+int LabelSettings::get_font_size() const {
+ return font_size;
+}
+
+void LabelSettings::set_font_color(const Color &p_color) {
+ if (font_color != p_color) {
+ font_color = p_color;
+ emit_changed();
+ }
+}
+
+Color LabelSettings::get_font_color() const {
+ return font_color;
+}
+
+void LabelSettings::set_outline_size(int p_size) {
+ if (outline_size != p_size) {
+ outline_size = p_size;
+ emit_changed();
+ }
+}
+
+int LabelSettings::get_outline_size() const {
+ return outline_size;
+}
+
+void LabelSettings::set_outline_color(const Color &p_color) {
+ if (outline_color != p_color) {
+ outline_color = p_color;
+ emit_changed();
+ }
+}
+
+Color LabelSettings::get_outline_color() const {
+ return outline_color;
+}
+
+void LabelSettings::set_shadow_size(int p_size) {
+ if (shadow_size != p_size) {
+ shadow_size = p_size;
+ emit_changed();
+ }
+}
+
+int LabelSettings::get_shadow_size() const {
+ return shadow_size;
+}
+
+void LabelSettings::set_shadow_color(const Color &p_color) {
+ if (shadow_color != p_color) {
+ shadow_color = p_color;
+ emit_changed();
+ }
+}
+
+Color LabelSettings::get_shadow_color() const {
+ return shadow_color;
+}
+
+void LabelSettings::set_shadow_offset(const Vector2 &p_offset) {
+ if (shadow_offset != p_offset) {
+ shadow_offset = p_offset;
+ emit_changed();
+ }
+}
+
+Vector2 LabelSettings::get_shadow_offset() const {
+ return shadow_offset;
+}
diff --git a/scene/resources/label_settings.h b/scene/resources/label_settings.h
new file mode 100644
index 0000000000..d2644a7484
--- /dev/null
+++ b/scene/resources/label_settings.h
@@ -0,0 +1,89 @@
+/*************************************************************************/
+/* label_settings.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 LABEL_SETTINGS_H
+#define LABEL_SETTINGS_H
+
+#include "core/io/resource.h"
+#include "font.h"
+
+/*************************************************************************/
+
+class LabelSettings : public Resource {
+ GDCLASS(LabelSettings, Resource);
+
+ real_t line_spacing = 0;
+
+ Ref<Font> font;
+ int font_size = Font::DEFAULT_FONT_SIZE;
+ Color font_color = Color(0.875, 0.875, 0.875);
+
+ int outline_size = 0;
+ Color outline_color = Color(1, 1, 1);
+
+ int shadow_size = 0;
+ Color shadow_color = Color(1, 1, 1);
+ Vector2 shadow_offset = Vector2(1, 1);
+
+ void _font_changed();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_line_spacing(real_t p_spacing);
+ real_t get_line_spacing() const;
+
+ void set_font(const Ref<Font> &p_font);
+ Ref<Font> get_font() const;
+
+ void set_font_size(int p_size);
+ int get_font_size() const;
+
+ void set_font_color(const Color &p_color);
+ Color get_font_color() const;
+
+ void set_outline_size(int p_size);
+ int get_outline_size() const;
+
+ void set_outline_color(const Color &p_color);
+ Color get_outline_color() const;
+
+ void set_shadow_size(int p_size);
+ int get_shadow_size() const;
+
+ void set_shadow_color(const Color &p_color);
+ Color get_shadow_color() const;
+
+ void set_shadow_offset(const Vector2 &p_offset);
+ Vector2 get_shadow_offset() const;
+};
+
+#endif // LABEL_SETTINGS_H
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index b7a3b677f5..1d7e6f6470 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -202,7 +202,98 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
if (!shader.is_null()) {
- shader->get_param_list(p_list);
+ List<PropertyInfo> list;
+ shader->get_param_list(&list, true);
+
+ HashMap<String, HashMap<String, List<PropertyInfo>>> groups;
+ {
+ HashMap<String, List<PropertyInfo>> none_subgroup;
+ none_subgroup.insert("<None>", List<PropertyInfo>());
+ groups.insert("<None>", none_subgroup);
+ }
+
+ String last_group = "<None>";
+ String last_subgroup = "<None>";
+
+ bool is_none_group_undefined = true;
+ bool is_none_group = true;
+
+ for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
+ if (E->get().usage == PROPERTY_USAGE_GROUP) {
+ if (!E->get().name.is_empty()) {
+ Vector<String> vgroup = E->get().name.split("::");
+ last_group = vgroup[0];
+ if (vgroup.size() > 1) {
+ last_subgroup = vgroup[1];
+ } else {
+ last_subgroup = "<None>";
+ }
+ is_none_group = false;
+
+ if (!groups.has(last_group)) {
+ PropertyInfo info;
+ info.usage = PROPERTY_USAGE_GROUP;
+ info.name = last_group;
+
+ List<PropertyInfo> none_subgroup;
+ none_subgroup.push_back(info);
+
+ HashMap<String, List<PropertyInfo>> subgroup_map;
+ subgroup_map.insert("<None>", none_subgroup);
+
+ groups.insert(last_group, subgroup_map);
+ }
+
+ if (!groups[last_group].has(last_subgroup)) {
+ PropertyInfo info;
+ info.usage = PROPERTY_USAGE_SUBGROUP;
+ info.name = last_subgroup;
+
+ List<PropertyInfo> subgroup;
+ subgroup.push_back(info);
+
+ groups[last_group].insert(last_subgroup, subgroup);
+ }
+ } else {
+ last_group = "<None>";
+ last_subgroup = "<None>";
+ is_none_group = true;
+ }
+ continue; // Pass group.
+ }
+
+ if (is_none_group_undefined && is_none_group) {
+ is_none_group_undefined = false;
+
+ PropertyInfo info;
+ info.usage = PROPERTY_USAGE_GROUP;
+ info.name = "Shader Param";
+ groups["<None>"]["<None>"].push_back(info);
+ }
+
+ PropertyInfo info = E->get();
+ info.name = info.name;
+ groups[last_group][last_subgroup].push_back(info);
+ }
+
+ // Sort groups alphabetically.
+ List<UniformProp> props;
+ for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
+ for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
+ for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
+ if (subgroup->key == "<None>") {
+ props.push_back({ group->key, item->get() });
+ } else {
+ props.push_back({ group->key + "::" + subgroup->key, item->get() });
+ }
+ }
+ }
+ }
+ props.sort_custom<UniformPropComparator>();
+
+ for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
+ p_list->push_back(E->get().info);
+ }
}
}
@@ -1702,12 +1793,21 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
}
flags[p_flag] = p_enabled;
- if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN || p_flag == FLAG_USE_POINT_SIZE) {
+
+ if (
+ p_flag == FLAG_USE_SHADOW_TO_OPACITY ||
+ p_flag == FLAG_USE_TEXTURE_REPEAT ||
+ p_flag == FLAG_SUBSURFACE_MODE_SKIN ||
+ p_flag == FLAG_USE_POINT_SIZE ||
+ p_flag == FLAG_UV1_USE_TRIPLANAR ||
+ p_flag == FLAG_UV2_USE_TRIPLANAR) {
notify_property_list_changed();
}
+
if (p_flag == FLAG_PARTICLE_TRAILS_MODE) {
update_configuration_warning();
}
+
_queue_shader_change();
}
@@ -1833,6 +1933,14 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+ if ((property.name == "uv1_triplanar_sharpness" || property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if ((property.name == "uv2_triplanar_sharpness" || property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
// you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash
const bool can_select_aa = (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH);
// alpha anti aliasiasing is only enabled when you can select aa
@@ -2546,7 +2654,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Transparency", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth Pre-Pass"), "set_transparency", "get_transparency");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge");
@@ -2593,7 +2701,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION);
- ADD_GROUP("NormalMap", "normal_");
+ ADD_GROUP("Normal Map", "normal_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "normal_enabled"), "set_feature", "get_feature", FEATURE_NORMAL_MAPPING);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_scale", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_normal_scale", "get_normal_scale");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_NORMAL);
@@ -2633,7 +2741,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "heightmap_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_HEIGHTMAP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "heightmap_flip_texture"), "set_flag", "get_flag", FLAG_INVERT_HEIGHTMAP);
- ADD_GROUP("Subsurf Scatter", "subsurf_scatter_");
+ ADD_GROUP("Subsurface Scattering", "subsurf_scatter_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURFACE_SCATTERING);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_subsurface_scattering_strength", "get_subsurface_scattering_strength");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_skin_mode"), "set_flag", "get_flag", FLAG_SUBSURFACE_MODE_SKIN);
@@ -2878,7 +2986,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
- set_alpha_scissor_threshold(0.05);
+ set_alpha_scissor_threshold(0.5);
set_alpha_hash_scale(1.0);
set_alpha_antialiasing_edge(0.3);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index b845fd68c8..8c04817c6b 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -84,6 +84,17 @@ class ShaderMaterial : public Material {
HashMap<StringName, Variant> param_cache;
+ struct UniformProp {
+ String str;
+ PropertyInfo info;
+ };
+
+ struct UniformPropComparator {
+ bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
+ return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
+ }
+ };
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -809,4 +820,4 @@ public:
//////////////////////
-#endif
+#endif // MATERIAL_H
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 3e7b0a2808..ec9db89794 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -260,6 +260,64 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
return triangle_mesh;
}
+Ref<TriangleMesh> Mesh::generate_surface_triangle_mesh(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, get_surface_count(), Ref<TriangleMesh>());
+
+ if (surface_triangle_meshes.size() != get_surface_count()) {
+ surface_triangle_meshes.resize(get_surface_count());
+ }
+
+ if (surface_triangle_meshes[p_surface].is_valid()) {
+ return surface_triangle_meshes[p_surface];
+ }
+
+ int facecount = 0;
+
+ if (surface_get_primitive_type(p_surface) != PRIMITIVE_TRIANGLES) {
+ return Ref<TriangleMesh>();
+ }
+
+ if (surface_get_format(p_surface) & ARRAY_FORMAT_INDEX) {
+ facecount += surface_get_array_index_len(p_surface);
+ } else {
+ facecount += surface_get_array_len(p_surface);
+ }
+
+ Vector<Vector3> faces;
+ faces.resize(facecount);
+ Vector3 *facesw = faces.ptrw();
+
+ Array a = surface_get_arrays(p_surface);
+ ERR_FAIL_COND_V(a.is_empty(), Ref<TriangleMesh>());
+
+ int vc = surface_get_array_len(p_surface);
+ Vector<Vector3> vertices = a[ARRAY_VERTEX];
+ const Vector3 *vr = vertices.ptr();
+ int widx = 0;
+
+ if (surface_get_format(p_surface) & ARRAY_FORMAT_INDEX) {
+ int ic = surface_get_array_index_len(p_surface);
+ Vector<int> indices = a[ARRAY_INDEX];
+ const int *ir = indices.ptr();
+
+ for (int j = 0; j < ic; j++) {
+ int index = ir[j];
+ facesw[widx++] = vr[index];
+ }
+
+ } else {
+ for (int j = 0; j < vc; j++) {
+ facesw[widx++] = vr[j];
+ }
+ }
+
+ Ref<TriangleMesh> triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
+ triangle_mesh->create(faces);
+ surface_triangle_meshes.set(p_surface, triangle_mesh);
+
+ return triangle_mesh;
+}
+
void Mesh::generate_debug_mesh_lines(Vector<Vector3> &r_lines) {
if (debug_lines.size() > 0) {
r_lines = debug_lines;
@@ -320,6 +378,14 @@ Vector<Face3> Mesh::get_faces() const {
return Vector<Face3>();
}
+Vector<Face3> Mesh::get_surface_faces(int p_surface) const {
+ Ref<TriangleMesh> tm = generate_surface_triangle_mesh(p_surface);
+ if (tm.is_valid()) {
+ return tm->get_faces();
+ }
+ return Vector<Face3>();
+}
+
Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
if (p_simplify) {
ConvexDecompositionSettings settings;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index b166d12ead..142373ce7f 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -42,6 +42,7 @@ class Mesh : public Resource {
GDCLASS(Mesh, Resource);
mutable Ref<TriangleMesh> triangle_mesh; //cached
+ mutable Vector<Ref<TriangleMesh>> surface_triangle_meshes; //cached
mutable Vector<Vector3> debug_lines;
Size2i lightmap_size_hint;
@@ -161,7 +162,9 @@ public:
virtual AABB get_aabb() const;
Vector<Face3> get_faces() const;
+ Vector<Face3> get_surface_faces(int p_surface) const;
Ref<TriangleMesh> generate_triangle_mesh() const;
+ Ref<TriangleMesh> generate_surface_triangle_mesh(int p_surface) const;
void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
void generate_debug_mesh_indices(Vector<Vector3> &r_points);
@@ -362,4 +365,4 @@ public:
~PlaceholderMesh();
};
-#endif
+#endif // MESH_H
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index c8bfb73b2d..2d3f9d9afc 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -107,7 +107,7 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::ARRAY, name + PNAME("shapes")));
p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
}
}
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index 30ada5365f..0f8cc76173 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -113,4 +113,4 @@ public:
VARIANT_ENUM_CAST(MultiMesh::TransformFormat);
-#endif // MULTI_MESH_H
+#endif // MULTIMESH_H
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index a808ead66b..ac5493efdc 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -30,6 +30,10 @@
#include "navigation_mesh.h"
+#ifdef DEBUG_ENABLED
+#include "servers/navigation_server_3d.h"
+#endif
+
void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND(p_mesh.is_null());
@@ -337,6 +341,7 @@ void NavigationMesh::clear_polygons() {
polygons.clear();
}
+#ifndef DISABLE_DEPRECATED
Ref<Mesh> NavigationMesh::get_debug_mesh() {
if (debug_mesh.is_valid()) {
return debug_mesh;
@@ -420,6 +425,102 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
return debug_mesh;
}
+#endif // DISABLE_DEPRECATED
+
+#ifdef DEBUG_ENABLED
+Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
+ if (debug_mesh.is_valid()) {
+ // Blocks further updates for now, code below is intended for dynamic updates e.g. when settings change.
+ return debug_mesh;
+ }
+
+ if (!debug_mesh.is_valid()) {
+ debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ } else {
+ debug_mesh->clear_surfaces();
+ }
+
+ if (vertices.size() == 0) {
+ return debug_mesh;
+ }
+
+ int polygon_count = get_polygon_count();
+
+ if (polygon_count < 1) {
+ // no face, no play
+ return debug_mesh;
+ }
+
+ // build geometry face surface
+ Vector<Vector3> face_vertex_array;
+ face_vertex_array.resize(polygon_count * 3);
+
+ for (int i = 0; i < polygon_count; i++) {
+ Vector<int> polygon = get_polygon(i);
+
+ face_vertex_array.push_back(vertices[polygon[0]]);
+ face_vertex_array.push_back(vertices[polygon[1]]);
+ face_vertex_array.push_back(vertices[polygon[2]]);
+ }
+
+ Array face_mesh_array;
+ face_mesh_array.resize(Mesh::ARRAY_MAX);
+ face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
+
+ // if enabled add vertex colors to colorize each face individually
+ bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
+ if (enabled_geometry_face_random_color) {
+ Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+ Color polygon_color = debug_navigation_geometry_face_color;
+
+ Vector<Color> face_color_array;
+ face_color_array.resize(polygon_count * 3);
+
+ for (int i = 0; i < polygon_count; i++) {
+ polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
+
+ Vector<int> polygon = get_polygon(i);
+
+ face_color_array.push_back(polygon_color);
+ face_color_array.push_back(polygon_color);
+ face_color_array.push_back(polygon_color);
+ }
+ face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
+ }
+
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
+ Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
+ debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_face_material);
+
+ // if enabled build geometry edge line surface
+ bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
+
+ if (enabled_edge_lines) {
+ Vector<Vector3> line_vertex_array;
+ line_vertex_array.resize(polygon_count * 6);
+
+ for (int i = 0; i < polygon_count; i++) {
+ Vector<int> polygon = get_polygon(i);
+
+ line_vertex_array.push_back(vertices[polygon[0]]);
+ line_vertex_array.push_back(vertices[polygon[1]]);
+ line_vertex_array.push_back(vertices[polygon[1]]);
+ line_vertex_array.push_back(vertices[polygon[2]]);
+ line_vertex_array.push_back(vertices[polygon[2]]);
+ line_vertex_array.push_back(vertices[polygon[0]]);
+ }
+
+ Array line_mesh_array;
+ line_mesh_array.resize(Mesh::ARRAY_MAX);
+ line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
+ Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
+ debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_edge_material);
+ }
+
+ return debug_mesh;
+}
+#endif
void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 40b275c792..79d8962d24 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -204,7 +204,11 @@ public:
Vector<int> get_polygon(int p_idx);
void clear_polygons();
+#ifndef DISABLE_DEPRECATED
Ref<Mesh> get_debug_mesh();
+#endif // DISABLE_DEPRECATED
+
+ Ref<ArrayMesh> _get_debug_mesh();
NavigationMesh();
};
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 2c58aa83a9..ac67e6e5e9 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -434,10 +434,10 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
for (int j = 0; j < binds.size(); j++) {
argptrs[j] = &binds[j];
}
- callable = callable.bind(argptrs, binds.size());
+ callable = callable.bindp(argptrs, binds.size());
}
- cfrom->connect(snames[c.signal], callable, varray(), CONNECT_PERSIST | c.flags);
+ cfrom->connect(snames[c.signal], callable, CONNECT_PERSIST | c.flags);
}
//Node *s = ret_nodes[0];
@@ -892,9 +892,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMap<String
cd.signal = _nm_get_string(c.signal.get_name(), name_map);
cd.flags = c.flags;
cd.unbinds = unbinds;
- for (int i = 0; i < c.binds.size(); i++) { // TODO: This could be removed now.
- cd.binds.push_back(_vm_get_variant(c.binds[i], variant_map));
- }
+
for (int i = 0; i < binds.size(); i++) {
cd.binds.push_back(_vm_get_variant(binds[i], variant_map));
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 5f8001c871..8e1a1d29b6 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -249,4 +249,4 @@ public:
VARIANT_ENUM_CAST(PackedScene::GenEditState)
-#endif // SCENE_PRELOADER_H
+#endif // PACKED_SCENE_H
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index f4fd81b25f..68441afb1c 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -2190,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;
@@ -2376,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) {
@@ -2394,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;
@@ -2437,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_murmur3_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);
@@ -2496,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_murmur3_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();
@@ -2682,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);
@@ -2704,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");
@@ -2716,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) {
@@ -2735,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();
@@ -2848,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;
}
@@ -2955,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..ec124e379f 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;
@@ -582,4 +595,5 @@ public:
};
VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
-#endif
+
+#endif // PRIMITIVE_MESHES_H
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 66afb001fb..2b1d91e4ef 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -65,14 +65,18 @@ Error ResourceLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, Varia
return ERR_PARSE_ERROR;
}
- String unique_id = token.value;
+ if (p_data->no_placeholders) {
+ r_res.unref();
+ } else {
+ String unique_id = token.value;
- if (!p_data->resource_map.has(unique_id)) {
- r_err_str = "Found unique_id reference before mapping, sub-resources stored out of order in resource file";
- return ERR_PARSE_ERROR;
- }
+ if (!p_data->resource_map.has(unique_id)) {
+ 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];
+ r_res = p_data->resource_map[unique_id];
+ }
VariantParser::get_token(p_stream, token, line, r_err_str);
if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
@@ -91,11 +95,15 @@ Error ResourceLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, Varia
return ERR_PARSE_ERROR;
}
- String id = token.value;
+ if (p_data->no_placeholders) {
+ r_res.unref();
+ } else {
+ String id = token.value;
- ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR);
- r_res = p_data->rev_external_resources[id];
+ r_res = p_data->rev_external_resources[id];
+ }
VariantParser::get_token(p_stream, token, line, r_err_str);
if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
@@ -1066,7 +1074,7 @@ static void bs_save_unicode_string(Ref<FileAccess> p_f, const String &p_string,
p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
}
-Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_path) {
+Error ResourceLoaderText::save_as_binary(const String &p_path) {
if (error) {
return error;
}
@@ -1271,7 +1279,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
}
if (next_tag.name == "node") {
- //this is a node, must save one more!
+ // This is a node, must save one more!
if (!is_scene) {
error_text += "found the 'node' tag on a resource file!";
@@ -1346,6 +1354,126 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
return OK;
}
+Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
+ if (error) {
+ return error;
+ }
+
+ ignore_resource_parsing = true;
+
+ DummyReadData dummy_read;
+ dummy_read.no_placeholders = true;
+ VariantParser::ResourceParser rp;
+ rp.ext_func = _parse_ext_resource_dummys;
+ rp.sub_func = _parse_sub_resource_dummys;
+ rp.userdata = &dummy_read;
+
+ while (next_tag.name == "ext_resource") {
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
+
+ if (error) {
+ _printerr();
+ return error;
+ }
+ }
+
+ while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
+ if (next_tag.name == "sub_resource") {
+ if (!next_tag.fields.has("type")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ r_classes->insert(next_tag.fields["type"]);
+
+ } else {
+ r_classes->insert(next_tag.fields["res_type"]);
+ }
+
+ while (true) {
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+
+ if (error) {
+ if (error == ERR_FILE_EOF) {
+ return OK;
+ }
+
+ _printerr();
+ return error;
+ }
+
+ if (!assign.is_empty()) {
+ continue;
+ } else if (!next_tag.name.is_empty()) {
+ error = OK;
+ break;
+ } else {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Premature end of file while parsing [sub_resource]";
+ _printerr();
+ return error;
+ }
+ }
+ }
+
+ while (next_tag.name == "node") {
+ // This is a node, must save one more!
+
+ if (!is_scene) {
+ error_text += "found the 'node' tag on a resource file!";
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ if (!next_tag.fields.has("type")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ r_classes->insert(next_tag.fields["type"]);
+
+ while (true) {
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+
+ if (error) {
+ if (error == ERR_FILE_MISSING_DEPENDENCIES) {
+ // Resource loading error, just skip it.
+ } else if (error != ERR_FILE_EOF) {
+ _printerr();
+ return error;
+ } else {
+ return OK;
+ }
+ }
+
+ if (!assign.is_empty()) {
+ continue;
+ } else if (!next_tag.name.is_empty()) {
+ error = OK;
+ break;
+ } else {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Premature end of file while parsing [sub_resource]";
+ _printerr();
+ return error;
+ }
+ }
+ }
+
+ return OK;
+}
+
String ResourceLoaderText::recognize(Ref<FileAccess> p_f) {
error = OK;
@@ -1473,6 +1601,26 @@ bool ResourceFormatLoaderText::handles_type(const String &p_type) const {
return true;
}
+void ResourceFormatLoaderText::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
+ String ext = p_path.get_extension().to_lower();
+ if (ext == "tscn") {
+ r_classes->insert("PackedScene");
+ }
+
+ // ...for anything else must test...
+
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
+ return; // Could not read.
+ }
+
+ ResourceLoaderText loader;
+ loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
+ loader.res_path = loader.local_path;
+ loader.open(f);
+ loader.get_classes_used(r_classes);
+}
+
String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
String ext = p_path.get_extension().to_lower();
if (ext == "tscn") {
@@ -1561,7 +1709,7 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path,
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
loader.res_path = loader.local_path;
loader.open(f);
- return loader.save_as_binary(f, p_dst_path);
+ return loader.save_as_binary(p_dst_path);
}
/*****************************************************************************************************/
@@ -2063,7 +2211,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
return OK;
}
-Error ResourceFormatSaverText::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverText::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
if (p_path.ends_with(".tscn") && !Ref<PackedScene>(p_resource).is_valid()) {
return ERR_FILE_UNRECOGNIZED;
}
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 5c6a937bf2..9154bcf795 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -90,6 +90,7 @@ class ResourceLoaderText {
};
struct DummyReadData {
+ bool no_placeholders = false;
HashMap<Ref<Resource>, int> external_resources;
HashMap<String, Ref<Resource>> rev_external_resources;
HashMap<Ref<Resource>, int> resource_index_map;
@@ -125,8 +126,9 @@ public:
ResourceUID::ID get_uid(Ref<FileAccess> p_f);
void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types);
Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map);
+ Error get_classes_used(HashSet<StringName> *r_classes);
- Error save_as_binary(Ref<FileAccess> p_f, const String &p_path);
+ Error save_as_binary(const String &p_path);
ResourceLoaderText();
};
@@ -137,6 +139,8 @@ public:
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
+ virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
+
virtual String get_resource_type(const String &p_path) const;
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
@@ -190,7 +194,7 @@ public:
class ResourceFormatSaverText : public ResourceFormatSaver {
public:
static ResourceFormatSaverText *singleton;
- virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
virtual bool recognize(const Ref<Resource> &p_resource) const;
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
diff --git a/scene/resources/scene_replication_config.cpp b/scene/resources/scene_replication_config.cpp
deleted file mode 100644
index 6789f9f7d5..0000000000
--- a/scene/resources/scene_replication_config.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/*************************************************************************/
-/* scene_replication_config.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 "scene_replication_config.h"
-
-#include "core/multiplayer/multiplayer_api.h"
-#include "scene/main/node.h"
-
-bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
-
- if (name.begins_with("properties/")) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
-
- if (properties.size() == idx && what == "path") {
- ERR_FAIL_COND_V(p_value.get_type() != Variant::NODE_PATH, false);
- NodePath path = p_value;
- ERR_FAIL_COND_V(path.is_empty() || path.get_subname_count() == 0, false);
- add_property(path);
- return true;
- }
- ERR_FAIL_COND_V(p_value.get_type() != Variant::BOOL, false);
- ERR_FAIL_INDEX_V(idx, properties.size(), false);
- ReplicationProperty &prop = properties[idx];
- if (what == "sync") {
- prop.sync = p_value;
- 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;
- if (prop.spawn) {
- spawn_props.push_back(prop.name);
- } else {
- spawn_props.erase(prop.name);
- }
- return true;
- }
- }
- return false;
-}
-
-bool SceneReplicationConfig::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
-
- if (name.begins_with("properties/")) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(idx, properties.size(), false);
- const ReplicationProperty &prop = properties[idx];
- if (what == "path") {
- r_ret = prop.name;
- return true;
- } else if (what == "sync") {
- r_ret = prop.sync;
- return true;
- } else if (what == "spawn") {
- r_ret = prop.spawn;
- return true;
- }
- }
- return false;
-}
-
-void SceneReplicationConfig::_get_property_list(List<PropertyInfo> *p_list) const {
- for (int i = 0; i < properties.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::STRING, "properties/" + itos(i) + "/path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::STRING, "properties/" + itos(i) + "/spawn", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::STRING, "properties/" + itos(i) + "/sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- }
-}
-
-TypedArray<NodePath> SceneReplicationConfig::get_properties() const {
- TypedArray<NodePath> paths;
- for (const ReplicationProperty &prop : properties) {
- paths.push_back(prop.name);
- }
- return paths;
-}
-
-void SceneReplicationConfig::add_property(const NodePath &p_path, int p_index) {
- ERR_FAIL_COND(properties.find(p_path));
-
- if (p_index < 0 || p_index == properties.size()) {
- properties.push_back(ReplicationProperty(p_path));
- return;
- }
-
- ERR_FAIL_INDEX(p_index, properties.size());
-
- List<ReplicationProperty>::Element *I = properties.front();
- int c = 0;
- while (c < p_index) {
- I = I->next();
- c++;
- }
- properties.insert_before(I, ReplicationProperty(p_path));
-}
-
-void SceneReplicationConfig::remove_property(const NodePath &p_path) {
- properties.erase(p_path);
-}
-
-bool SceneReplicationConfig::has_property(const NodePath &p_path) const {
- for (int i = 0; i < properties.size(); i++) {
- if (properties[i].name == p_path) {
- return true;
- }
- }
- return false;
-}
-
-int SceneReplicationConfig::property_get_index(const NodePath &p_path) const {
- for (int i = 0; i < properties.size(); i++) {
- if (properties[i].name == p_path) {
- return i;
- }
- }
- ERR_FAIL_V(-1);
-}
-
-bool SceneReplicationConfig::property_get_spawn(const NodePath &p_path) {
- List<ReplicationProperty>::Element *E = properties.find(p_path);
- ERR_FAIL_COND_V(!E, false);
- return E->get().spawn;
-}
-
-void SceneReplicationConfig::property_set_spawn(const NodePath &p_path, bool p_enabled) {
- List<ReplicationProperty>::Element *E = properties.find(p_path);
- ERR_FAIL_COND(!E);
- if (E->get().spawn == p_enabled) {
- return;
- }
- E->get().spawn = p_enabled;
- spawn_props.clear();
- for (const ReplicationProperty &prop : properties) {
- if (prop.spawn) {
- spawn_props.push_back(p_path);
- }
- }
-}
-
-bool SceneReplicationConfig::property_get_sync(const NodePath &p_path) {
- List<ReplicationProperty>::Element *E = properties.find(p_path);
- ERR_FAIL_COND_V(!E, false);
- return E->get().sync;
-}
-
-void SceneReplicationConfig::property_set_sync(const NodePath &p_path, bool p_enabled) {
- List<ReplicationProperty>::Element *E = properties.find(p_path);
- ERR_FAIL_COND(!E);
- if (E->get().sync == p_enabled) {
- return;
- }
- E->get().sync = p_enabled;
- sync_props.clear();
- for (const ReplicationProperty &prop : properties) {
- if (prop.sync) {
- sync_props.push_back(p_path);
- }
- }
-}
-
-void SceneReplicationConfig::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_properties"), &SceneReplicationConfig::get_properties);
- ClassDB::bind_method(D_METHOD("add_property", "path", "index"), &SceneReplicationConfig::add_property, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("has_property", "path"), &SceneReplicationConfig::has_property);
- ClassDB::bind_method(D_METHOD("remove_property", "path"), &SceneReplicationConfig::remove_property);
- ClassDB::bind_method(D_METHOD("property_get_index", "path"), &SceneReplicationConfig::property_get_index);
- ClassDB::bind_method(D_METHOD("property_get_spawn", "path"), &SceneReplicationConfig::property_get_spawn);
- ClassDB::bind_method(D_METHOD("property_set_spawn", "path", "enabled"), &SceneReplicationConfig::property_set_spawn);
- ClassDB::bind_method(D_METHOD("property_get_sync", "path"), &SceneReplicationConfig::property_get_sync);
- ClassDB::bind_method(D_METHOD("property_set_sync", "path", "enabled"), &SceneReplicationConfig::property_set_sync);
-}
diff --git a/scene/resources/separation_ray_shape_2d.cpp b/scene/resources/separation_ray_shape_2d.cpp
index 0d6aee47d8..fea41061fd 100644
--- a/scene/resources/separation_ray_shape_2d.cpp
+++ b/scene/resources/separation_ray_shape_2d.cpp
@@ -57,7 +57,7 @@ void SeparationRayShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Transform2D xf;
xf.rotate(target_position.angle());
- xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
+ xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
Vector<Vector2> pts = {
xf.xform(Vector2(arrow_size, 0)),
diff --git a/scene/resources/separation_ray_shape_3d.h b/scene/resources/separation_ray_shape_3d.h
index 0e750a48e6..ae08ff7887 100644
--- a/scene/resources/separation_ray_shape_3d.h
+++ b/scene/resources/separation_ray_shape_3d.h
@@ -28,8 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SEPARATION_RAY_SHAPE_H
-#define SEPARATION_RAY_SHAPE_H
+#ifndef SEPARATION_RAY_SHAPE_3D_H
+#define SEPARATION_RAY_SHAPE_3D_H
+
#include "scene/resources/shape_3d.h"
class SeparationRayShape3D : public Shape3D {
@@ -53,4 +54,5 @@ public:
SeparationRayShape3D();
};
-#endif // SEPARATION_RAY_SHAPE_H
+
+#endif // SEPARATION_RAY_SHAPE_3D_H
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index d49157b1b8..18fd6c8d25 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -33,6 +33,7 @@
#include "core/io/file_access.h"
#include "scene/scene_string_names.h"
#include "servers/rendering/shader_language.h"
+#include "servers/rendering/shader_preprocessor.h"
#include "servers/rendering_server.h"
#include "texture.h"
@@ -40,7 +41,23 @@ Shader::Mode Shader::get_mode() const {
return mode;
}
+void Shader::_dependency_changed() {
+ RenderingServer::get_singleton()->shader_set_code(shader, RenderingServer::get_singleton()->shader_get_code(shader));
+ params_cache_dirty = true;
+
+ emit_changed();
+}
+
+void Shader::set_path(const String &p_path, bool p_take_over) {
+ Resource::set_path(p_path, p_take_over);
+ RS::get_singleton()->shader_set_path_hint(shader, p_path);
+}
+
void Shader::set_code(const String &p_code) {
+ for (Ref<ShaderInclude> E : include_dependencies) {
+ E->disconnect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed));
+ }
+
String type = ShaderLanguage::get_shader_type(p_code);
if (type == "canvas_item") {
@@ -55,7 +72,27 @@ void Shader::set_code(const String &p_code) {
mode = MODE_SPATIAL;
}
- RenderingServer::get_singleton()->shader_set_code(shader, p_code);
+ code = p_code;
+ String pp_code = p_code;
+
+ HashSet<Ref<ShaderInclude>> new_include_dependencies;
+
+ {
+ // Preprocessor must run here and not in the server because:
+ // 1) Need to keep track of include dependencies at resource level
+ // 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
+ ShaderPreprocessor preprocessor;
+ preprocessor.preprocess(p_code, pp_code, nullptr, nullptr, &new_include_dependencies);
+ }
+
+ // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
+ include_dependencies = new_include_dependencies;
+
+ for (Ref<ShaderInclude> E : include_dependencies) {
+ E->connect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed));
+ }
+
+ RenderingServer::get_singleton()->shader_set_code(shader, pp_code);
params_cache_dirty = true;
emit_changed();
@@ -63,10 +100,10 @@ void Shader::set_code(const String &p_code) {
String Shader::get_code() const {
_update_shader();
- return RenderingServer::get_singleton()->shader_get_code(shader);
+ return code;
}
-void Shader::get_param_list(List<PropertyInfo> *p_params) const {
+void Shader::get_param_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
List<PropertyInfo> local;
@@ -75,12 +112,16 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
params_cache_dirty = false;
for (PropertyInfo &pi : local) {
- if (default_textures.has(pi.name)) { //do not show default textures
+ bool is_group = pi.usage == PROPERTY_USAGE_GROUP || pi.usage == PROPERTY_USAGE_SUBGROUP;
+ if (!p_get_groups && is_group) {
continue;
}
- String original_name = pi.name;
- pi.name = "shader_param/" + pi.name;
- params_cache[pi.name] = original_name;
+ if (!is_group) {
+ if (default_textures.has(pi.name)) { //do not show default textures
+ continue;
+ }
+ params_cache[pi.name] = pi.name;
+ }
if (p_params) {
//small little hack
if (pi.type == Variant::RID) {
@@ -210,7 +251,7 @@ String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const
return "";
}
-Error ResourceFormatSaverShader::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverShader::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<Shader> shader = p_resource;
ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER);
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 11c9f60ce8..082b37d355 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -35,6 +35,7 @@
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "scene/resources/texture.h"
+#include "shader_include.h"
class Shader : public Resource {
GDCLASS(Shader, Resource);
@@ -53,6 +54,8 @@ public:
private:
RID shader;
Mode mode = MODE_SPATIAL;
+ HashSet<Ref<ShaderInclude>> include_dependencies;
+ String code;
// hack the name of performance
// shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make
@@ -61,6 +64,7 @@ private:
mutable HashMap<StringName, StringName> params_cache; //map a shader param to a material param..
HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures;
+ void _dependency_changed();
virtual void _update_shader() const; //used for visual shader
protected:
static void _bind_methods();
@@ -69,10 +73,12 @@ public:
//void set_mode(Mode p_mode);
virtual Mode get_mode() const;
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
+
void set_code(const String &p_code);
String get_code() const;
- void get_param_list(List<PropertyInfo> *p_params) const;
+ void get_param_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
bool has_param(const StringName &p_param) const;
void set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index = 0);
@@ -111,7 +117,7 @@ public:
class ResourceFormatSaverShader : public ResourceFormatSaver {
public:
- virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
virtual bool recognize(const Ref<Resource> &p_resource) const;
};
diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp
new file mode 100644
index 0000000000..42435fe3c7
--- /dev/null
+++ b/scene/resources/shader_include.cpp
@@ -0,0 +1,144 @@
+/*************************************************************************/
+/* shader_include.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 "shader_include.h"
+#include "servers/rendering/shader_language.h"
+#include "servers/rendering/shader_preprocessor.h"
+
+void ShaderInclude::_dependency_changed() {
+ emit_changed();
+}
+
+void ShaderInclude::set_code(const String &p_code) {
+ HashSet<Ref<ShaderInclude>> new_dependencies;
+ code = p_code;
+
+ for (Ref<ShaderInclude> E : dependencies) {
+ E->disconnect(SNAME("changed"), callable_mp(this, &ShaderInclude::_dependency_changed));
+ }
+
+ {
+ String pp_code;
+ ShaderPreprocessor preprocessor;
+ preprocessor.preprocess(p_code, pp_code, nullptr, nullptr, &new_dependencies);
+ }
+
+ // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
+ dependencies = new_dependencies;
+
+ for (Ref<ShaderInclude> E : dependencies) {
+ E->connect(SNAME("changed"), callable_mp(this, &ShaderInclude::_dependency_changed));
+ }
+
+ emit_changed();
+}
+
+String ShaderInclude::get_code() const {
+ return code;
+}
+
+void ShaderInclude::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_code", "code"), &ShaderInclude::set_code);
+ ClassDB::bind_method(D_METHOD("get_code"), &ShaderInclude::get_code);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code");
+}
+
+// ResourceFormatLoaderShaderInclude
+
+Ref<Resource> ResourceFormatLoaderShaderInclude::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ if (r_error) {
+ *r_error = ERR_FILE_CANT_OPEN;
+ }
+
+ Ref<ShaderInclude> shader_inc;
+ shader_inc.instantiate();
+
+ Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path);
+
+ String str;
+ str.parse_utf8((const char *)buffer.ptr(), buffer.size());
+
+ shader_inc->set_code(str);
+
+ if (r_error) {
+ *r_error = OK;
+ }
+
+ return shader_inc;
+}
+
+void ResourceFormatLoaderShaderInclude::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("gdshaderinc");
+}
+
+bool ResourceFormatLoaderShaderInclude::handles_type(const String &p_type) const {
+ return (p_type == "ShaderInclude");
+}
+
+String ResourceFormatLoaderShaderInclude::get_resource_type(const String &p_path) const {
+ String extension = p_path.get_extension().to_lower();
+ if (extension == "gdshaderinc") {
+ return "ShaderInclude";
+ }
+ return "";
+}
+
+// ResourceFormatSaverShaderInclude
+
+Error ResourceFormatSaverShaderInclude::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
+ Ref<ShaderInclude> shader_inc = p_resource;
+ ERR_FAIL_COND_V(shader_inc.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = shader_inc->get_code();
+
+ Error error;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &error);
+
+ ERR_FAIL_COND_V_MSG(error, error, "Cannot save shader include '" + p_path + "'.");
+
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
+
+ return OK;
+}
+
+void ResourceFormatSaverShaderInclude::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
+ const ShaderInclude *shader_inc = Object::cast_to<ShaderInclude>(*p_resource);
+ if (shader_inc != nullptr) {
+ p_extensions->push_back("gdshaderinc");
+ }
+}
+
+bool ResourceFormatSaverShaderInclude::recognize(const Ref<Resource> &p_resource) const {
+ return p_resource->get_class_name() == "ShaderInclude"; //only shader, not inherited
+}
diff --git a/scene/resources/shader_include.h b/scene/resources/shader_include.h
new file mode 100644
index 0000000000..b0865e3a61
--- /dev/null
+++ b/scene/resources/shader_include.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* shader_include.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 SHADER_INCLUDE_H
+#define SHADER_INCLUDE_H
+
+#include "core/io/resource.h"
+#include "core/io/resource_loader.h"
+#include "core/io/resource_saver.h"
+#include "core/templates/hash_set.h"
+
+class ShaderInclude : public Resource {
+ GDCLASS(ShaderInclude, Resource);
+ OBJ_SAVE_TYPE(ShaderInclude);
+
+private:
+ String code;
+ HashSet<Ref<ShaderInclude>> dependencies;
+ void _dependency_changed();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_code(const String &p_text);
+ String get_code() const;
+};
+
+class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader {
+public:
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverShaderInclude : public ResourceFormatSaver {
+public:
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+};
+
+#endif // SHADER_INCLUDE_H
diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h
index 77e79a269d..58fe723d89 100644
--- a/scene/resources/shape_3d.h
+++ b/scene/resources/shape_3d.h
@@ -73,4 +73,4 @@ public:
~Shape3D();
};
-#endif // SHAPE_H
+#endif // SHAPE_3D_H
diff --git a/scene/resources/skeleton_modification_2d.h b/scene/resources/skeleton_modification_2d.h
index 3b9235ffd8..4c49119df0 100644
--- a/scene/resources/skeleton_modification_2d.h
+++ b/scene/resources/skeleton_modification_2d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2D_H
-#define SKELETONMODIFICATION2D_H
+#ifndef SKELETON_MODIFICATION_2D_H
+#define SKELETON_MODIFICATION_2D_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_stack_2d.h"
@@ -86,4 +86,4 @@ public:
SkeletonModification2D();
};
-#endif // SKELETONMODIFICATION2D_H
+#endif // SKELETON_MODIFICATION_2D_H
diff --git a/scene/resources/skeleton_modification_2d_ccdik.h b/scene/resources/skeleton_modification_2d_ccdik.h
index 31485fa31f..e49dfca5b5 100644
--- a/scene/resources/skeleton_modification_2d_ccdik.h
+++ b/scene/resources/skeleton_modification_2d_ccdik.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DCCDIK_H
-#define SKELETONMODIFICATION2DCCDIK_H
+#ifndef SKELETON_MODIFICATION_2D_CCDIK_H
+#define SKELETON_MODIFICATION_2D_CCDIK_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -113,4 +113,4 @@ public:
~SkeletonModification2DCCDIK();
};
-#endif // SKELETONMODIFICATION2DCCDIK_H
+#endif // SKELETON_MODIFICATION_2D_CCDIK_H
diff --git a/scene/resources/skeleton_modification_2d_fabrik.h b/scene/resources/skeleton_modification_2d_fabrik.h
index d5077084ef..4a875d039f 100644
--- a/scene/resources/skeleton_modification_2d_fabrik.h
+++ b/scene/resources/skeleton_modification_2d_fabrik.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DFABRIK_H
-#define SKELETONMODIFICATION2DFABRIK_H
+#ifndef SKELETON_MODIFICATION_2D_FABRIK_H
+#define SKELETON_MODIFICATION_2D_FABRIK_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -105,4 +105,4 @@ public:
~SkeletonModification2DFABRIK();
};
-#endif // SKELETONMODIFICATION2DFABRIK_H
+#endif // SKELETON_MODIFICATION_2D_FABRIK_H
diff --git a/scene/resources/skeleton_modification_2d_jiggle.h b/scene/resources/skeleton_modification_2d_jiggle.h
index a1abca6564..b9080eafa9 100644
--- a/scene/resources/skeleton_modification_2d_jiggle.h
+++ b/scene/resources/skeleton_modification_2d_jiggle.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DJIGGLE_H
-#define SKELETONMODIFICATION2DJIGGLE_H
+#ifndef SKELETON_MODIFICATION_2D_JIGGLE_H
+#define SKELETON_MODIFICATION_2D_JIGGLE_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -136,4 +136,4 @@ public:
~SkeletonModification2DJiggle();
};
-#endif // SKELETONMODIFICATION2DJIGGLE_H
+#endif // SKELETON_MODIFICATION_2D_JIGGLE_H
diff --git a/scene/resources/skeleton_modification_2d_lookat.h b/scene/resources/skeleton_modification_2d_lookat.h
index ff91b92e7d..e4d7afa605 100644
--- a/scene/resources/skeleton_modification_2d_lookat.h
+++ b/scene/resources/skeleton_modification_2d_lookat.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DLOOKAT_H
-#define SKELETONMODIFICATION2DLOOKAT_H
+#ifndef SKELETON_MODIFICATION_2D_LOOKAT_H
+#define SKELETON_MODIFICATION_2D_LOOKAT_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -97,4 +97,4 @@ public:
~SkeletonModification2DLookAt();
};
-#endif // SKELETONMODIFICATION2DLOOKAT_H
+#endif // SKELETON_MODIFICATION_2D_LOOKAT_H
diff --git a/scene/resources/skeleton_modification_2d_physicalbones.h b/scene/resources/skeleton_modification_2d_physicalbones.h
index 373ff666ee..55482b2cca 100644
--- a/scene/resources/skeleton_modification_2d_physicalbones.h
+++ b/scene/resources/skeleton_modification_2d_physicalbones.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DPHYSICALBONES_H
-#define SKELETONMODIFICATION2DPHYSICALBONES_H
+#ifndef SKELETON_MODIFICATION_2D_PHYSICALBONES_H
+#define SKELETON_MODIFICATION_2D_PHYSICALBONES_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -79,4 +79,4 @@ public:
~SkeletonModification2DPhysicalBones();
};
-#endif // SKELETONMODIFICATION2DPHYSICALBONES_H
+#endif // SKELETON_MODIFICATION_2D_PHYSICALBONES_H
diff --git a/scene/resources/skeleton_modification_2d_stackholder.h b/scene/resources/skeleton_modification_2d_stackholder.h
index 99d9f6f381..4da9fcc1f6 100644
--- a/scene/resources/skeleton_modification_2d_stackholder.h
+++ b/scene/resources/skeleton_modification_2d_stackholder.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DSTACKHOLDER_H
-#define SKELETONMODIFICATION2DSTACKHOLDER_H
+#ifndef SKELETON_MODIFICATION_2D_STACKHOLDER_H
+#define SKELETON_MODIFICATION_2D_STACKHOLDER_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -61,4 +61,4 @@ public:
~SkeletonModification2DStackHolder();
};
-#endif // SKELETONMODIFICATION2DSTACKHOLDER_H
+#endif // SKELETON_MODIFICATION_2D_STACKHOLDER_H
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.h b/scene/resources/skeleton_modification_2d_twoboneik.h
index fc14d35f70..e1dbb6cfda 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.h
+++ b/scene/resources/skeleton_modification_2d_twoboneik.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION2DTWOBONEIK_H
-#define SKELETONMODIFICATION2DTWOBONEIK_H
+#ifndef SKELETON_MODIFICATION_2D_TWOBONEIK_H
+#define SKELETON_MODIFICATION_2D_TWOBONEIK_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -104,4 +104,4 @@ public:
~SkeletonModification2DTwoBoneIK();
};
-#endif // SKELETONMODIFICATION2DTWOBONEIK_H
+#endif // SKELETON_MODIFICATION_2D_TWOBONEIK_H
diff --git a/scene/resources/skeleton_modification_3d.h b/scene/resources/skeleton_modification_3d.h
index ab736fcbd2..6daf5efcd9 100644
--- a/scene/resources/skeleton_modification_3d.h
+++ b/scene/resources/skeleton_modification_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATION3D_H
-#define SKELETONMODIFICATION3D_H
+#ifndef SKELETON_MODIFICATION_3D_H
+#define SKELETON_MODIFICATION_3D_H
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_stack_3d.h"
@@ -76,4 +76,4 @@ public:
SkeletonModification3D();
};
-#endif // SKELETONMODIFICATION3D_H
+#endif // SKELETON_MODIFICATION_3D_H
diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h
index 873ab8aa5a..7098794038 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.h
+++ b/scene/resources/skeleton_modification_3d_ccdik.h
@@ -32,8 +32,8 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DCCDIK_H
-#define SKELETONMODIFICATION3DCCDIK_H
+#ifndef SKELETON_MODIFICATION_3D_CCDIK_H
+#define SKELETON_MODIFICATION_3D_CCDIK_H
class SkeletonModification3DCCDIK : public SkeletonModification3D {
GDCLASS(SkeletonModification3DCCDIK, SkeletonModification3D);
@@ -111,4 +111,4 @@ public:
~SkeletonModification3DCCDIK();
};
-#endif //SKELETONMODIFICATION3DCCDIK_H
+#endif // SKELETON_MODIFICATION_3D_CCDIK_H
diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h
index cc4d3a5e20..3d66bb6d99 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.h
+++ b/scene/resources/skeleton_modification_3d_fabrik.h
@@ -32,8 +32,8 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DFABRIK_H
-#define SKELETONMODIFICATION3DFABRIK_H
+#ifndef SKELETON_MODIFICATION_3D_FABRIK_H
+#define SKELETON_MODIFICATION_3D_FABRIK_H
class SkeletonModification3DFABRIK : public SkeletonModification3D {
GDCLASS(SkeletonModification3DFABRIK, SkeletonModification3D);
@@ -121,4 +121,4 @@ public:
~SkeletonModification3DFABRIK();
};
-#endif //SKELETONMODIFICATION3DFABRIK_H
+#endif // SKELETON_MODIFICATION_3D_FABRIK_H
diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h
index 7ec5ed4f11..f41ffcd58d 100644
--- a/scene/resources/skeleton_modification_3d_jiggle.h
+++ b/scene/resources/skeleton_modification_3d_jiggle.h
@@ -32,8 +32,8 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DJIGGLE_H
-#define SKELETONMODIFICATION3DJIGGLE_H
+#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H
+#define SKELETON_MODIFICATION_3D_JIGGLE_H
class SkeletonModification3DJiggle : public SkeletonModification3D {
GDCLASS(SkeletonModification3DJiggle, SkeletonModification3D);
@@ -135,4 +135,4 @@ public:
~SkeletonModification3DJiggle();
};
-#endif //SKELETONMODIFICATION3DJIGGLE_H
+#endif // SKELETON_MODIFICATION_3D_JIGGLE_H
diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h
index 9f5120a0fd..4e5714b5dc 100644
--- a/scene/resources/skeleton_modification_3d_lookat.h
+++ b/scene/resources/skeleton_modification_3d_lookat.h
@@ -31,8 +31,8 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DLOOKAT_H
-#define SKELETONMODIFICATION3DLOOKAT_H
+#ifndef SKELETON_MODIFICATION_3D_LOOKAT_H
+#define SKELETON_MODIFICATION_3D_LOOKAT_H
class SkeletonModification3DLookAt : public SkeletonModification3D {
GDCLASS(SkeletonModification3DLookAt, SkeletonModification3D);
@@ -86,4 +86,4 @@ public:
~SkeletonModification3DLookAt();
};
-#endif //SKELETONMODIFICATION3DLOOKAT_H
+#endif // SKELETON_MODIFICATION_3D_LOOKAT_H
diff --git a/scene/resources/skeleton_modification_3d_stackholder.h b/scene/resources/skeleton_modification_3d_stackholder.h
index 5780d7d43f..ae22099158 100644
--- a/scene/resources/skeleton_modification_3d_stackholder.h
+++ b/scene/resources/skeleton_modification_3d_stackholder.h
@@ -31,8 +31,8 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DSTACKHOLDER_H
-#define SKELETONMODIFICATION3DSTACKHOLDER_H
+#ifndef SKELETON_MODIFICATION_3D_STACKHOLDER_H
+#define SKELETON_MODIFICATION_3D_STACKHOLDER_H
class SkeletonModification3DStackHolder : public SkeletonModification3D {
GDCLASS(SkeletonModification3DStackHolder, SkeletonModification3D);
@@ -56,4 +56,4 @@ public:
~SkeletonModification3DStackHolder();
};
-#endif //SKELETONMODIFICATION3DSTACKHOLDER_H
+#endif // SKELETON_MODIFICATION_3D_STACKHOLDER_H
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h
index a4ddc6cee7..57e8237511 100644
--- a/scene/resources/skeleton_modification_3d_twoboneik.h
+++ b/scene/resources/skeleton_modification_3d_twoboneik.h
@@ -31,8 +31,8 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DTWOBONEIK_H
-#define SKELETONMODIFICATION3DTWOBONEIK_H
+#ifndef SKELETON_MODIFICATION_3D_TWOBONEIK_H
+#define SKELETON_MODIFICATION_3D_TWOBONEIK_H
class SkeletonModification3DTwoBoneIK : public SkeletonModification3D {
GDCLASS(SkeletonModification3DTwoBoneIK, SkeletonModification3D);
@@ -115,4 +115,4 @@ public:
~SkeletonModification3DTwoBoneIK();
};
-#endif //SKELETONMODIFICATION3DTWOBONEIK_H
+#endif // SKELETON_MODIFICATION_3D_TWOBONEIK_H
diff --git a/scene/resources/skeleton_modification_stack_2d.h b/scene/resources/skeleton_modification_stack_2d.h
index 7b5f8e0322..ceffd71368 100644
--- a/scene/resources/skeleton_modification_stack_2d.h
+++ b/scene/resources/skeleton_modification_stack_2d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATIONSTACK2D_H
-#define SKELETONMODIFICATIONSTACK2D_H
+#ifndef SKELETON_MODIFICATION_STACK_2D_H
+#define SKELETON_MODIFICATION_STACK_2D_H
#include "scene/2d/skeleton_2d.h"
#include "scene/resources/skeleton_modification_2d.h"
@@ -96,4 +96,4 @@ public:
SkeletonModificationStack2D();
};
-#endif // SKELETONMODIFICATION2D_H
+#endif // SKELETON_MODIFICATION_STACK_2D_H
diff --git a/scene/resources/skeleton_modification_stack_3d.h b/scene/resources/skeleton_modification_stack_3d.h
index 2c17fba2c5..4ff1bd1e33 100644
--- a/scene/resources/skeleton_modification_stack_3d.h
+++ b/scene/resources/skeleton_modification_stack_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETONMODIFICATIONSTACK3D_H
-#define SKELETONMODIFICATIONSTACK3D_H
+#ifndef SKELETON_MODIFICATION_STACK_3D_H
+#define SKELETON_MODIFICATION_STACK_3D_H
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
@@ -88,4 +88,4 @@ public:
SkeletonModificationStack3D();
};
-#endif // SKELETONMODIFICATIONSTACK3D_H
+#endif // SKELETON_MODIFICATION_STACK_3D_H
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
new file mode 100644
index 0000000000..bfb4bb6e2b
--- /dev/null
+++ b/scene/resources/skeleton_profile.cpp
@@ -0,0 +1,835 @@
+/*************************************************************************/
+/* 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("groups/")) {
+ 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);
+ } else {
+ return false;
+ }
+ }
+
+ if (path.begins_with("bones/")) {
+ 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 == "bone_parent") {
+ set_bone_parent(which, p_value);
+ } else if (what == "tail_direction") {
+ set_tail_direction(which, static_cast<TailDirection>((int)p_value));
+ } else if (what == "bone_tail") {
+ set_bone_tail(which, p_value);
+ } else if (what == "reference_pose") {
+ set_reference_pose(which, p_value);
+ } else if (what == "handle_offset") {
+ set_handle_offset(which, p_value);
+ } else if (what == "group") {
+ set_group(which, p_value);
+ } else if (what == "require") {
+ set_require(which, p_value);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("groups/")) {
+ 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);
+ } else {
+ return false;
+ }
+ }
+
+ if (path.begins_with("bones/")) {
+ 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 == "bone_parent") {
+ r_ret = get_bone_parent(which);
+ } else if (what == "tail_direction") {
+ r_ret = get_tail_direction(which);
+ } else if (what == "bone_tail") {
+ r_ret = get_bone_tail(which);
+ } else if (what == "reference_pose") {
+ r_ret = get_reference_pose(which);
+ } else if (what == "handle_offset") {
+ r_ret = get_handle_offset(which);
+ } else if (what == "group") {
+ r_ret = get_group(which);
+ } else if (what == "require") {
+ r_ret = is_require(which);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SkeletonProfile::_validate_property(PropertyInfo &property) const {
+ if (is_read_only) {
+ if (property.name == ("group_size") || property.name == ("bone_size") || property.name == ("root_bone") || property.name == ("scale_base_bone")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+ }
+
+ if (property.name == ("root_bone") || property.name == ("scale_base_bone")) {
+ String hint = "";
+ for (int i = 0; i < bones.size(); i++) {
+ hint += i == 0 ? String(bones[i].bone_name) : "," + String(bones[i].bone_name);
+ }
+ property.hint_string = hint;
+ }
+
+ PackedStringArray split = property.name.split("/");
+ if (split.size() == 3 && split[0] == "bones") {
+ if (split[2] == "bone_tail" && get_tail_direction(split[1].to_int()) != TAIL_DIRECTION_SPECIFIC_CHILD) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+ }
+}
+
+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 = "groups/" + 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 = "bones/" + itos(i) + "/";
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_name"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_parent"));
+ p_list->push_back(PropertyInfo(Variant::INT, path + "tail_direction", PROPERTY_HINT_ENUM, "AverageChildren,SpecificChild,End"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_tail"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, path + "reference_pose"));
+ 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));
+ p_list->push_back(PropertyInfo(Variant::BOOL, path + "require"));
+ }
+
+ for (PropertyInfo &E : *p_list) {
+ _validate_property(E);
+ }
+}
+
+StringName SkeletonProfile::get_root_bone() {
+ return root_bone;
+}
+
+void SkeletonProfile::set_root_bone(StringName p_bone_name) {
+ if (is_read_only) {
+ return;
+ }
+ root_bone = p_bone_name;
+}
+
+StringName SkeletonProfile::get_scale_base_bone() {
+ return scale_base_bone;
+}
+
+void SkeletonProfile::set_scale_base_bone(StringName p_bone_name) {
+ if (is_read_only) {
+ return;
+ }
+ scale_base_bone = p_bone_name;
+}
+
+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();
+}
+
+int SkeletonProfile::find_bone(StringName p_bone_name) const {
+ if (p_bone_name == StringName()) {
+ return -1;
+ }
+ for (int i = 0; i < bones.size(); i++) {
+ if (bones[i].bone_name == p_bone_name) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+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");
+}
+
+StringName SkeletonProfile::get_bone_parent(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_parent;
+}
+
+void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName p_bone_parent) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_parent = p_bone_parent;
+ emit_signal("profile_updated");
+}
+
+SkeletonProfile::TailDirection SkeletonProfile::get_tail_direction(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), TAIL_DIRECTION_AVERAGE_CHILDREN);
+ return bones[p_bone_idx].tail_direction;
+}
+
+void SkeletonProfile::set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].tail_direction = p_tail_direction;
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+StringName SkeletonProfile::get_bone_tail(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_tail;
+}
+
+void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName p_bone_tail) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_tail = p_bone_tail;
+ emit_signal("profile_updated");
+}
+
+Transform3D SkeletonProfile::get_reference_pose(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Transform3D());
+ return bones[p_bone_idx].reference_pose;
+}
+
+void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].reference_pose = p_reference_pose;
+ 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::is_require(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), false);
+ return bones[p_bone_idx].require;
+}
+
+void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].require = p_require;
+ 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_root_bone", "bone_name"), &SkeletonProfile::set_root_bone);
+ ClassDB::bind_method(D_METHOD("get_root_bone"), &SkeletonProfile::get_root_bone);
+
+ ClassDB::bind_method(D_METHOD("set_scale_base_bone", "bone_name"), &SkeletonProfile::set_scale_base_bone);
+ ClassDB::bind_method(D_METHOD("get_scale_base_bone"), &SkeletonProfile::get_scale_base_bone);
+
+ 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("find_bone", "bone_name"), &SkeletonProfile::find_bone);
+
+ 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_bone_parent", "bone_idx"), &SkeletonProfile::get_bone_parent);
+ ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "bone_parent"), &SkeletonProfile::set_bone_parent);
+
+ ClassDB::bind_method(D_METHOD("get_tail_direction", "bone_idx"), &SkeletonProfile::get_tail_direction);
+ ClassDB::bind_method(D_METHOD("set_tail_direction", "bone_idx", "tail_direction"), &SkeletonProfile::set_tail_direction);
+
+ ClassDB::bind_method(D_METHOD("get_bone_tail", "bone_idx"), &SkeletonProfile::get_bone_tail);
+ ClassDB::bind_method(D_METHOD("set_bone_tail", "bone_idx", "bone_tail"), &SkeletonProfile::set_bone_tail);
+
+ ClassDB::bind_method(D_METHOD("get_reference_pose", "bone_idx"), &SkeletonProfile::get_reference_pose);
+ ClassDB::bind_method(D_METHOD("set_reference_pose", "bone_idx", "bone_name"), &SkeletonProfile::set_reference_pose);
+
+ 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::STRING_NAME, "root_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_root_bone", "get_root_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "scale_base_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_scale_base_bone", "get_scale_base_bone");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "group_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Groups,groups/"), "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,bones/"), "set_bone_size", "get_bone_size");
+
+ ADD_SIGNAL(MethodInfo("profile_updated"));
+
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_AVERAGE_CHILDREN);
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_SPECIFIC_CHILD);
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_END);
+}
+
+SkeletonProfile::SkeletonProfile() {
+}
+
+SkeletonProfile::~SkeletonProfile() {
+}
+
+SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
+ is_read_only = true;
+
+ root_bone = "Root";
+ scale_base_bone = "Hips";
+
+ 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].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
+ bones.write[0].handle_offset = Vector2(0.5, 0.91);
+ bones.write[0].group = "Body";
+
+ bones.write[1].bone_name = "Hips";
+ bones.write[1].bone_parent = "Root";
+ bones.write[1].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[1].bone_tail = "Spine";
+ bones.write[1].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0);
+ bones.write[1].handle_offset = Vector2(0.5, 0.5);
+ bones.write[1].group = "Body";
+ bones.write[1].require = true;
+
+ bones.write[2].bone_name = "Spine";
+ bones.write[2].bone_parent = "Hips";
+ bones.write[2].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[2].handle_offset = Vector2(0.5, 0.43);
+ bones.write[2].group = "Body";
+ bones.write[2].require = true;
+
+ bones.write[3].bone_name = "Chest";
+ bones.write[3].bone_parent = "Spine";
+ bones.write[3].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[3].handle_offset = Vector2(0.5, 0.36);
+ bones.write[3].group = "Body";
+
+ bones.write[4].bone_name = "UpperChest";
+ bones.write[4].bone_parent = "Chest";
+ bones.write[4].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[4].handle_offset = Vector2(0.5, 0.29);
+ bones.write[4].group = "Body";
+
+ bones.write[5].bone_name = "Neck";
+ bones.write[5].bone_parent = "UpperChest";
+ bones.write[5].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[5].bone_tail = "Head";
+ bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[5].handle_offset = Vector2(0.5, 0.23);
+ bones.write[5].group = "Body";
+ bones.write[5].require = true;
+
+ bones.write[6].bone_name = "Head";
+ bones.write[6].bone_parent = "Neck";
+ bones.write[6].tail_direction = TAIL_DIRECTION_END;
+ bones.write[6].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[6].handle_offset = Vector2(0.5, 0.18);
+ bones.write[6].group = "Body";
+ bones.write[6].require = true;
+
+ bones.write[7].bone_name = "LeftEye";
+ bones.write[7].bone_parent = "Head";
+ bones.write[7].reference_pose = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, 0.05, 0.15, 0);
+ bones.write[7].handle_offset = Vector2(0.6, 0.46);
+ bones.write[7].group = "Face";
+
+ bones.write[8].bone_name = "RightEye";
+ bones.write[8].bone_parent = "Head";
+ bones.write[8].reference_pose = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, -0.05, 0.15, 0);
+ bones.write[8].handle_offset = Vector2(0.37, 0.46);
+ bones.write[8].group = "Face";
+
+ bones.write[9].bone_name = "Jaw";
+ bones.write[9].bone_parent = "Head";
+ bones.write[9].reference_pose = Transform3D(-1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0.05, 0.05);
+ bones.write[9].handle_offset = Vector2(0.46, 0.75);
+ bones.write[9].group = "Face";
+
+ bones.write[10].bone_name = "LeftShoulder";
+ bones.write[10].bone_parent = "UpperChest";
+ bones.write[10].reference_pose = Transform3D(0, 1, 0, 0, 0, 1, 1, 0, 0, 0.05, 0.1, 0);
+ bones.write[10].handle_offset = Vector2(0.55, 0.235);
+ bones.write[10].group = "Body";
+ bones.write[10].require = true;
+
+ bones.write[11].bone_name = "LeftUpperArm";
+ bones.write[11].bone_parent = "LeftShoulder";
+ bones.write[11].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
+ bones.write[11].handle_offset = Vector2(0.6, 0.24);
+ bones.write[11].group = "Body";
+ bones.write[11].require = true;
+
+ bones.write[12].bone_name = "LeftLowerArm";
+ bones.write[12].bone_parent = "LeftUpperArm";
+ bones.write[12].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
+ bones.write[12].handle_offset = Vector2(0.7, 0.24);
+ bones.write[12].group = "Body";
+ bones.write[12].require = true;
+
+ bones.write[13].bone_name = "LeftHand";
+ bones.write[13].bone_parent = "LeftLowerArm";
+ bones.write[13].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[13].bone_tail = "LeftMiddleProximal";
+ bones.write[13].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
+ bones.write[13].handle_offset = Vector2(0.82, 0.235);
+ bones.write[13].group = "Body";
+ bones.write[13].require = true;
+
+ bones.write[14].bone_name = "LeftThumbMetacarpal";
+ bones.write[14].bone_parent = "LeftHand";
+ bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0.707, 0.577, 0.408, -0.707, 0.577, 0.408, -0.025, 0, 0);
+ bones.write[14].handle_offset = Vector2(0.4, 0.8);
+ bones.write[14].group = "LeftHand";
+
+ bones.write[15].bone_name = "LeftThumbProximal";
+ bones.write[15].bone_parent = "LeftThumbMetacarpal";
+ bones.write[15].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[15].handle_offset = Vector2(0.3, 0.69);
+ bones.write[15].group = "LeftHand";
+
+ bones.write[16].bone_name = "LeftThumbDistal";
+ bones.write[16].bone_parent = "LeftThumbProximal";
+ bones.write[16].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[16].handle_offset = Vector2(0.23, 0.555);
+ bones.write[16].group = "LeftHand";
+
+ bones.write[17].bone_name = "LeftIndexProximal";
+ bones.write[17].bone_parent = "LeftHand";
+ bones.write[17].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.025, 0.075, 0);
+ bones.write[17].handle_offset = Vector2(0.413, 0.52);
+ bones.write[17].group = "LeftHand";
+
+ bones.write[18].bone_name = "LeftIndexIntermediate";
+ bones.write[18].bone_parent = "LeftIndexProximal";
+ bones.write[18].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[18].handle_offset = Vector2(0.403, 0.36);
+ bones.write[18].group = "LeftHand";
+
+ bones.write[19].bone_name = "LeftIndexDistal";
+ bones.write[19].bone_parent = "LeftIndexIntermediate";
+ bones.write[19].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[19].handle_offset = Vector2(0.403, 0.255);
+ bones.write[19].group = "LeftHand";
+
+ bones.write[20].bone_name = "LeftMiddleProximal";
+ bones.write[20].bone_parent = "LeftHand";
+ bones.write[20].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[20].handle_offset = Vector2(0.5, 0.51);
+ bones.write[20].group = "LeftHand";
+
+ bones.write[21].bone_name = "LeftMiddleIntermediate";
+ bones.write[21].bone_parent = "LeftMiddleProximal";
+ bones.write[21].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[21].handle_offset = Vector2(0.5, 0.345);
+ bones.write[21].group = "LeftHand";
+
+ bones.write[22].bone_name = "LeftMiddleDistal";
+ bones.write[22].bone_parent = "LeftMiddleIntermediate";
+ bones.write[22].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[22].handle_offset = Vector2(0.5, 0.22);
+ bones.write[22].group = "LeftHand";
+
+ bones.write[23].bone_name = "LeftRingProximal";
+ bones.write[23].bone_parent = "LeftHand";
+ bones.write[23].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.025, 0.075, 0);
+ bones.write[23].handle_offset = Vector2(0.586, 0.52);
+ bones.write[23].group = "LeftHand";
+
+ bones.write[24].bone_name = "LeftRingIntermediate";
+ bones.write[24].bone_parent = "LeftRingProximal";
+ bones.write[24].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[24].handle_offset = Vector2(0.59, 0.36);
+ bones.write[24].group = "LeftHand";
+
+ bones.write[25].bone_name = "LeftRingDistal";
+ bones.write[25].bone_parent = "LeftRingIntermediate";
+ bones.write[25].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[25].handle_offset = Vector2(0.591, 0.25);
+ bones.write[25].group = "LeftHand";
+
+ bones.write[26].bone_name = "LeftLittleProximal";
+ bones.write[26].bone_parent = "LeftHand";
+ bones.write[26].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0.05, 0);
+ bones.write[26].handle_offset = Vector2(0.663, 0.543);
+ bones.write[26].group = "LeftHand";
+
+ bones.write[27].bone_name = "LeftLittleIntermediate";
+ bones.write[27].bone_parent = "LeftLittleProximal";
+ bones.write[27].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[27].handle_offset = Vector2(0.672, 0.415);
+ bones.write[27].group = "LeftHand";
+
+ bones.write[28].bone_name = "LeftLittleDistal";
+ bones.write[28].bone_parent = "LeftLittleIntermediate";
+ bones.write[28].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[28].handle_offset = Vector2(0.672, 0.32);
+ bones.write[28].group = "LeftHand";
+
+ bones.write[29].bone_name = "RightShoulder";
+ bones.write[29].bone_parent = "UpperChest";
+ bones.write[29].reference_pose = Transform3D(0, -1, 0, 0, 0, 1, -1, 0, 0, -0.05, 0.1, 0);
+ bones.write[29].handle_offset = Vector2(0.45, 0.235);
+ bones.write[29].group = "Body";
+ bones.write[29].require = true;
+
+ bones.write[30].bone_name = "RightUpperArm";
+ bones.write[30].bone_parent = "RightShoulder";
+ bones.write[30].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
+ bones.write[30].handle_offset = Vector2(0.4, 0.24);
+ bones.write[30].group = "Body";
+ bones.write[30].require = true;
+
+ bones.write[31].bone_name = "RightLowerArm";
+ bones.write[31].bone_parent = "RightUpperArm";
+ bones.write[31].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
+ bones.write[31].handle_offset = Vector2(0.3, 0.24);
+ bones.write[31].group = "Body";
+ bones.write[31].require = true;
+
+ bones.write[32].bone_name = "RightHand";
+ bones.write[32].bone_parent = "RightLowerArm";
+ bones.write[32].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[32].bone_tail = "RightMiddleProximal";
+ bones.write[32].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
+ bones.write[32].handle_offset = Vector2(0.18, 0.235);
+ bones.write[32].group = "Body";
+ bones.write[32].require = true;
+
+ bones.write[33].bone_name = "RightThumbMetacarpal";
+ bones.write[33].bone_parent = "RightHand";
+ bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, -0.707, 0.577, 0.408, 0.707, 0.577, 0.408, 0.025, 0, 0);
+ bones.write[33].handle_offset = Vector2(0.6, 0.8);
+ bones.write[33].group = "RightHand";
+
+ bones.write[34].bone_name = "RightThumbProximal";
+ bones.write[34].bone_parent = "RightThumbMetacarpal";
+ bones.write[34].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[34].handle_offset = Vector2(0.7, 0.69);
+ bones.write[34].group = "RightHand";
+
+ bones.write[35].bone_name = "RightThumbDistal";
+ bones.write[35].bone_parent = "RightThumbProximal";
+ bones.write[35].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[35].handle_offset = Vector2(0.77, 0.555);
+ bones.write[35].group = "RightHand";
+
+ bones.write[36].bone_name = "RightIndexProximal";
+ bones.write[36].bone_parent = "RightHand";
+ bones.write[36].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.025, 0.075, 0);
+ bones.write[36].handle_offset = Vector2(0.587, 0.52);
+ bones.write[36].group = "RightHand";
+
+ bones.write[37].bone_name = "RightIndexIntermediate";
+ bones.write[37].bone_parent = "RightIndexProximal";
+ bones.write[37].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[37].handle_offset = Vector2(0.597, 0.36);
+ bones.write[37].group = "RightHand";
+
+ bones.write[38].bone_name = "RightIndexDistal";
+ bones.write[38].bone_parent = "RightIndexIntermediate";
+ bones.write[38].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[38].handle_offset = Vector2(0.597, 0.255);
+ bones.write[38].group = "RightHand";
+
+ bones.write[39].bone_name = "RightMiddleProximal";
+ bones.write[39].bone_parent = "RightHand";
+ bones.write[39].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[39].handle_offset = Vector2(0.5, 0.51);
+ bones.write[39].group = "RightHand";
+
+ bones.write[40].bone_name = "RightMiddleIntermediate";
+ bones.write[40].bone_parent = "RightMiddleProximal";
+ bones.write[40].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[40].handle_offset = Vector2(0.5, 0.345);
+ bones.write[40].group = "RightHand";
+
+ bones.write[41].bone_name = "RightMiddleDistal";
+ bones.write[41].bone_parent = "RightMiddleIntermediate";
+ bones.write[41].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[41].handle_offset = Vector2(0.5, 0.22);
+ bones.write[41].group = "RightHand";
+
+ bones.write[42].bone_name = "RightRingProximal";
+ bones.write[42].bone_parent = "RightHand";
+ bones.write[42].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.025, 0.075, 0);
+ bones.write[42].handle_offset = Vector2(0.414, 0.52);
+ bones.write[42].group = "RightHand";
+
+ bones.write[43].bone_name = "RightRingIntermediate";
+ bones.write[43].bone_parent = "RightRingProximal";
+ bones.write[43].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[43].handle_offset = Vector2(0.41, 0.36);
+ bones.write[43].group = "RightHand";
+
+ bones.write[44].bone_name = "RightRingDistal";
+ bones.write[44].bone_parent = "RightRingIntermediate";
+ bones.write[44].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[44].handle_offset = Vector2(0.409, 0.25);
+ bones.write[44].group = "RightHand";
+
+ bones.write[45].bone_name = "RightLittleProximal";
+ bones.write[45].bone_parent = "RightHand";
+ bones.write[45].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05, 0.05, 0);
+ bones.write[45].handle_offset = Vector2(0.337, 0.543);
+ bones.write[45].group = "RightHand";
+
+ bones.write[46].bone_name = "RightLittleIntermediate";
+ bones.write[46].bone_parent = "RightLittleProximal";
+ bones.write[46].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[46].handle_offset = Vector2(0.328, 0.415);
+ bones.write[46].group = "RightHand";
+
+ bones.write[47].bone_name = "RightLittleDistal";
+ bones.write[47].bone_parent = "RightLittleIntermediate";
+ bones.write[47].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[47].handle_offset = Vector2(0.328, 0.32);
+ bones.write[47].group = "RightHand";
+
+ bones.write[48].bone_name = "LeftUpperLeg";
+ bones.write[48].bone_parent = "Hips";
+ bones.write[48].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, 0.1, 0, 0);
+ bones.write[48].handle_offset = Vector2(0.549, 0.49);
+ bones.write[48].group = "Body";
+ bones.write[48].require = true;
+
+ bones.write[49].bone_name = "LeftLowerLeg";
+ bones.write[49].bone_parent = "LeftUpperLeg";
+ bones.write[49].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
+ bones.write[49].handle_offset = Vector2(0.548, 0.683);
+ bones.write[49].group = "Body";
+ bones.write[49].require = true;
+
+ bones.write[50].bone_name = "LeftFoot";
+ bones.write[50].bone_parent = "LeftLowerLeg";
+ bones.write[50].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
+ bones.write[50].handle_offset = Vector2(0.545, 0.9);
+ bones.write[50].group = "Body";
+ bones.write[50].require = true;
+
+ bones.write[51].bone_name = "LeftToes";
+ bones.write[51].bone_parent = "LeftFoot";
+ bones.write[51].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.15, 0);
+ bones.write[51].handle_offset = Vector2(0.545, 0.95);
+ bones.write[51].group = "Body";
+
+ bones.write[52].bone_name = "RightUpperLeg";
+ bones.write[52].bone_parent = "Hips";
+ bones.write[52].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, -0.1, 0, 0);
+ bones.write[52].handle_offset = Vector2(0.451, 0.49);
+ bones.write[52].group = "Body";
+ bones.write[52].require = true;
+
+ bones.write[53].bone_name = "RightLowerLeg";
+ bones.write[53].bone_parent = "RightUpperLeg";
+ bones.write[53].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
+ bones.write[53].handle_offset = Vector2(0.452, 0.683);
+ bones.write[53].group = "Body";
+ bones.write[53].require = true;
+
+ bones.write[54].bone_name = "RightFoot";
+ bones.write[54].bone_parent = "RightLowerLeg";
+ bones.write[54].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
+ bones.write[54].handle_offset = Vector2(0.455, 0.9);
+ bones.write[54].group = "Body";
+ bones.write[54].require = true;
+
+ bones.write[55].bone_name = "RightToes";
+ bones.write[55].bone_parent = "RightFoot";
+ bones.write[55].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.15, 0);
+ 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..84dfca458e
--- /dev/null
+++ b/scene/resources/skeleton_profile.h
@@ -0,0 +1,140 @@
+/*************************************************************************/
+/* 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);
+
+public:
+ enum TailDirection {
+ TAIL_DIRECTION_AVERAGE_CHILDREN,
+ TAIL_DIRECTION_SPECIFIC_CHILD,
+ TAIL_DIRECTION_END
+ };
+
+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;
+ StringName bone_parent;
+ TailDirection tail_direction = TAIL_DIRECTION_AVERAGE_CHILDREN;
+ StringName bone_tail;
+ Transform3D reference_pose;
+ Vector2 handle_offset;
+ StringName group;
+ bool require = false;
+ };
+
+ StringName root_bone;
+ StringName scale_base_bone;
+
+ 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:
+ StringName get_root_bone();
+ void set_root_bone(StringName p_bone_name);
+
+ StringName get_scale_base_bone();
+ void set_scale_base_bone(StringName p_bone_name);
+
+ 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);
+
+ int find_bone(const StringName p_bone_name) const;
+
+ StringName get_bone_name(int p_bone_idx) const;
+ void set_bone_name(int p_bone_idx, const StringName p_bone_name);
+
+ StringName get_bone_parent(int p_bone_idx) const;
+ void set_bone_parent(int p_bone_idx, const StringName p_bone_parent);
+
+ TailDirection get_tail_direction(int p_bone_idx) const;
+ void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction);
+
+ StringName get_bone_tail(int p_bone_idx) const;
+ void set_bone_tail(int p_bone_idx, const StringName p_bone_tail);
+
+ Transform3D get_reference_pose(int p_bone_idx) const;
+ void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose);
+
+ 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 is_require(int p_bone_idx) const;
+ void set_require(int p_bone_idx, const bool p_require);
+
+ bool has_bone(StringName p_bone_name);
+
+ SkeletonProfile();
+ ~SkeletonProfile();
+};
+
+class SkeletonProfileHumanoid : public SkeletonProfile {
+ GDCLASS(SkeletonProfileHumanoid, SkeletonProfile);
+
+public:
+ SkeletonProfileHumanoid();
+ ~SkeletonProfileHumanoid();
+};
+
+VARIANT_ENUM_CAST(SkeletonProfile::TailDirection);
+
+#endif // SKELETON_PROFILE_H
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index 5be8922ba4..61999af3c4 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -219,4 +219,4 @@ public:
~PhysicalSkyMaterial();
};
-#endif /* !SKY_MATERIAL_H */
+#endif // SKY_MATERIAL_H
diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h
index 8f77378ef4..91d72e01ec 100644
--- a/scene/resources/sphere_shape_3d.h
+++ b/scene/resources/sphere_shape_3d.h
@@ -52,4 +52,4 @@ public:
SphereShape3D();
};
-#endif // SPHERE_SHAPE_H
+#endif // SPHERE_SHAPE_3D_H
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index ba21b9fd17..55c9d7397d 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -96,17 +96,6 @@ void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &
animations[p_next] = anim;
}
-Vector<String> SpriteFrames::_get_animation_list() const {
- Vector<String> ret;
- List<StringName> al;
- get_animation_list(&al);
- for (const StringName &E : al) {
- ret.push_back(E);
- }
-
- return ret;
-}
-
void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
for (const KeyValue<StringName, Anim> &E : animations) {
r_animations->push_back(E.key);
@@ -147,31 +136,22 @@ bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
return E->value.loop;
}
-void SpriteFrames::_set_frames(const Array &p_frames) {
- clear_all();
- HashMap<StringName, Anim>::Iterator E = animations.find(SceneStringNames::get_singleton()->_default);
- ERR_FAIL_COND(!E);
-
- E->value.frames.resize(p_frames.size());
- for (int i = 0; i < E->value.frames.size(); i++) {
- E->value.frames.write[i] = p_frames[i];
- }
-}
-
-Array SpriteFrames::_get_frames() const {
- return Array();
-}
-
Array SpriteFrames::_get_animations() const {
Array anims;
- for (const KeyValue<StringName, Anim> &E : animations) {
+
+ List<StringName> sorted_names;
+ get_animation_list(&sorted_names);
+ sorted_names.sort_custom<StringName::AlphCompare>();
+
+ for (const StringName &name : sorted_names) {
+ const Anim &anim = animations[name];
Dictionary d;
- d["name"] = E.key;
- d["speed"] = E.value.speed;
- d["loop"] = E.value.loop;
+ d["name"] = name;
+ d["speed"] = anim.speed;
+ d["loop"] = anim.loop;
Array frames;
- for (int i = 0; i < E.value.frames.size(); i++) {
- frames.push_back(E.value.frames[i]);
+ for (int i = 0; i < anim.frames.size(); i++) {
+ frames.push_back(anim.frames[i]);
}
d["frames"] = frames;
anims.push_back(d);
@@ -225,15 +205,12 @@ void SpriteFrames::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
- ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
- ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_frames", "_get_frames"); //compatibility
+ // `animations` property is for serialization.
ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations");
}
SpriteFrames::SpriteFrames() {
diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h
index e32ccc1336..87d84b70c0 100644
--- a/scene/resources/sprite_frames.h
+++ b/scene/resources/sprite_frames.h
@@ -44,14 +44,9 @@ class SpriteFrames : public Resource {
HashMap<StringName, Anim> animations;
- Array _get_frames() const;
- void _set_frames(const Array &p_frames);
-
Array _get_animations() const;
void _set_animations(const Array &p_animations);
- Vector<String> _get_animation_list() const;
-
protected:
static void _bind_methods();
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 3b3654775f..9f4f69d3ba 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -264,4 +264,4 @@ public:
~StyleBoxLine();
};
-#endif
+#endif // STYLE_BOX_H
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index 2d399ca3bf..6735d6623f 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -207,4 +207,4 @@ public:
VARIANT_ENUM_CAST(SurfaceTool::CustomFormat)
VARIANT_ENUM_CAST(SurfaceTool::SkinWeightCount)
-#endif
+#endif // SURFACE_TOOL_H
diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h
index 1243a9dbf7..69131ffbee 100644
--- a/scene/resources/syntax_highlighter.h
+++ b/scene/resources/syntax_highlighter.h
@@ -142,4 +142,4 @@ public:
Color get_member_variable_color() const;
};
-#endif
+#endif // SYNTAX_HIGHLIGHTER_H
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_file.h b/scene/resources/text_file.h
index 0c8cf855f0..168e4f5879 100644
--- a/scene/resources/text_file.h
+++ b/scene/resources/text_file.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXTFILE_H
-#define TEXTFILE_H
+#ifndef TEXT_FILE_H
+#define TEXT_FILE_H
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
@@ -51,4 +51,4 @@ public:
Error load_text(const String &p_path);
};
-#endif // TEXTFILE_H
+#endif // TEXT_FILE_H
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index d6e7ca3478..823d742d72 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));
@@ -74,7 +74,7 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextLine::set_flags);
ClassDB::bind_method(D_METHOD("get_flags"), &TextLine::get_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justification,Word Justification,Trim Edge Spaces After Justification,Justify Only After Last Tab,Constrain Ellipsis"), "set_flags", "get_flags");
ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &TextLine::set_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &TextLine::get_text_overrun_behavior);
@@ -106,24 +106,24 @@ void TextLine::_shape() {
TS->shaped_text_tab_align(rid, tab_stops);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
case TextServer::OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
case TextServer::OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
break;
case TextServer::OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
break;
case TextServer::OVERRUN_NO_TRIMMING:
break;
@@ -131,7 +131,7 @@ void TextLine::_shape() {
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
TS->shaped_text_fit_to_width(rid, width, flags);
- overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags);
} else {
TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags);
@@ -149,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) {
@@ -194,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;
}
@@ -242,14 +241,14 @@ void TextLine::tab_align(const Vector<float> &p_tab_stops) {
dirty = true;
}
-void TextLine::set_flags(uint16_t p_flags) {
+void TextLine::set_flags(BitField<TextServer::JustificationFlag> p_flags) {
if (flags != p_flags) {
flags = p_flags;
dirty = true;
}
}
-uint16_t TextLine::get_flags() const {
+BitField<TextServer::JustificationFlag> TextLine::get_flags() const {
return flags;
}
@@ -278,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 {
@@ -347,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);
@@ -394,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);
@@ -409,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 784ee8ef26..e70e82cf2b 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -41,13 +41,11 @@ class TextLine : public RefCounted {
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;
+ BitField<TextServer::JustificationFlag> flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_TRIM_ELLIPSIS;
@@ -77,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);
@@ -86,8 +84,8 @@ public:
void tab_align(const Vector<float> &p_tab_stops);
- void set_flags(uint16_t p_flags);
- uint16_t get_flags() const;
+ void set_flags(BitField<TextServer::JustificationFlag> p_flags);
+ BitField<TextServer::JustificationFlag> get_flags() const;
void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
TextServer::OverrunBehavior get_text_overrun_behavior() const;
@@ -111,7 +109,7 @@ 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();
};
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 874992ea3d..43d3f329fa 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));
@@ -74,10 +74,15 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("tab_align", "tab_stops"), &TextParagraph::tab_align);
- ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextParagraph::set_flags);
- ClassDB::bind_method(D_METHOD("get_flags"), &TextParagraph::get_flags);
+ ClassDB::bind_method(D_METHOD("set_break_flags", "flags"), &TextParagraph::set_break_flags);
+ ClassDB::bind_method(D_METHOD("get_break_flags"), &TextParagraph::get_break_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab,Break Mandatory,Break Words,Break Graphemes"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "break_flags", PROPERTY_HINT_FLAGS, "Mandatory,Word Bound,Grapheme Bound,Adaptive"), "set_break_flags", "get_break_flags");
+
+ ClassDB::bind_method(D_METHOD("set_justification_flags", "flags"), &TextParagraph::set_justification_flags);
+ ClassDB::bind_method(D_METHOD("get_justification_flags"), &TextParagraph::get_justification_flags);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "justification_flags", PROPERTY_HINT_FLAGS, "Kashida Justification,Word Justification,Trim Edge Spaces After Justification,Justify Only After Last Tab,Constrain Ellipsis"), "set_justification_flags", "get_justification_flags");
ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &TextParagraph::set_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &TextParagraph::get_text_overrun_behavior);
@@ -113,9 +118,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);
@@ -157,7 +159,7 @@ void TextParagraph::_shape_lines() {
if (h_offset > 0) {
// Dropcap, flow around.
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, flags);
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, brk_flags);
for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x;
@@ -175,7 +177,7 @@ void TextParagraph::_shape_lines() {
}
}
// Use fixed for the rest of lines.
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, flags);
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, brk_flags);
for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
if (!tab_stops.is_empty()) {
@@ -184,43 +186,43 @@ void TextParagraph::_shape_lines() {
lines_rid.push_back(line);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
case TextServer::OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
case TextServer::OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
break;
case TextServer::OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
break;
case TextServer::OVERRUN_NO_TRIMMING:
break;
}
}
- bool autowrap_enabled = ((flags & TextServer::BREAK_WORD_BOUND) == TextServer::BREAK_WORD_BOUND) || ((flags & TextServer::BREAK_GRAPHEME_BOUND) == TextServer::BREAK_GRAPHEME_BOUND);
+ bool autowrap_enabled = brk_flags.has_flag(TextServer::BREAK_WORD_BOUND) || brk_flags.has_flag(TextServer::BREAK_GRAPHEME_BOUND);
// Fill after min_size calculation.
if (autowrap_enabled) {
int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
bool lines_hidden = visible_lines > 0 && visible_lines < (int)lines_rid.size();
if (lines_hidden) {
- overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
+ overrun_flags.set_flag(TextServer::OVERRUN_ENFORCE_ELLIPSIS);
}
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
if (i < visible_lines - 1 || (int)lines_rid.size() == 1) {
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
+ TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
}
@@ -234,10 +236,10 @@ void TextParagraph::_shape_lines() {
// Autowrap disabled.
for (int i = 0; i < (int)lines_rid.size(); i++) {
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
- overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
+ overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
+ TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
} else {
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
}
@@ -266,8 +268,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]);
}
@@ -347,44 +347,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_
@@ -432,17 +425,30 @@ void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
lines_dirty = true;
}
-void TextParagraph::set_flags(uint16_t p_flags) {
+void TextParagraph::set_justification_flags(BitField<TextServer::JustificationFlag> p_flags) {
_THREAD_SAFE_METHOD_
- if (flags != p_flags) {
- flags = p_flags;
+ if (jst_flags != p_flags) {
+ jst_flags = p_flags;
lines_dirty = true;
}
}
-uint16_t TextParagraph::get_flags() const {
- return flags;
+BitField<TextServer::JustificationFlag> TextParagraph::get_justification_flags() const {
+ return jst_flags;
+}
+
+void TextParagraph::set_break_flags(BitField<TextServer::LineBreakFlag> p_flags) {
+ _THREAD_SAFE_METHOD_
+
+ if (brk_flags != p_flags) {
+ brk_flags = p_flags;
+ lines_dirty = true;
+ }
+}
+
+BitField<TextServer::LineBreakFlag> TextParagraph::get_break_flags() const {
+ return brk_flags;
}
void TextParagraph::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
@@ -476,9 +482,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);
}
}
@@ -492,9 +498,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);
}
}
@@ -538,9 +544,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;
@@ -552,9 +558,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);
}
}
@@ -571,7 +577,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 {
@@ -579,7 +585,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 {
@@ -647,7 +653,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;
@@ -656,7 +662,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;
@@ -711,10 +717,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]);
}
}
}
@@ -749,7 +755,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;
@@ -758,7 +764,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;
@@ -813,10 +819,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]);
}
}
}
@@ -840,12 +846,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;
@@ -908,9 +914,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);
}
@@ -923,18 +929,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 bdcc2b5701..0fe82b4364 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -48,15 +48,14 @@ private:
RID rid;
LocalVector<RID> lines_rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
bool lines_dirty = true;
float width = -1.0;
int max_lines_visible = -1;
- uint16_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+ BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND;
+ BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -92,10 +91,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);
@@ -104,8 +103,11 @@ public:
void tab_align(const Vector<float> &p_tab_stops);
- void set_flags(uint16_t p_flags);
- uint16_t get_flags() const;
+ void set_justification_flags(BitField<TextServer::JustificationFlag> p_flags);
+ BitField<TextServer::JustificationFlag> get_justification_flags() const;
+
+ void set_break_flags(BitField<TextServer::LineBreakFlag> p_flags);
+ BitField<TextServer::LineBreakFlag> get_break_flags() const;
void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
TextServer::OverrunBehavior get_text_overrun_behavior() const;
@@ -151,7 +153,7 @@ 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();
};
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index f31a71eada..05ed9238b8 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -139,7 +139,7 @@ void ImageTexture::reload_from_file() {
img.instantiate();
if (ImageLoader::load_image(path, img) == OK) {
- create_from_image(img);
+ set_image(img);
} else {
Resource::reload_from_file();
notify_property_list_changed();
@@ -149,7 +149,7 @@ void ImageTexture::reload_from_file() {
bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "image") {
- create_from_image(p_value);
+ set_image(p_value);
return true;
}
return false;
@@ -167,7 +167,16 @@ void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
}
-void ImageTexture::create_from_image(const Ref<Image> &p_image) {
+Ref<ImageTexture> ImageTexture::create_from_image(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_V_MSG(p_image.is_null() || p_image->is_empty(), Ref<ImageTexture>(), "Invalid image");
+
+ Ref<ImageTexture> image_texture;
+ image_texture.instantiate();
+ image_texture->set_image(p_image);
+ return image_texture;
+}
+
+void ImageTexture::set_image(const Ref<Image> &p_image) {
ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image");
w = p_image->get_width();
h = p_image->get_height();
@@ -291,8 +300,8 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void ImageTexture::set_size_override(const Size2 &p_size) {
- Size2 s = p_size;
+void ImageTexture::set_size_override(const Size2i &p_size) {
+ Size2i s = p_size;
if (s.x != 0) {
w = s.x;
}
@@ -311,9 +320,10 @@ void ImageTexture::set_path(const String &p_path, bool p_take_over) {
}
void ImageTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image);
+ ClassDB::bind_static_method("ImageTexture", D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image);
ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format);
+ ClassDB::bind_method(D_METHOD("set_image", "image"), &ImageTexture::set_image);
ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update);
ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
}
@@ -1999,7 +2009,7 @@ void CurveXYZTexture::set_curve_x(Ref<Curve> p_curve) {
}
_curve_x = p_curve;
if (_curve_x.is_valid()) {
- _curve_x->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), varray(), CONNECT_REFERENCE_COUNTED);
+ _curve_x->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
}
_update();
}
@@ -2012,7 +2022,7 @@ void CurveXYZTexture::set_curve_y(Ref<Curve> p_curve) {
}
_curve_y = p_curve;
if (_curve_y.is_valid()) {
- _curve_y->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), varray(), CONNECT_REFERENCE_COUNTED);
+ _curve_y->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
}
_update();
}
@@ -2025,7 +2035,7 @@ void CurveXYZTexture::set_curve_z(Ref<Curve> p_curve) {
}
_curve_z = p_curve;
if (_curve_z.is_valid()) {
- _curve_z->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), varray(), CONNECT_REFERENCE_COUNTED);
+ _curve_z->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
}
_update();
}
@@ -2148,7 +2158,7 @@ void GradientTexture1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
@@ -3016,12 +3026,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/texture.h b/scene/resources/texture.h
index 317756e313..36b193c5d4 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -110,7 +110,8 @@ protected:
static void _bind_methods();
public:
- void create_from_image(const Ref<Image> &p_image);
+ void set_image(const Ref<Image> &p_image);
+ static Ref<ImageTexture> create_from_image(const Ref<Image> &p_image);
Image::Format get_format() const;
@@ -129,7 +130,7 @@ public:
bool is_pixel_opaque(int p_x, int p_y) const override;
- void set_size_override(const Size2 &p_size);
+ void set_size_override(const Size2i &p_size);
virtual void set_path(const String &p_path, bool p_take_over = false) override;
@@ -1105,4 +1106,4 @@ public:
PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
};
-#endif
+#endif // TEXTURE_H
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 39b77568cf..3f6eec8497 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -295,7 +295,7 @@ void Theme::set_default_font(const Ref<Font> &p_default_font) {
default_font = p_default_font;
if (default_font.is_valid()) {
- default_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED);
+ default_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed();
@@ -341,7 +341,7 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, c
icon_map[p_theme_type][p_name] = p_icon;
if (p_icon.is_valid()) {
- icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED);
+ icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed(!existing);
@@ -451,7 +451,7 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_typ
style_map[p_theme_type][p_name] = p_style;
if (p_style.is_valid()) {
- style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED);
+ style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed(!existing);
@@ -561,7 +561,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c
font_map[p_theme_type][p_name] = p_font;
if (p_font.is_valid()) {
- font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED);
+ font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed(!existing);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 87d7d2fdea..a2aca5e61f 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -256,4 +256,4 @@ public:
VARIANT_ENUM_CAST(Theme::DataType);
-#endif
+#endif // THEME_H
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 13b671e562..b0b9f1228f 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1048,13 +1048,13 @@ int TileSet::get_custom_data_layer_by_name(String p_value) const {
}
}
-void TileSet::set_custom_data_name(int p_layer_id, String p_value) {
+void TileSet::set_custom_data_layer_name(int p_layer_id, String p_value) {
ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
// Exit if another property has the same name.
if (!p_value.is_empty()) {
for (int other_layer_id = 0; other_layer_id < get_custom_data_layers_count(); other_layer_id++) {
- if (other_layer_id != p_layer_id && get_custom_data_name(other_layer_id) == p_value) {
+ if (other_layer_id != p_layer_id && get_custom_data_layer_name(other_layer_id) == p_value) {
ERR_FAIL_MSG(vformat("There is already a custom property named %s", p_value));
}
}
@@ -1070,12 +1070,12 @@ void TileSet::set_custom_data_name(int p_layer_id, String p_value) {
emit_changed();
}
-String TileSet::get_custom_data_name(int p_layer_id) const {
+String TileSet::get_custom_data_layer_name(int p_layer_id) const {
ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), "");
return custom_data_layers[p_layer_id].name;
}
-void TileSet::set_custom_data_type(int p_layer_id, Variant::Type p_value) {
+void TileSet::set_custom_data_layer_type(int p_layer_id, Variant::Type p_value) {
ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
custom_data_layers.write[p_layer_id].type = p_value;
@@ -1086,7 +1086,7 @@ void TileSet::set_custom_data_type(int p_layer_id, Variant::Type p_value) {
emit_changed();
}
-Variant::Type TileSet::get_custom_data_type(int p_layer_id) const {
+Variant::Type TileSet::get_custom_data_layer_type(int p_layer_id) const {
ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), Variant::NIL);
return custom_data_layers[p_layer_id].type;
}
@@ -1801,19 +1801,16 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
if (counts[terrain_set][terrain].count > 0) {
// Get the best tile.
Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
- Rect2 region = counts[terrain_set][terrain].region;
+ Rect2i region = counts[terrain_set][terrain].region;
image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
- image->blit_rect(texture->get_image(), region, Point2());
+ image->blit_rect(texture->get_image(), region, Point2i());
image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
} else {
image->create(1, 1, false, Image::FORMAT_RGBA8);
image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
}
- Ref<ImageTexture> icon;
- icon.instantiate();
- icon->create_from_image(image);
+ Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
icon->set_size_override(p_size);
-
output.write[terrain_set].write[terrain] = icon;
}
}
@@ -2470,9 +2467,42 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector
}
void TileSet::reset_state() {
+ // Rendering
occlusion_layers.clear();
+ tile_lines_mesh.instantiate();
+ tile_filled_mesh.instantiate();
+ tile_meshes_dirty = true;
+
+ // Physics
physics_layers.clear();
+
+ // Terrains
+ terrain_sets.clear();
+ terrain_meshes.clear();
+ terrain_peering_bits_meshes.clear();
+ per_terrain_pattern_tiles.clear();
+ terrains_cache_dirty = true;
+
+ // Navigation
+ navigation_layers.clear();
+
custom_data_layers.clear();
+ custom_data_layers_by_name.clear();
+
+ // Proxies
+ source_level_proxies.clear();
+ coords_level_proxies.clear();
+ alternative_level_proxies.clear();
+
+#ifndef DISABLE_DEPRECATED
+ for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
+ memdelete(E.value);
+ }
+ compatibility_data.clear();
+#endif // DISABLE_DEPRECATED
+ while (!source_ids.is_empty()) {
+ remove_source(source_ids[0]);
+ }
}
const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1);
@@ -3006,14 +3036,14 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
while (index >= custom_data_layers.size()) {
add_custom_data_layer();
}
- set_custom_data_name(index, p_value);
+ set_custom_data_layer_name(index, p_value);
return true;
} else if (components[1] == "type") {
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
while (index >= custom_data_layers.size()) {
add_custom_data_layer();
}
- set_custom_data_type(index, Variant::Type(int(p_value)));
+ set_custom_data_layer_type(index, Variant::Type(int(p_value)));
return true;
}
} else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) {
@@ -3135,10 +3165,10 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
if (components[1] == "name") {
- r_ret = get_custom_data_name(index);
+ r_ret = get_custom_data_layer_name(index);
return true;
} else if (components[1] == "type") {
- r_ret = get_custom_data_type(index);
+ r_ret = get_custom_data_layer_type(index);
return true;
}
} else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) {
@@ -3361,6 +3391,11 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_custom_data_layer", "to_position"), &TileSet::add_custom_data_layer, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("move_custom_data_layer", "layer_index", "to_position"), &TileSet::move_custom_data_layer);
ClassDB::bind_method(D_METHOD("remove_custom_data_layer", "layer_index"), &TileSet::remove_custom_data_layer);
+ ClassDB::bind_method(D_METHOD("get_custom_data_layer_by_name", "layer_name"), &TileSet::get_custom_data_layer_by_name);
+ ClassDB::bind_method(D_METHOD("set_custom_data_layer_name", "layer_index", "layer_name"), &TileSet::set_custom_data_layer_name);
+ ClassDB::bind_method(D_METHOD("get_custom_data_layer_name", "layer_index"), &TileSet::get_custom_data_layer_name);
+ ClassDB::bind_method(D_METHOD("set_custom_data_layer_type", "layer_index", "layer_type"), &TileSet::set_custom_data_layer_type);
+ ClassDB::bind_method(D_METHOD("get_custom_data_layer_type", "layer_index"), &TileSet::get_custom_data_layer_type);
// Tile proxies
ClassDB::bind_method(D_METHOD("set_source_level_tile_proxy", "source_from", "source_to"), &TileSet::set_source_level_tile_proxy);
@@ -3460,6 +3495,10 @@ void TileSetSource::set_tile_set(const TileSet *p_tile_set) {
tile_set = p_tile_set;
}
+void TileSetSource::reset_state() {
+ tile_set = nullptr;
+};
+
void TileSetSource::_bind_methods() {
// Base tiles
ClassDB::bind_method(D_METHOD("get_tiles_count"), &TileSetSource::get_tiles_count);
@@ -3643,12 +3682,17 @@ void TileSetAtlasSource::remove_custom_data_layer(int p_index) {
}
void TileSetAtlasSource::reset_state() {
- // Reset all TileData.
+ tile_set = nullptr;
+
for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
- for (KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
- E_alternative.value->reset_state();
+ for (const KeyValue<int, TileData *> &E_tile_data : E_tile.value.alternatives) {
+ memdelete(E_tile_data.value);
}
}
+ _coords_mapping_cache.clear();
+ tiles.clear();
+ tiles_ids.clear();
+ _queue_update_padded_texture();
}
void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) {
@@ -3930,7 +3974,7 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
tile_property_list.push_back(property_info);
// animation_frames_count.
- tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NETWORK));
+ tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
// animation_frame_*.
bool store_durations = tiles[E_tile.key].animation_frames_durations.size() >= 2;
@@ -4594,7 +4638,7 @@ void TileSetAtlasSource::_update_padded_texture() {
if (!padded_texture.is_valid()) {
padded_texture.instantiate();
}
- padded_texture->create_from_image(image);
+ padded_texture->set_image(image);
emit_changed();
}
@@ -4808,14 +4852,14 @@ void TileData::notify_tile_data_properties_should_change() {
// Convert custom data to the new type.
custom_data.resize(tile_set->get_custom_data_layers_count());
for (int i = 0; i < custom_data.size(); i++) {
- if (custom_data[i].get_type() != tile_set->get_custom_data_type(i)) {
+ if (custom_data[i].get_type() != tile_set->get_custom_data_layer_type(i)) {
Variant new_val;
Callable::CallError error;
- if (Variant::can_convert(custom_data[i].get_type(), tile_set->get_custom_data_type(i))) {
+ if (Variant::can_convert(custom_data[i].get_type(), tile_set->get_custom_data_layer_type(i))) {
const Variant *args[] = { &custom_data[i] };
- Variant::construct(tile_set->get_custom_data_type(i), new_val, args, 1, error);
+ Variant::construct(tile_set->get_custom_data_layer_type(i), new_val, args, 1, error);
} else {
- Variant::construct(tile_set->get_custom_data_type(i), new_val, nullptr, 0, error);
+ Variant::construct(tile_set->get_custom_data_layer_type(i), new_val, nullptr, 0, error);
}
custom_data.write[i] = new_val;
}
@@ -4924,6 +4968,10 @@ void TileData::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
void TileData::remove_terrain(int p_terrain_set, int p_index) {
if (terrain_set == p_terrain_set) {
+ if (terrain == p_index) {
+ terrain = -1;
+ }
+
for (int i = 0; i < 16; i++) {
if (terrain_peering_bits[i] == p_index) {
terrain_peering_bits[i] = -1;
@@ -4974,13 +5022,6 @@ void TileData::remove_custom_data_layer(int p_index) {
custom_data.remove_at(p_index);
}
-void TileData::reset_state() {
- occluders.clear();
- physics.clear();
- navigation.clear();
- custom_data.clear();
-}
-
void TileData::set_allow_transform(bool p_allow_transform) {
allow_transform = p_allow_transform;
}
@@ -5625,7 +5666,7 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
Variant default_val;
Callable::CallError error;
Variant::construct(custom_data[i].get_type(), default_val, nullptr, 0, error);
- property_info = PropertyInfo(tile_set->get_custom_data_type(i), vformat("custom_data_%d", i), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
+ property_info = PropertyInfo(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
if (custom_data[i] == default_val) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 7368d2bd87..6ea3889fce 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -479,10 +479,10 @@ public:
void move_custom_data_layer(int p_from_index, int p_to_pos);
void remove_custom_data_layer(int p_index);
int get_custom_data_layer_by_name(String p_value) const;
- void set_custom_data_name(int p_layer_id, String p_value);
- String get_custom_data_name(int p_layer_id) const;
- void set_custom_data_type(int p_layer_id, Variant::Type p_value);
- Variant::Type get_custom_data_type(int p_layer_id) const;
+ void set_custom_data_layer_name(int p_layer_id, String p_value);
+ String get_custom_data_layer_name(int p_layer_id) const;
+ void set_custom_data_layer_type(int p_layer_id, Variant::Type p_value);
+ Variant::Type get_custom_data_layer_type(int p_layer_id) const;
// Tiles proxies.
void set_source_level_tile_proxy(int p_source_from, int p_source_to);
@@ -569,7 +569,7 @@ public:
virtual void add_custom_data_layer(int p_index){};
virtual void move_custom_data_layer(int p_from_index, int p_to_pos){};
virtual void remove_custom_data_layer(int p_index){};
- virtual void reset_state() override{};
+ virtual void reset_state() override;
// Tiles.
virtual int get_tiles_count() const = 0;
@@ -847,7 +847,6 @@ public:
void add_custom_data_layer(int p_index);
void move_custom_data_layer(int p_from_index, int p_to_pos);
void remove_custom_data_layer(int p_index);
- void reset_state();
void set_allow_transform(bool p_allow_transform);
bool is_allowing_transform() const;
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 3e154d539b..35686b293c 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -72,7 +72,7 @@ class VideoStream : public Resource {
public:
virtual void set_audio_track(int p_track) = 0;
- virtual Ref<VideoStreamPlayback> instance_playback() = 0;
+ virtual Ref<VideoStreamPlayback> instantiate_playback() = 0;
};
-#endif
+#endif // VIDEO_STREAM_H
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index b8eac6de00..5e0627a7d9 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -30,6 +30,7 @@
#include "visual_shader.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vmap.h"
#include "servers/rendering/shader_types.h"
#include "visual_shader_nodes.h"
@@ -966,6 +967,12 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
ERR_FAIL_COND(!g->nodes.has(p_to_node));
ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count());
+ for (const Connection &E : g->connections) {
+ if (E.from_node == p_from_node && E.from_port == p_from_port && E.to_node == p_to_node && E.to_port == p_to_port) {
+ return;
+ }
+ }
+
Connection c;
c.from_node = p_from_node;
c.from_port = p_from_port;
@@ -3189,18 +3196,18 @@ VisualShaderNodeInput::VisualShaderNodeInput() {
////////////// UniformRef
-List<VisualShaderNodeUniformRef::Uniform> uniforms;
+RBMap<RID, List<VisualShaderNodeUniformRef::Uniform>> uniforms;
-void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
- uniforms.push_back({ p_name, p_type });
+void VisualShaderNodeUniformRef::add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type) {
+ uniforms[p_shader_rid].push_back({ p_name, p_type });
}
-void VisualShaderNodeUniformRef::clear_uniforms() {
- uniforms.clear();
+void VisualShaderNodeUniformRef::clear_uniforms(RID p_shader_rid) {
+ uniforms[p_shader_rid].clear();
}
-bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
- for (const VisualShaderNodeUniformRef::Uniform &E : uniforms) {
+bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_name) {
+ for (const VisualShaderNodeUniformRef::Uniform &E : uniforms[p_shader_rid]) {
if (E.name == p_name) {
return true;
}
@@ -3313,14 +3320,24 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
return "";
}
+void VisualShaderNodeUniformRef::set_shader_rid(const RID &p_shader_rid) {
+ shader_rid = p_shader_rid;
+}
+
void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
uniform_name = p_name;
+ if (shader_rid.is_valid()) {
+ update_uniform_type();
+ }
+ emit_changed();
+}
+
+void VisualShaderNodeUniformRef::update_uniform_type() {
if (uniform_name != "[None]") {
uniform_type = get_uniform_type_by_name(uniform_name);
} else {
uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
- emit_changed();
}
String VisualShaderNodeUniformRef::get_uniform_name() const {
@@ -3328,35 +3345,45 @@ String VisualShaderNodeUniformRef::get_uniform_name() const {
}
int VisualShaderNodeUniformRef::get_uniforms_count() const {
- return uniforms.size();
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), 0);
+
+ return uniforms[shader_rid].size();
}
String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].name;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ return uniforms[shader_rid][p_idx].name;
}
return "";
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
- for (int i = 0; i < uniforms.size(); i++) {
- if (uniforms[i].name == p_name) {
- return uniforms[i].type;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+
+ for (int i = 0; i < uniforms[shader_rid].size(); i++) {
+ if (uniforms[shader_rid][i].name == p_name) {
+ return uniforms[shader_rid][i].type;
}
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].type;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ return uniforms[shader_rid][p_idx].type;
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- switch (uniforms[p_idx].type) {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ switch (uniforms[shader_rid][p_idx].type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return PORT_TYPE_SCALAR;
case UniformType::UNIFORM_TYPE_INT:
@@ -3724,7 +3751,7 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
}
return vformat(RTR("This uniform type does not support the '%s' qualifier."), qualifier_str);
} else if (qualifier == Qualifier::QUAL_GLOBAL) {
- RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(uniform_name);
+ RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(uniform_name);
if (gvt == RS::GLOBAL_VAR_TYPE_MAX) {
return vformat(RTR("Global uniform '%s' does not exist.\nCreate it in the Project Settings."), uniform_name);
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index afd84e49cc..7ca4e5fc4a 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -561,6 +561,7 @@ public:
};
private:
+ RID shader_rid;
String uniform_name = "[None]";
UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
@@ -568,9 +569,9 @@ protected:
static void _bind_methods();
public:
- static void add_uniform(const String &p_name, UniformType p_type);
- static void clear_uniforms();
- static bool has_uniform(const String &p_name);
+ static void add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type);
+ static void clear_uniforms(RID p_shader_rid);
+ static bool has_uniform(RID p_shader_rid, const String &p_name);
public:
virtual String get_caption() const override;
@@ -583,9 +584,13 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ void set_shader_rid(const RID &p_shader);
+
void set_uniform_name(const String &p_name);
String get_uniform_name() const;
+ void update_uniform_type();
+
void _set_uniform_type(int p_uniform_type);
int _get_uniform_type() const;
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
index 54df935168..bdfbb59fa6 100644
--- a/scene/resources/visual_shader_particle_nodes.cpp
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -470,7 +470,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2>
image->set_pixel(i, 0, Color(v.x, v.y, 0));
}
if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
- r_texture->create_from_image(image);
+ r_texture->set_image(image);
} else {
r_texture->update(image);
}
@@ -491,7 +491,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3>
image->set_pixel(i, 0, Color(v.x, v.y, v.z));
}
if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
- r_texture->create_from_image(image);
+ r_texture->set_image(image);
} else {
r_texture->update(image);
}
@@ -511,7 +511,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p
image->set_pixel(i, 0, p_array[i]);
}
if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
- r_texture->create_from_image(image);
+ r_texture->set_image(image);
} else {
r_texture->update(image);
}
diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h
index 05a059373b..64acb6d18f 100644
--- a/scene/resources/visual_shader_particle_nodes.h
+++ b/scene/resources/visual_shader_particle_nodes.h
@@ -352,4 +352,4 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeParticleEmit::EmitFlags)
-#endif
+#endif // VISUAL_SHADER_PARTICLE_NODES_H
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index a84ee773b4..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"
diff --git a/scene/resources/world_boundary_shape_3d.h b/scene/resources/world_boundary_shape_3d.h
index 5378bc52c7..5c34767106 100644
--- a/scene/resources/world_boundary_shape_3d.h
+++ b/scene/resources/world_boundary_shape_3d.h
@@ -53,4 +53,5 @@ public:
WorldBoundaryShape3D();
};
-#endif // WORLD_BOUNDARY_SHAPE_H
+
+#endif // WORLD_BOUNDARY_SHAPE_3D_H