summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp1448
-rw-r--r--scene/resources/animation.h73
-rw-r--r--scene/resources/animation_library.cpp14
-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)174
-rw-r--r--scene/resources/audio_stream_wav.h (renamed from scene/resources/audio_stream_sample.h)46
-rw-r--r--scene/resources/bit_map.cpp159
-rw-r--r--scene/resources/bit_map.h30
-rw-r--r--scene/resources/bone_map.cpp187
-rw-r--r--scene/resources/bone_map.h (renamed from scene/resources/scene_replication_config.h)70
-rw-r--r--scene/resources/box_shape_3d.cpp2
-rw-r--r--scene/resources/box_shape_3d.h6
-rw-r--r--scene/resources/camera_attributes.cpp493
-rw-r--r--scene/resources/camera_attributes.h183
-rw-r--r--scene/resources/camera_effects.cpp206
-rw-r--r--scene/resources/canvas_item_material.cpp6
-rw-r--r--scene/resources/canvas_item_material.h4
-rw-r--r--scene/resources/capsule_shape_2d.cpp4
-rw-r--r--scene/resources/capsule_shape_3d.cpp8
-rw-r--r--scene/resources/capsule_shape_3d.h6
-rw-r--r--scene/resources/circle_shape_2d.cpp2
-rw-r--r--scene/resources/concave_polygon_shape_2d.h2
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp8
-rw-r--r--scene/resources/concave_polygon_shape_3d.h14
-rw-r--r--scene/resources/convex_polygon_shape_3d.h6
-rw-r--r--scene/resources/curve.cpp488
-rw-r--r--scene/resources/curve.h59
-rw-r--r--scene/resources/cylinder_shape_3d.cpp8
-rw-r--r--scene/resources/cylinder_shape_3d.h2
-rw-r--r--scene/resources/default_theme/default_theme.cpp218
-rw-r--r--scene/resources/default_theme/default_theme.h5
-rw-r--r--scene/resources/environment.cpp227
-rw-r--r--scene/resources/environment.h41
-rw-r--r--scene/resources/fog_material.cpp8
-rw-r--r--scene/resources/font.cpp2596
-rw-r--r--scene/resources/font.h338
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/gradient.h14
-rw-r--r--scene/resources/height_map_shape_3d.h6
-rw-r--r--scene/resources/immediate_mesh.cpp4
-rw-r--r--scene/resources/immediate_mesh.h4
-rw-r--r--scene/resources/importer_mesh.cpp60
-rw-r--r--scene/resources/importer_mesh.h11
-rw-r--r--scene/resources/label_settings.cpp187
-rw-r--r--scene/resources/label_settings.h89
-rw-r--r--scene/resources/material.cpp518
-rw-r--r--scene/resources/material.h24
-rw-r--r--scene/resources/mesh.cpp313
-rw-r--r--scene/resources/mesh.h21
-rw-r--r--scene/resources/mesh_library.cpp16
-rw-r--r--scene/resources/mesh_library.h2
-rw-r--r--scene/resources/multimesh.cpp8
-rw-r--r--scene/resources/multimesh.h2
-rw-r--r--scene/resources/navigation_mesh.cpp267
-rw-r--r--scene/resources/navigation_mesh.h33
-rw-r--r--scene/resources/packed_scene.cpp137
-rw-r--r--scene/resources/packed_scene.h16
-rw-r--r--scene/resources/particle_process_material.cpp (renamed from scene/resources/particles_material.cpp)719
-rw-r--r--scene/resources/particle_process_material.h (renamed from scene/resources/particles_material.h)91
-rw-r--r--scene/resources/polygon_path_finder.cpp74
-rw-r--r--scene/resources/polygon_path_finder.h22
-rw-r--r--scene/resources/primitive_meshes.cpp990
-rw-r--r--scene/resources/primitive_meshes.h159
-rw-r--r--scene/resources/rectangle_shape_2d.cpp10
-rw-r--r--scene/resources/rectangle_shape_2d.h6
-rw-r--r--scene/resources/resource_format_text.cpp261
-rw-r--r--scene/resources/resource_format_text.h10
-rw-r--r--scene/resources/scene_replication_config.cpp187
-rw-r--r--scene/resources/segment_shape_2d.cpp4
-rw-r--r--scene/resources/separation_ray_shape_2d.cpp4
-rw-r--r--scene/resources/separation_ray_shape_3d.cpp2
-rw-r--r--scene/resources/separation_ray_shape_3d.h8
-rw-r--r--scene/resources/shader.cpp97
-rw-r--r--scene/resources/shader.h57
-rw-r--r--scene/resources/shader_include.cpp144
-rw-r--r--scene/resources/shader_include.h (renamed from scene/resources/camera_effects.h)80
-rw-r--r--scene/resources/shape_2d.cpp20
-rw-r--r--scene/resources/shape_2d.h4
-rw-r--r--scene/resources/shape_3d.cpp2
-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.cpp8
-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.cpp12
-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.cpp4
-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.cpp8
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.h8
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.cpp4
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.h8
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.cpp4
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.h8
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp12
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.h8
-rw-r--r--scene/resources/skeleton_modification_3d_stackholder.h8
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.cpp8
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.h8
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp8
-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/skin.cpp9
-rw-r--r--scene/resources/sky_material.cpp225
-rw-r--r--scene/resources/sky_material.h50
-rw-r--r--scene/resources/sphere_shape_3d.cpp8
-rw-r--r--scene/resources/sphere_shape_3d.h4
-rw-r--r--scene/resources/sprite_frames.cpp53
-rw-r--r--scene/resources/sprite_frames.h5
-rw-r--r--scene/resources/style_box.cpp116
-rw-r--r--scene/resources/style_box.h9
-rw-r--r--scene/resources/surface_tool.cpp66
-rw-r--r--scene/resources/surface_tool.h14
-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.cpp92
-rw-r--r--scene/resources/text_line.h29
-rw-r--r--scene/resources/text_paragraph.cpp321
-rw-r--r--scene/resources/text_paragraph.h41
-rw-r--r--scene/resources/texture.cpp205
-rw-r--r--scene/resources/texture.h48
-rw-r--r--scene/resources/theme.cpp191
-rw-r--r--scene/resources/theme.h50
-rw-r--r--scene/resources/tile_set.cpp529
-rw-r--r--scene/resources/tile_set.h80
-rw-r--r--scene/resources/video_stream.h12
-rw-r--r--scene/resources/visual_shader.cpp652
-rw-r--r--scene/resources/visual_shader.h116
-rw-r--r--scene/resources/visual_shader_nodes.cpp1404
-rw-r--r--scene/resources/visual_shader_nodes.h261
-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_2d.cpp5
-rw-r--r--scene/resources/world_2d.h4
-rw-r--r--scene/resources/world_3d.cpp32
-rw-r--r--scene/resources/world_3d.h12
-rw-r--r--scene/resources/world_boundary_shape_2d.cpp2
-rw-r--r--scene/resources/world_boundary_shape_3d.cpp2
-rw-r--r--scene/resources/world_boundary_shape_3d.h3
146 files changed, 11617 insertions, 6038 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index a26aa10f42..a52bfe97e7 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -313,29 +313,37 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
Dictionary d = p_value;
ERR_FAIL_COND_V(!d.has("times"), false);
ERR_FAIL_COND_V(!d.has("points"), false);
-
Vector<real_t> times = d["times"];
Vector<real_t> values = d["points"];
+#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND_V(!d.has("handle_modes"), false);
+ Vector<int> handle_modes = d["handle_modes"];
+#endif // TOOLS_ENABLED
- ERR_FAIL_COND_V(times.size() * 6 != values.size(), false);
+ ERR_FAIL_COND_V(times.size() * 5 != values.size(), false);
if (times.size()) {
int valcount = times.size();
const real_t *rt = times.ptr();
const real_t *rv = values.ptr();
+#ifdef TOOLS_ENABLED
+ const int *rh = handle_modes.ptr();
+#endif // TOOLS_ENABLED
bt->values.resize(valcount);
for (int i = 0; i < valcount; i++) {
bt->values.write[i].time = rt[i];
bt->values.write[i].transition = 0; //unused in bezier
- bt->values.write[i].value.value = rv[i * 6 + 0];
- bt->values.write[i].value.in_handle.x = rv[i * 6 + 1];
- bt->values.write[i].value.in_handle.y = rv[i * 6 + 2];
- bt->values.write[i].value.out_handle.x = rv[i * 6 + 3];
- bt->values.write[i].value.out_handle.y = rv[i * 6 + 4];
- bt->values.write[i].value.handle_mode = static_cast<HandleMode>((int)rv[i * 6 + 5]);
+ bt->values.write[i].value.value = rv[i * 5 + 0];
+ bt->values.write[i].value.in_handle.x = rv[i * 5 + 1];
+ bt->values.write[i].value.in_handle.y = rv[i * 5 + 2];
+ bt->values.write[i].value.out_handle.x = rv[i * 5 + 3];
+ bt->values.write[i].value.out_handle.y = rv[i * 5 + 4];
+#ifdef TOOLS_ENABLED
+ bt->values.write[i].value.handle_mode = static_cast<HandleMode>(rh[i]);
+#endif // TOOLS_ENABLED
}
}
@@ -699,28 +707,39 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
int kk = bt->values.size();
key_times.resize(kk);
- key_points.resize(kk * 6);
+ key_points.resize(kk * 5);
real_t *wti = key_times.ptrw();
real_t *wpo = key_points.ptrw();
+#ifdef TOOLS_ENABLED
+ Vector<int> handle_modes;
+ handle_modes.resize(kk);
+ int *whm = handle_modes.ptrw();
+#endif // TOOLS_ENABLED
+
int idx = 0;
const TKey<BezierKey> *vls = bt->values.ptr();
for (int i = 0; i < kk; i++) {
wti[idx] = vls[i].time;
- wpo[idx * 6 + 0] = vls[i].value.value;
- wpo[idx * 6 + 1] = vls[i].value.in_handle.x;
- wpo[idx * 6 + 2] = vls[i].value.in_handle.y;
- wpo[idx * 6 + 3] = vls[i].value.out_handle.x;
- wpo[idx * 6 + 4] = vls[i].value.out_handle.y;
- wpo[idx * 6 + 5] = (double)vls[i].value.handle_mode;
+ wpo[idx * 5 + 0] = vls[i].value.value;
+ wpo[idx * 5 + 1] = vls[i].value.in_handle.x;
+ wpo[idx * 5 + 2] = vls[i].value.in_handle.y;
+ wpo[idx * 5 + 3] = vls[i].value.out_handle.x;
+ wpo[idx * 5 + 4] = vls[i].value.out_handle.y;
+#ifdef TOOLS_ENABLED
+ whm[idx] = static_cast<int>(vls[i].value.handle_mode);
+#endif // TOOLS_ENABLED
idx++;
}
d["times"] = key_times;
d["points"] = key_points;
+#ifdef TOOLS_ENABLED
+ d["handle_modes"] = handle_modes;
+#endif // TOOLS_ENABLED
r_ret = d;
@@ -967,7 +986,6 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const
void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) {
ERR_FAIL_INDEX(p_track, tracks.size());
- ERR_FAIL_INDEX(p_interp, 3);
tracks[p_track]->interpolation = p_interp;
emit_changed();
}
@@ -1563,33 +1581,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 +1619,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 +1638,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() != 5, -1);
TKey<BezierKey> k;
k.time = p_time;
@@ -1634,24 +1654,31 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
k.value.in_handle.y = arr[2];
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);
+ Vector<int> key_neighborhood;
+ key_neighborhood.push_back(ret);
+ if (ret > 0) {
+ key_neighborhood.push_back(ret - 1);
+ }
+ if (ret < track_get_key_count(p_track) - 1) {
+ key_neighborhood.push_back(ret + 1);
+ }
} 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 +1688,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 {
@@ -1773,13 +1802,12 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const {
ERR_FAIL_INDEX_V(p_key_idx, bt->values.size(), Variant());
Array arr;
- arr.resize(6);
+ arr.resize(5);
arr[0] = bt->values[p_key_idx].value.value;
arr[1] = bt->values[p_key_idx].value.in_handle.x;
arr[2] = bt->values[p_key_idx].value.in_handle.y;
arr[3] = bt->values[p_key_idx].value.out_handle.x;
arr[4] = bt->values[p_key_idx].value.out_handle.y;
- arr[5] = (double)bt->values[p_key_idx].value.handle_mode;
return arr;
} break;
@@ -2148,14 +2176,13 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
ERR_FAIL_INDEX(p_key_idx, bt->values.size());
Array arr = p_value;
- ERR_FAIL_COND(arr.size() != 6);
+ ERR_FAIL_COND(arr.size() != 5);
bt->values.write[p_key_idx].value.value = arr[0];
bt->values.write[p_key_idx].value.in_handle.x = arr[1];
bt->values.write[p_key_idx].value.in_handle.y = arr[2];
bt->values.write[p_key_idx].value.out_handle.x = arr[3];
bt->values.write[p_key_idx].value.out_handle.y = arr[4];
- bt->values.write[p_key_idx].value.handle_mode = static_cast<HandleMode>((int)arr[5]);
} break;
case TYPE_AUDIO: {
@@ -2279,6 +2306,8 @@ int Animation::_find(const Vector<K> &p_keys, double p_time, bool p_backward) co
return middle;
}
+// Linear interpolation for anytype.
+
Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const {
return p_a.lerp(p_b, p_c);
}
@@ -2288,24 +2317,37 @@ Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b,
}
Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const {
- Variant dst;
- Variant::interpolate(p_a, p_b, p_c, dst);
- return dst;
+ return interpolate_variant(p_a, p_b, p_c);
}
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
- return p_a * (1.0 - p_c) + p_b * p_c;
+ return Math::lerp(p_a, p_b, p_c);
}
-Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const {
- return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
+Variant Animation::_interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const {
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ uint32_t vformat = 1 << type_a;
+ vformat |= 1 << type_b;
+ if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
+ real_t a = p_a;
+ real_t b = p_b;
+ return Math::fposmod((float)Math::lerp_angle(a, b, p_c), (float)Math_TAU);
+ }
+ return _interpolate(p_a, p_b, p_c);
+}
+
+// Cubic interpolation for anytype.
+
+Vector3 Animation::_cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return p_a.cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
-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);
+Quaternion Animation::_cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return p_a.spherical_cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
-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 {
+Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
Variant::Type type_a = p_a.get_type();
Variant::Type type_b = p_b.get_type();
Variant::Type type_pa = p_pre_a.get_type();
@@ -2325,7 +2367,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
real_t pa = p_pre_a;
real_t pb = p_post_b;
- return Math::cubic_interpolate(a, b, pa, pb, p_c);
+ return Math::cubic_interpolate_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
} else if ((vformat & (vformat - 1))) {
return p_a; //can't interpolate, mix of types
}
@@ -2337,7 +2379,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Vector2 pa = p_pre_a;
Vector2 pb = p_post_b;
- return a.cubic_interpolate(b, pa, pb, p_c);
+ return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
case Variant::RECT2: {
Rect2 a = p_a;
@@ -2346,8 +2388,8 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Rect2 pb = p_post_b;
return Rect2(
- a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c),
- a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c));
+ a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t),
+ a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t));
}
case Variant::VECTOR3: {
Vector3 a = p_a;
@@ -2355,7 +2397,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Vector3 pa = p_pre_a;
Vector3 pb = p_post_b;
- return a.cubic_interpolate(b, pa, pb, p_c);
+ return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
case Variant::QUATERNION: {
Quaternion a = p_a;
@@ -2363,7 +2405,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_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
case Variant::AABB: {
AABB a = p_a;
@@ -2372,8 +2414,8 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
AABB pb = p_post_b;
return AABB(
- a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c),
- a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c));
+ a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t),
+ a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t));
}
default: {
return _interpolate(p_a, p_b, p_c);
@@ -2381,7 +2423,26 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
}
}
-real_t Animation::_cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const {
+real_t Animation::_cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return Math::cubic_interpolate_in_time(p_a, p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+}
+
+Variant Animation::_cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ Variant::Type type_pa = p_pre_a.get_type();
+ Variant::Type type_pb = p_post_b.get_type();
+ uint32_t vformat = 1 << type_a;
+ vformat |= 1 << type_b;
+ vformat |= 1 << type_pa;
+ vformat |= 1 << type_pb;
+ if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
+ real_t a = p_a;
+ real_t b = p_b;
+ real_t pa = p_pre_a;
+ real_t pb = p_post_b;
+ return Math::fposmod((float)Math::cubic_interpolate_angle_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t), (float)Math_TAU);
+ }
return _interpolate(p_a, p_b, p_c);
}
@@ -2564,26 +2625,70 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
case INTERPOLATION_LINEAR: {
return _interpolate(p_keys[idx].value, p_keys[next].value, c);
} break;
- case INTERPOLATION_CUBIC: {
- int pre = idx - 1;
- if (pre < 0) {
- if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
- pre = len - 1;
- } else {
- pre = 0;
+ case INTERPOLATION_LINEAR_ANGLE: {
+ return _interpolate_angle(p_keys[idx].value, p_keys[next].value, c);
+ } break;
+ case INTERPOLATION_CUBIC:
+ case INTERPOLATION_CUBIC_ANGLE: {
+ int pre = 0;
+ int post = 0;
+ if (!p_backward) {
+ pre = idx - 1;
+ if (pre < 0) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre = len - 1;
+ } else {
+ pre = 0;
+ }
}
- }
- int post = next + 1;
- if (post >= len) {
- if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
- post = 0;
- } else {
- post = next;
+ post = next + 1;
+ if (post >= len) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ post = 0;
+ } else {
+ post = next;
+ }
+ }
+ } else {
+ pre = idx + 1;
+ if (pre >= len) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre = 0;
+ } else {
+ pre = idx;
+ }
+ }
+ post = next - 1;
+ if (post < 0) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ post = len - 1;
+ } else {
+ post = 0;
+ }
}
}
- return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
+ real_t pre_t = 0.0;
+ real_t to_t = 0.0;
+ real_t post_t = 0.0;
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre_t = pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time;
+ to_t = next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time;
+ post_t = next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time;
+ } else {
+ pre_t = p_keys[pre].time - p_keys[idx].time;
+ to_t = p_keys[next].time - p_keys[idx].time;
+ post_t = p_keys[post].time - p_keys[idx].time;
+ }
+ if (p_interp == INTERPOLATION_CUBIC_ANGLE) {
+ return _cubic_interpolate_angle_in_time(
+ p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
+ pre_t, to_t, post_t);
+ }
+ return _cubic_interpolate_in_time(
+ p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
+ pre_t, to_t, post_t);
} break;
default:
return p_keys[idx].value;
@@ -3211,7 +3316,7 @@ StringName Animation::method_track_get_name(int p_track, int p_key_idx) const {
return pm->methods[p_key_idx].method;
}
-int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode) {
+int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle) {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
ERR_FAIL_COND_V(t->type != TYPE_BEZIER, -1);
@@ -3229,7 +3334,6 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu
if (k.value.out_handle.x < 0) {
k.value.out_handle.x = 0;
}
- k.value.handle_mode = p_handle_mode;
int key = _insert(p_time, bt->values, k);
@@ -3238,30 +3342,6 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu
return key;
}
-void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio) {
- ERR_FAIL_INDEX(p_track, tracks.size());
- Track *t = tracks[p_track];
- ERR_FAIL_COND(t->type != TYPE_BEZIER);
-
- BezierTrack *bt = static_cast<BezierTrack *>(t);
-
- ERR_FAIL_INDEX(p_index, bt->values.size());
-
- bt->values.write[p_index].value.handle_mode = p_mode;
-
- if (p_mode == HANDLE_MODE_BALANCED) {
- Transform2D xform;
- xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
-
- Vector2 vec_in = xform.xform(bt->values[p_index].value.in_handle);
- Vector2 vec_out = xform.xform(bt->values[p_index].value.out_handle);
-
- bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
- }
-
- emit_changed();
-}
-
void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_value) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
@@ -3272,10 +3352,11 @@ void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_va
ERR_FAIL_INDEX(p_index, bt->values.size());
bt->values.write[p_index].value.value = p_value;
+
emit_changed();
}
-void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) {
+void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
ERR_FAIL_COND(t->type != TYPE_BEZIER);
@@ -3290,7 +3371,11 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V
}
bt->values.write[p_index].value.in_handle = in_handle;
- if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
+#ifdef TOOLS_ENABLED
+ if (bt->values[p_index].value.handle_mode == HANDLE_MODE_LINEAR) {
+ bt->values.write[p_index].value.in_handle = Vector2();
+ bt->values.write[p_index].value.out_handle = Vector2();
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
@@ -3298,12 +3383,15 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V
Vector2 vec_in = xform.xform(in_handle);
bt->values.write[p_index].value.out_handle = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_MIRRORED) {
+ bt->values.write[p_index].value.out_handle = -in_handle;
}
+#endif // TOOLS_ENABLED
emit_changed();
}
-void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) {
+void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
ERR_FAIL_COND(t->type != TYPE_BEZIER);
@@ -3318,7 +3406,11 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const
}
bt->values.write[p_index].value.out_handle = out_handle;
- if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
+#ifdef TOOLS_ENABLED
+ if (bt->values[p_index].value.handle_mode == HANDLE_MODE_LINEAR) {
+ bt->values.write[p_index].value.in_handle = Vector2();
+ bt->values.write[p_index].value.out_handle = Vector2();
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
@@ -3326,7 +3418,10 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const
Vector2 vec_out = xform.xform(out_handle);
bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_MIRRORED) {
+ bt->values.write[p_index].value.in_handle = -out_handle;
}
+#endif // TOOLS_ENABLED
emit_changed();
}
@@ -3343,18 +3438,6 @@ real_t Animation::bezier_track_get_key_value(int p_track, int p_index) const {
return bt->values[p_index].value.value;
}
-int Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const {
- ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
- Track *t = tracks[p_track];
- ERR_FAIL_COND_V(t->type != TYPE_BEZIER, 0);
-
- BezierTrack *bt = static_cast<BezierTrack *>(t);
-
- ERR_FAIL_INDEX_V(p_index, bt->values.size(), 0);
-
- return bt->values[p_index].value.handle_mode;
-}
-
Vector2 Animation::bezier_track_get_key_in_handle(int p_track, int p_index) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector2());
Track *t = tracks[p_track];
@@ -3379,16 +3462,108 @@ Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) con
return bt->values[p_index].value.out_handle;
}
-static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, const Vector2 &control_1, const Vector2 &control_2, const Vector2 &end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
+#ifdef TOOLS_ENABLED
+void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode) {
+ ERR_FAIL_INDEX(p_track, tracks.size());
+ Track *t = tracks[p_track];
+ ERR_FAIL_COND(t->type != TYPE_BEZIER);
- return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
+ BezierTrack *bt = static_cast<BezierTrack *>(t);
+
+ ERR_FAIL_INDEX(p_index, bt->values.size());
+
+ bt->values.write[p_index].value.handle_mode = p_mode;
+
+ switch (p_mode) {
+ case HANDLE_MODE_LINEAR: {
+ bt->values.write[p_index].value.in_handle = Vector2(0, 0);
+ bt->values.write[p_index].value.out_handle = Vector2(0, 0);
+ } break;
+ case HANDLE_MODE_BALANCED:
+ case HANDLE_MODE_MIRRORED: {
+ int prev_key = MAX(0, p_index - 1);
+ int next_key = MIN(bt->values.size() - 1, p_index + 1);
+ if (prev_key == next_key) {
+ break; // Exists only one key.
+ }
+ real_t in_handle_x = 0;
+ real_t in_handle_y = 0;
+ real_t out_handle_x = 0;
+ real_t out_handle_y = 0;
+ if (p_mode == HANDLE_MODE_BALANCED) {
+ // Note:
+ // If p_set_mode == HANDLE_SET_MODE_NONE, I don't know if it should change the Tangent implicitly.
+ // At the least, we need to avoid corrupting the handles when loading animation from the resource.
+ // However, changes made by the Inspector do not go through the BezierEditor,
+ // so if you change from Free to Balanced or Mirrored in Inspector, there is no guarantee that
+ // it is Balanced or Mirrored until there is a handle operation.
+ if (p_set_mode == HANDLE_SET_MODE_RESET) {
+ real_t handle_length = 1.0 / 3.0;
+ in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length;
+ in_handle_y = 0;
+ out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length;
+ out_handle_y = 0;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ } else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
+ real_t handle_length = 1.0 / 6.0;
+ real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / (bt->values[next_key].time - bt->values[prev_key].time);
+ in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length;
+ in_handle_y = in_handle_x * tangent;
+ out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length;
+ out_handle_y = out_handle_x * tangent;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ }
+ } else {
+ real_t handle_length = 1.0 / 4.0;
+ real_t prev_interval = Math::abs(bt->values[p_index].time - bt->values[prev_key].time);
+ real_t next_interval = Math::abs(bt->values[p_index].time - bt->values[next_key].time);
+ real_t min_time = 0;
+ if (Math::is_zero_approx(prev_interval)) {
+ min_time = next_interval;
+ } else if (Math::is_zero_approx(next_interval)) {
+ min_time = prev_interval;
+ } else {
+ min_time = MIN(prev_interval, next_interval);
+ }
+ if (p_set_mode == HANDLE_SET_MODE_RESET) {
+ in_handle_x = -min_time * handle_length;
+ in_handle_y = 0;
+ out_handle_x = min_time * handle_length;
+ out_handle_y = 0;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ } else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
+ real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / min_time;
+ in_handle_x = -min_time * handle_length;
+ in_handle_y = in_handle_x * tangent;
+ out_handle_x = min_time * handle_length;
+ out_handle_y = out_handle_x * tangent;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ }
+ }
+ } break;
+ default: {
+ } break;
+ }
+
+ emit_changed();
+}
+
+Animation::HandleMode Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const {
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), HANDLE_MODE_FREE);
+ Track *t = tracks[p_track];
+ ERR_FAIL_COND_V(t->type != TYPE_BEZIER, HANDLE_MODE_FREE);
+
+ BezierTrack *bt = static_cast<BezierTrack *>(t);
+
+ ERR_FAIL_INDEX_V(p_index, bt->values.size(), HANDLE_MODE_FREE);
+
+ return bt->values[p_index].value.handle_mode;
}
+#endif // TOOLS_ENABLED
real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
//this uses a different interpolation scheme
@@ -3438,7 +3613,7 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
for (int i = 0; i < iterations; i++) {
real_t middle = (low + high) / 2;
- Vector2 interp = _bezier_interp(middle, start, start_out, end_in, end);
+ Vector2 interp = start.bezier_interpolate(start_out, end_in, end, middle);
if (interp.x < t) {
low = middle;
@@ -3448,8 +3623,8 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
}
//interpolate the result:
- Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end);
- Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end);
+ Vector2 low_pos = start.bezier_interpolate(start_out, end_in, end, low);
+ Vector2 high_pos = start.bezier_interpolate(start_out, end_in, end, high);
real_t c = (t - low_pos.x) / (high_pos.x - low_pos.x);
return low_pos.lerp(high_pos, c).y;
@@ -3786,7 +3961,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name);
ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params);
- ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle", "handle_mode"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(Animation::HandleMode::HANDLE_MODE_BALANCED));
+ ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "track_idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_in_handle, DEFVAL(1.0));
@@ -3806,9 +3981,6 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_handle_mode", "track_idx", "key_idx", "key_handle_mode", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_handle_mode, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_handle_mode", "track_idx", "key_idx"), &Animation::bezier_track_get_key_handle_mode);
-
ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key);
ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation);
@@ -3827,9 +3999,9 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("compress", "page_size", "fps", "split_tolerance"), &Animation::compress, DEFVAL(8192), DEFVAL(120), DEFVAL(4.0));
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001,suffix:s"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_step", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001,suffix:s"), "set_step", "get_step");
ADD_SIGNAL(MethodInfo("tracks_changed"));
@@ -3846,6 +4018,8 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST);
BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR);
BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC);
+ BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR_ANGLE);
+ BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_ANGLE);
BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS);
BIND_ENUM_CONSTANT(UPDATE_DISCRETE);
@@ -3855,9 +4029,6 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(LOOP_NONE);
BIND_ENUM_CONSTANT(LOOP_LINEAR);
BIND_ENUM_CONSTANT(LOOP_PINGPONG);
-
- BIND_ENUM_CONSTANT(HANDLE_MODE_FREE);
- BIND_ENUM_CONSTANT(HANDLE_MODE_BALANCED);
}
void Animation::clear() {
@@ -3875,316 +4046,369 @@ void Animation::clear() {
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
-bool Animation::_position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm) {
- const Vector3 &v0 = t0.value;
- const Vector3 &v1 = t1.value;
- const Vector3 &v2 = t2.value;
-
- if (v0.is_equal_approx(v2)) {
- //0 and 2 are close, let's see if 1 is close
- if (!v0.is_equal_approx(v1)) {
- //not close, not optimizable
- return false;
- }
-
- } else {
- Vector3 pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false;
- }
-
- Vector3 s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_err) {
- return false; //beyond allowed error for collinearity
- }
-
- if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_allowed_angular_error) {
- return false;
+bool Animation::_float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if (abs(t0.value - t1.value) < p_allowed_precision_error && abs(t1.value - t2.value) < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ double v0 = (t1.value - t0.value) / (t1.time - t0.time);
+ double v1 = (t2.value - t1.value) / (t2.time - t1.time);
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ if (!signbit(v0 * v1)) {
+ v0 = abs(v0);
+ v1 = abs(v1);
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle) {
- const Quaternion &q0 = t0.value;
- const Quaternion &q1 = t1.value;
- const Quaternion &q2 = t2.value;
-
- //localize both to rotation from q0
-
- if (q0.is_equal_approx(q2)) {
- if (!q0.is_equal_approx(q1)) {
- return false;
- }
-
- } else {
- Quaternion r02 = (q0.inverse() * q2).normalized();
- Quaternion r01 = (q0.inverse() * q1).normalized();
-
- Vector3 v02, v01;
- real_t a02, a01;
-
- r02.get_axis_angle(v02, a02);
- r01.get_axis_angle(v01, a01);
-
- if (Math::abs(a02) > p_max_optimizable_angle) {
- return false;
- }
-
- if (v01.dot(v02) < 0) {
- //make sure both rotations go the same way to compare
- v02 = -v02;
- a02 = -a02;
- }
-
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI;
- if (err_01 > p_allowed_angular_error) {
- //not rotating in the same axis
- return false;
- }
-
- if (a01 * a02 < 0) {
- //not rotating in the same direction
- return false;
- }
-
- real_t tr = a01 / a02;
- if (tr < 0 || tr > 1) {
- return false; //rotating too much or too less
+bool Animation::_vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ Vector2 vc0 = (t1.value - t0.value) / (t1.time - t0.time);
+ Vector2 vc1 = (t2.value - t1.value) / (t2.time - t1.time);
+ double v0 = vc0.length();
+ double v1 = vc1.length();
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ // Check axis.
+ if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ v0 = abs(v0);
+ v1 = abs(v1);
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error) {
- const Vector3 &v0 = t0.value;
- const Vector3 &v1 = t1.value;
- const Vector3 &v2 = t2.value;
-
- if (v0.is_equal_approx(v2)) {
- //0 and 2 are close, let's see if 1 is close
- if (!v0.is_equal_approx(v1)) {
- //not close, not optimizable
- return false;
- }
-
- } else {
- Vector3 pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false; //beyond segment range
- }
-
- Vector3 s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_error) {
- return false; //beyond allowed error for colinearity
+bool Animation::_vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ Vector3 vc0 = (t1.value - t0.value) / (t1.time - t0.time);
+ Vector3 vc1 = (t2.value - t1.value) / (t2.time - t1.time);
+ double v0 = vc0.length();
+ double v1 = vc1.length();
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ // Check axis.
+ if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ v0 = abs(v0);
+ v1 = abs(v1);
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error) {
- float v0 = t0.value;
- float v1 = t1.value;
- float v2 = t2.value;
-
- if (Math::is_equal_approx(v1, v2, (float)p_allowed_unit_error)) {
- //0 and 2 are close, let's see if 1 is close
- if (!Math::is_equal_approx(v0, v1, (float)p_allowed_unit_error)) {
- //not close, not optimizable
- return false;
+bool Animation::_quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Check axis.
+ Quaternion q0 = t0.value * t1.value * t0.value.inverse();
+ Quaternion q1 = t1.value * t2.value * t1.value.inverse();
+ if (q0.get_axis().dot(q1.get_axis()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ double a0 = Math::acos(t0.value.dot(t1.value));
+ double a1 = Math::acos(t1.value.dot(t2.value));
+ if (a0 + a1 >= Math_PI) {
+ return false; // Rotation is more than 180 deg, keep key.
}
- } else {
- /*
- TODO eventually discuss a way to optimize these better.
- float pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false; //beyond segment range
+ // Calc velocities.
+ double v0 = a0 / (t1.time - t0.time);
+ double v1 = a1 / (t2.time - t1.time);
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
}
-
- float s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_error) {
- return false; //beyond allowed error for colinearity
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
-*/
}
-
- return true;
+ return false;
}
-void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) {
+void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Vector3> first_erased;
- Vector3 norm;
-
- for (int i = 1; i < tt->positions.size() - 1; i++) {
- TKey<Vector3> &t0 = tt->positions.write[i - 1];
- TKey<Vector3> &t1 = tt->positions.write[i];
- TKey<Vector3> &t2 = tt->positions.write[i + 1];
-
- bool erase = _position_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, norm);
- if (erase && !prev_erased) {
- norm = (t2.value - t1.value).normalized();
- }
-
- if (prev_erased && !_position_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, norm)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < tt->positions.size() - 2) {
+ TKey<Vector3> t0 = tt->positions[i];
+ TKey<Vector3> t1 = tt->positions[i + 1];
+ TKey<Vector3> t2 = tt->positions[i + 2];
+ bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->positions.remove_at(i);
- i--;
-
+ tt->positions.remove_at(i + 1);
} else {
- prev_erased = false;
- norm = Vector3();
+ i++;
+ }
+ }
+
+ if (tt->positions.size() == 2) {
+ if ((tt->positions[0].value - tt->positions[1].value).length() < p_allowed_precision_error) {
+ tt->positions.remove_at(1);
}
}
}
-void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) {
+void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D);
- RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Quaternion> first_erased;
-
- for (int i = 1; i < tt->rotations.size() - 1; i++) {
- TKey<Quaternion> &t0 = tt->rotations.write[i - 1];
- TKey<Quaternion> &t1 = tt->rotations.write[i];
- TKey<Quaternion> &t2 = tt->rotations.write[i + 1];
+ RotationTrack *rt = static_cast<RotationTrack *>(tracks[p_idx]);
- bool erase = _rotation_track_optimize_key(t0, t1, t2, p_allowed_angular_err, p_max_optimizable_angle);
-
- if (prev_erased && !_rotation_track_optimize_key(t0, first_erased, t2, p_allowed_angular_err, p_max_optimizable_angle)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < rt->rotations.size() - 2) {
+ TKey<Quaternion> t0 = rt->rotations[i];
+ TKey<Quaternion> t1 = rt->rotations[i + 1];
+ TKey<Quaternion> t2 = rt->rotations[i + 2];
+ bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->rotations.remove_at(i);
- i--;
-
+ rt->rotations.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (rt->rotations.size() == 2) {
+ if ((rt->rotations[0].value - rt->rotations[1].value).length() < p_allowed_precision_error) {
+ rt->rotations.remove_at(1);
}
}
}
-void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) {
+void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D);
- ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Vector3> first_erased;
-
- for (int i = 1; i < tt->scales.size() - 1; i++) {
- TKey<Vector3> &t0 = tt->scales.write[i - 1];
- TKey<Vector3> &t1 = tt->scales.write[i];
- TKey<Vector3> &t2 = tt->scales.write[i + 1];
+ ScaleTrack *st = static_cast<ScaleTrack *>(tracks[p_idx]);
- bool erase = _scale_track_optimize_key(t0, t1, t2, p_allowed_linear_err);
-
- if (prev_erased && !_scale_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < st->scales.size() - 2) {
+ TKey<Vector3> t0 = st->scales[i];
+ TKey<Vector3> t1 = st->scales[i + 1];
+ TKey<Vector3> t2 = st->scales[i + 2];
+ bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->scales.remove_at(i);
- i--;
-
+ st->scales.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (st->scales.size() == 2) {
+ if ((st->scales[0].value - st->scales[1].value).length() < p_allowed_precision_error) {
+ st->scales.remove_at(1);
}
}
}
-void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_linear_err) {
+void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE);
- BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<float> first_erased;
- first_erased.value = 0.0;
-
- for (int i = 1; i < tt->blend_shapes.size() - 1; i++) {
- TKey<float> &t0 = tt->blend_shapes.write[i - 1];
- TKey<float> &t1 = tt->blend_shapes.write[i];
- TKey<float> &t2 = tt->blend_shapes.write[i + 1];
+ BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(tracks[p_idx]);
- bool erase = _blend_shape_track_optimize_key(t0, t1, t2, p_allowed_linear_err);
+ int i = 0;
+ while (i < bst->blend_shapes.size() - 2) {
+ TKey<float> t0 = bst->blend_shapes[i];
+ TKey<float> t1 = bst->blend_shapes[i + 1];
+ TKey<float> t2 = bst->blend_shapes[i + 2];
- if (prev_erased && !_blend_shape_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) {
- //avoid error to go beyond first erased key
- erase = false;
+ bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
+ if (erase) {
+ bst->blend_shapes.remove_at(i + 1);
+ } else {
+ i++;
}
+ }
- if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
+ if (bst->blend_shapes.size() == 2) {
+ if (abs(bst->blend_shapes[0].value - bst->blend_shapes[1].value) < p_allowed_precision_error) {
+ bst->blend_shapes.remove_at(1);
+ }
+ }
+}
- tt->blend_shapes.remove_at(i);
- i--;
+void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
+ ERR_FAIL_INDEX(p_idx, tracks.size());
+ ERR_FAIL_COND(tracks[p_idx]->type != TYPE_VALUE);
+ ValueTrack *vt = static_cast<ValueTrack *>(tracks[p_idx]);
+ if (vt->values.size() == 0) {
+ return;
+ }
+ Variant::Type type = vt->values[0].value.get_type();
+
+ // Special case for angle interpolation.
+ bool is_using_angle = vt->interpolation == Animation::INTERPOLATION_LINEAR_ANGLE || vt->interpolation == Animation::INTERPOLATION_CUBIC_ANGLE;
+ int i = 0;
+ while (i < vt->values.size() - 2) {
+ bool erase = false;
+ switch (type) {
+ case Variant::FLOAT: {
+ TKey<float> t0;
+ TKey<float> t1;
+ TKey<float> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ if (is_using_angle) {
+ float diff1 = fmod(t1.value - t0.value, Math_TAU);
+ t1.value = t0.value + fmod(2.0 * diff1, Math_TAU) - diff1;
+ float diff2 = fmod(t2.value - t1.value, Math_TAU);
+ t2.value = t1.value + fmod(2.0 * diff2, Math_TAU) - diff2;
+ if (abs(abs(diff1) + abs(diff2)) >= Math_PI) {
+ break; // Rotation is more than 180 deg, keep key.
+ }
+ }
+ erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
+ } break;
+ case Variant::VECTOR2: {
+ TKey<Vector2> t0;
+ TKey<Vector2> t1;
+ TKey<Vector2> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ erase = _vector2_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
+ } break;
+ case Variant::VECTOR3: {
+ TKey<Vector3> t0;
+ TKey<Vector3> t1;
+ TKey<Vector3> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
+ } break;
+ case Variant::QUATERNION: {
+ TKey<Quaternion> t0;
+ TKey<Quaternion> t1;
+ TKey<Quaternion> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
+ } break;
+ default: {
+ } break;
+ }
+ if (erase) {
+ vt->values.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (vt->values.size() == 2) {
+ bool single_key = false;
+ switch (type) {
+ case Variant::FLOAT: {
+ float val_0 = vt->values[0].value;
+ float val_1 = vt->values[1].value;
+ if (is_using_angle) {
+ float diff1 = fmod(val_1 - val_0, Math_TAU);
+ val_1 = val_0 + fmod(2.0 * diff1, Math_TAU) - diff1;
+ }
+ single_key = abs(val_0 - val_1) < p_allowed_precision_error;
+ } break;
+ case Variant::VECTOR2: {
+ Vector2 val_0 = vt->values[0].value;
+ Vector2 val_1 = vt->values[1].value;
+ single_key = (val_0 - val_1).length() < p_allowed_precision_error;
+ } break;
+ case Variant::VECTOR3: {
+ Vector3 val_0 = vt->values[0].value;
+ Vector3 val_1 = vt->values[1].value;
+ single_key = (val_0 - val_1).length() < p_allowed_precision_error;
+ } break;
+ case Variant::QUATERNION: {
+ Quaternion val_0 = vt->values[0].value;
+ Quaternion val_1 = vt->values[1].value;
+ single_key = (val_0 - val_1).length() < p_allowed_precision_error;
+ } break;
+ default: {
+ } break;
+ }
+ if (single_key) {
+ vt->values.remove_at(1);
}
}
}
-void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) {
+void Animation::optimize(real_t p_allowed_velocity_err, real_t p_allowed_angular_err, int p_precision) {
+ real_t precision = Math::pow(0.1, p_precision);
for (int i = 0; i < tracks.size(); i++) {
if (track_is_compressed(i)) {
continue; //not possible to optimize compressed track
}
if (tracks[i]->type == TYPE_POSITION_3D) {
- _position_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err);
+ _position_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_ROTATION_3D) {
- _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle);
+ _rotation_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_SCALE_3D) {
- _scale_track_optimize(i, p_allowed_linear_err);
+ _scale_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_BLEND_SHAPE) {
- _blend_shape_track_optimize(i, p_allowed_linear_err);
+ _blend_shape_track_optimize(i, p_allowed_velocity_err, precision);
+ } else if (tracks[i]->type == TYPE_VALUE) {
+ _value_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
}
}
}
@@ -5337,6 +5561,466 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
return false;
}
+// Helper math functions for Variant.
+Variant Animation::add_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) + (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal, pa.d + pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position, aa.size + ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * (b.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * (b.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * (b.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_ADD, a, b);
+ }
+ }
+}
+
+Variant Animation::subtract_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) - (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal - pb.normal, pa.d - pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position - ab.position, aa.size - ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (b.operator Quaternion()).inverse() * (a.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (b.operator Transform2D()).inverse() * (a.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (b.operator Transform3D()).inverse() * (a.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_SUBTRACT, a, b);
+ }
+ }
+}
+
+Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + vb * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ return int((a.operator int64_t()) + (b.operator int64_t()) * c + 0.5);
+ }
+ case Variant::FLOAT: {
+ return (a.operator double()) + (b.operator double()) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()) + (b.operator Vector2()) * c;
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position * c, ra.size + rb.size * c);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + rb.position.x * c + 0.5), int32_t(ra.position.y + rb.position.y * c + 0.5), int32_t(ra.size.x + rb.size.x * c + 0.5), int32_t(ra.size.y + rb.size.y * c + 0.5));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()) + (b.operator Vector3()) * c;
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()) + (b.operator Vector4()) * c;
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5), int32_t(va.w + vb.w * c + 0.5));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal * c, pa.d + pb.d * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()) + (b.operator Color()) * c;
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position * c, aa.size + ab.size * c);
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()) + (b.operator Basis()) * c;
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * Quaternion().slerp((b.operator Quaternion()), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * Transform2D().interpolate_with((b.operator Transform2D()), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * Transform3D().interpolate_with((b.operator Transform3D()), c);
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
+Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + (vb - va) * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ const int64_t va = a.operator int64_t();
+ return int(va + ((b.operator int64_t()) - va) * c);
+ }
+ case Variant::FLOAT: {
+ const real_t va = a.operator real_t();
+ return va + ((b.operator real_t()) - va) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()).lerp(b.operator Vector2(), c);
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position.lerp(rb.position, c), ra.size.lerp(rb.size, c));
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + (rb.position.x - ra.position.x) * c), int32_t(ra.position.y + (rb.position.y - ra.position.y) * c), int32_t(ra.size.x + (rb.size.x - ra.size.x) * c), int32_t(ra.size.y + (rb.size.y - ra.size.y) * c));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()).lerp(b.operator Vector3(), c);
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()).lerp(b.operator Vector4(), c);
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c), int32_t(va.w + (vb.w - va.w) * c));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal.lerp(pb.normal, c), pa.d + (pb.d - pa.d) * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()).lerp(b.operator Color(), c);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position.lerp(ab.position, c), aa.size.lerp(ab.size, c));
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()).lerp(b.operator Basis(), c);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()).slerp(b.operator Quaternion(), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()).interpolate_with(b.operator Transform2D(), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()).interpolate_with(b.operator Transform3D(), c);
+ }
+ case Variant::STRING: {
+ // This is pretty funny and bizarre, but artists like to use it for typewriter effects.
+ const String sa = a.operator String();
+ const String sb = b.operator String();
+ String dst;
+ int sa_len = sa.length();
+ int sb_len = sb.length();
+ int csize = sa_len + (sb_len - sa_len) * c;
+ if (csize == 0) {
+ return "";
+ }
+ dst.resize(csize + 1);
+ dst[csize] = 0;
+ int split = csize / 2;
+
+ for (int i = 0; i < csize; i++) {
+ char32_t chr = ' ';
+
+ if (i < split) {
+ if (i < sa.length()) {
+ chr = sa[i];
+ } else if (i < sb.length()) {
+ chr = sb[i];
+ }
+
+ } else {
+ if (i < sb.length()) {
+ chr = sb[i];
+ } else if (i < sa.length()) {
+ chr = sa[i];
+ }
+ }
+
+ dst[i] = chr;
+ }
+
+ return dst;
+ }
+ case Variant::PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a);
+ const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b);
+ int32_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int32_t> v;
+ v.resize(sz);
+ {
+ int32_t *vw = v.ptrw();
+ const int32_t *ar = arr_a->ptr();
+ const int32_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int32_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a);
+ const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b);
+ int64_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int64_t> v;
+ v.resize(sz);
+ {
+ int64_t *vw = v.ptrw();
+ const int64_t *ar = arr_a->ptr();
+ const int64_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int64_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a);
+ const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<float> v;
+ v.resize(sz);
+ {
+ float *vw = v.ptrw();
+ const float *ar = arr_a->ptr();
+ const float *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a);
+ const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<double> v;
+ v.resize(sz);
+ {
+ double *vw = v.ptrw();
+ const double *ar = arr_a->ptr();
+ const double *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a);
+ const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector2> v;
+ v.resize(sz);
+ {
+ Vector2 *vw = v.ptrw();
+ const Vector2 *ar = arr_a->ptr();
+ const Vector2 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a);
+ const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector3> v;
+ v.resize(sz);
+ {
+ Vector3 *vw = v.ptrw();
+ const Vector3 *ar = arr_a->ptr();
+ const Vector3 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a);
+ const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Color> v;
+ v.resize(sz);
+ {
+ Color *vw = v.ptrw();
+ const Color *ar = arr_a->ptr();
+ const Color *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
Animation::Animation() {}
Animation::~Animation() {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index b4528ccd3a..49c8fa4c22 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -56,7 +56,9 @@ public:
enum InterpolationType {
INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR,
- INTERPOLATION_CUBIC
+ INTERPOLATION_CUBIC,
+ INTERPOLATION_LINEAR_ANGLE,
+ INTERPOLATION_CUBIC_ANGLE,
};
enum UpdateMode {
@@ -72,10 +74,19 @@ public:
LOOP_PINGPONG,
};
+#ifdef TOOLS_ENABLED
enum HandleMode {
HANDLE_MODE_FREE,
+ HANDLE_MODE_LINEAR,
HANDLE_MODE_BALANCED,
+ HANDLE_MODE_MIRRORED,
};
+ enum HandleSetMode {
+ HANDLE_SET_MODE_NONE,
+ HANDLE_SET_MODE_RESET,
+ HANDLE_SET_MODE_AUTO,
+ };
+#endif // TOOLS_ENABLED
private:
struct Track {
@@ -165,8 +176,10 @@ private:
struct BezierKey {
Vector2 in_handle; //relative (x always <0)
Vector2 out_handle; //relative (x always >0)
- HandleMode handle_mode = HANDLE_MODE_BALANCED;
real_t value = 0.0;
+#ifdef TOOLS_ENABLED
+ HandleMode handle_mode = HANDLE_MODE_FREE;
+#endif // TOOLS_ENABLED
};
struct BezierTrack : public Track {
@@ -225,11 +238,13 @@ private:
_FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const;
_FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const;
_FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const;
+ _FORCE_INLINE_ Variant _interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const;
- _FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const;
- _FORCE_INLINE_ Quaternion _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;
- _FORCE_INLINE_ Variant _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;
- _FORCE_INLINE_ real_t _cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const;
+ _FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Variant _cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
template <class T>
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
@@ -351,15 +366,16 @@ private:
return idxr;
}
- bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm);
- bool _rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle);
- bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error);
- bool _blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error);
+ bool _float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
+ bool _vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ bool _quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
- void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err);
- void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle);
- void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err);
- void _blend_shape_track_optimize(int p_idx, real_t p_allowed_unit_error);
+ void _position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
+ void _rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ void _scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
+ void _blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
+ void _value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -392,7 +408,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);
@@ -424,15 +440,17 @@ public:
void track_set_interpolation_type(int p_track, InterpolationType p_interp);
InterpolationType track_get_interpolation_type(int p_track) const;
- int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode = HandleMode::HANDLE_MODE_BALANCED);
- void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio = 1.0);
+ int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle);
void bezier_track_set_key_value(int p_track, int p_index, real_t p_value);
- void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0);
- void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0);
+ void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0);
+ void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0);
real_t bezier_track_get_key_value(int p_track, int p_index) const;
- int bezier_track_get_key_handle_mode(int p_track, int p_index) const;
Vector2 bezier_track_get_key_in_handle(int p_track, int p_index) const;
Vector2 bezier_track_get_key_out_handle(int p_track, int p_index) const;
+#ifdef TOOLS_ENABLED
+ void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode = HANDLE_SET_MODE_NONE);
+ HandleMode bezier_track_get_key_handle_mode(int p_track, int p_index) const;
+#endif // TOOLS_ENABLED
real_t bezier_track_interpolate(int p_track, double p_time) const;
@@ -475,9 +493,15 @@ public:
void clear();
- void optimize(real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125);
+ void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
+ // Helper math functions for Variant.
+ static Variant add_variant(const Variant &a, const Variant &b);
+ static Variant subtract_variant(const Variant &a, const Variant &b);
+ static Variant blend_variant(const Variant &a, const Variant &b, float c);
+ static Variant interpolate_variant(const Variant &a, const Variant &b, float c);
+
Animation();
~Animation();
};
@@ -485,7 +509,10 @@ public:
VARIANT_ENUM_CAST(Animation::TrackType);
VARIANT_ENUM_CAST(Animation::InterpolationType);
VARIANT_ENUM_CAST(Animation::UpdateMode);
-VARIANT_ENUM_CAST(Animation::HandleMode);
VARIANT_ENUM_CAST(Animation::LoopMode);
+#ifdef TOOLS_ENABLED
+VARIANT_ENUM_CAST(Animation::HandleMode);
+VARIANT_ENUM_CAST(Animation::HandleSetMode);
+#endif // TOOLS_ENABLED
-#endif
+#endif // ANIMATION_H
diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp
index 2a581fb126..427d418551 100644
--- a/scene/resources/animation_library.cpp
+++ b/scene/resources/animation_library.cpp
@@ -63,7 +63,7 @@ Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animat
}
void AnimationLibrary::remove_animation(const StringName &p_name) {
- ERR_FAIL_COND(!animations.has(p_name));
+ ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name));
animations.erase(p_name);
emit_signal(SNAME("animation_removed"), p_name);
@@ -71,9 +71,9 @@ void AnimationLibrary::remove_animation(const StringName &p_name) {
}
void AnimationLibrary::rename_animation(const StringName &p_name, const StringName &p_new_name) {
- ERR_FAIL_COND(!animations.has(p_name));
+ ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name));
ERR_FAIL_COND_MSG(!is_valid_animation_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'.");
- ERR_FAIL_COND(animations.has(p_new_name));
+ ERR_FAIL_COND_MSG(animations.has(p_new_name), vformat("Animation name \"%s\" already exists in library.", p_new_name));
animations.insert(p_new_name, animations[p_name]);
animations.erase(p_name);
@@ -85,7 +85,7 @@ bool AnimationLibrary::has_animation(const StringName &p_name) const {
}
Ref<Animation> AnimationLibrary::get_animation(const StringName &p_name) const {
- ERR_FAIL_COND_V(!animations.has(p_name), Ref<Animation>());
+ ERR_FAIL_COND_V_MSG(!animations.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
return animations[p_name];
}
@@ -143,9 +143,9 @@ void AnimationLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_data"), &AnimationLibrary::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
- ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation")));
- ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation")));
- ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"), PropertyInfo(Variant::OBJECT, "to_name", PROPERTY_HINT_RESOURCE_TYPE, "Animation")));
+ ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::STRING_NAME, "name")));
+ ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::STRING_NAME, "name")));
+ ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::STRING_NAME, "name"), PropertyInfo(Variant::STRING_NAME, "to_name")));
}
AnimationLibrary::AnimationLibrary() {
}
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..9bd1e84524 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(double 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,28 +55,28 @@ 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 {
+double 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(double p_time) {
+ if (base->format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
return; //no seeking in ima-adpcm
}
- float max = base->get_length();
+ double max = base->get_length();
if (p_time < 0) {
p_time = 0;
} else if (p_time >= max) {
@@ -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 {
+double 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;
}
@@ -477,14 +481,14 @@ float AudioStreamSample::get_length() const {
len /= 2;
}
- return float(len) / mix_rate;
+ return double(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..d0edc52031 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,29 +57,31 @@ 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);
public:
- virtual void start(float p_from_pos = 0.0) override;
+ virtual void start(double p_from_pos = 0.0) override;
virtual void stop() override;
virtual bool is_playing() const override;
virtual int get_loop_count() const override; //times it looped
- virtual float get_playback_position() const override;
- virtual void seek(float p_time) override;
+ virtual double get_playback_position() const override;
+ virtual void seek(double p_time) override;
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
@@ -135,7 +137,7 @@ public:
void set_stereo(bool p_enable);
bool is_stereo() const;
- virtual float get_length() const override; //if supported, otherwise return 0
+ virtual double get_length() const override; //if supported, otherwise return 0
virtual bool is_monophonic() const override;
@@ -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/bit_map.cpp b/scene/resources/bit_map.cpp
index 634fb3ef2f..0505f6b559 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -31,14 +31,20 @@
#include "bit_map.h"
#include "core/io/image_loader.h"
+#include "core/variant/typed_array.h"
-void BitMap::create(const Size2 &p_size) {
+void BitMap::create(const Size2i &p_size) {
ERR_FAIL_COND(p_size.width < 1);
ERR_FAIL_COND(p_size.height < 1);
+ ERR_FAIL_COND(static_cast<int64_t>(p_size.width) * static_cast<int64_t>(p_size.height) > INT32_MAX);
+
+ Error err = bitmask.resize((((p_size.width * p_size.height) - 1) / 8) + 1);
+ ERR_FAIL_COND(err != OK);
+
width = p_size.width;
height = p_size.height;
- bitmask.resize((((width * height) - 1) / 8) + 1);
+
memset(bitmask.ptrw(), 0, bitmask.size());
}
@@ -48,7 +54,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
img->convert(Image::FORMAT_LA8);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8);
- create(img->get_size());
+ create(Size2i(img->get_width(), img->get_height()));
const uint8_t *r = img->get_data().ptr();
uint8_t *w = bitmask.ptrw();
@@ -62,7 +68,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
}
}
-void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) {
+void BitMap::set_bit_rect(const Rect2i &p_rect, bool p_value) {
Rect2i current = Rect2i(0, 0, width, height).intersection(p_rect);
uint8_t *data = bitmask.ptrw();
@@ -90,7 +96,7 @@ int BitMap::get_true_bit_count() const {
const uint8_t *d = bitmask.ptr();
int c = 0;
- //fast, almost branchless version
+ // Fast, almost branchless version.
for (int i = 0; i < ds; i++) {
c += (d[i] & (1 << 7)) >> 7;
@@ -106,14 +112,15 @@ int BitMap::get_true_bit_count() const {
return c;
}
-void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
- int x = p_pos.x;
- int y = p_pos.y;
+void BitMap::set_bitv(const Point2i &p_pos, bool p_value) {
+ set_bit(p_pos.x, p_pos.y, p_value);
+}
- ERR_FAIL_INDEX(x, width);
- ERR_FAIL_INDEX(y, height);
+void BitMap::set_bit(int p_x, int p_y, bool p_value) {
+ ERR_FAIL_INDEX(p_x, width);
+ ERR_FAIL_INDEX(p_y, height);
- int ofs = width * y + x;
+ int ofs = width * p_y + p_x;
int bbyte = ofs / 8;
int bbit = ofs % 8;
@@ -128,21 +135,23 @@ void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
bitmask.write[bbyte] = b;
}
-bool BitMap::get_bit(const Point2 &p_pos) const {
- int x = Math::fast_ftoi(p_pos.x);
- int y = Math::fast_ftoi(p_pos.y);
- ERR_FAIL_INDEX_V(x, width, false);
- ERR_FAIL_INDEX_V(y, height, false);
+bool BitMap::get_bitv(const Point2i &p_pos) const {
+ return get_bit(p_pos.x, p_pos.y);
+}
+
+bool BitMap::get_bit(int p_x, int p_y) const {
+ ERR_FAIL_INDEX_V(p_x, width, false);
+ ERR_FAIL_INDEX_V(p_y, height, false);
- int ofs = width * y + x;
+ int ofs = width * p_y + p_x;
int bbyte = ofs / 8;
int bbit = ofs % 8;
return (bitmask[bbyte] & (1 << bbit)) != 0;
}
-Size2 BitMap::get_size() const {
- return Size2(width, height);
+Size2i BitMap::get_size() const {
+ return Size2i(width, height);
}
void BitMap::_set_data(const Dictionary &p_d) {
@@ -160,22 +169,22 @@ Dictionary BitMap::_get_data() const {
return d;
}
-Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) const {
+Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_start) const {
int stepx = 0;
int stepy = 0;
int prevx = 0;
int prevy = 0;
- int startx = start.x;
- int starty = start.y;
+ int startx = p_start.x;
+ int starty = p_start.y;
int curx = startx;
int cury = starty;
unsigned int count = 0;
- RBSet<Point2i> case9s;
- RBSet<Point2i> case6s;
+ HashSet<Point2i> case9s;
+ HashSet<Point2i> case6s;
Vector<Vector2> _points;
do {
int sv = 0;
- { //square value
+ { // Square value
/*
checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
@@ -186,13 +195,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
+---+---+
*/
Point2i tl = Point2i(curx - 1, cury - 1);
- sv += (rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
+ sv += (p_rect.has_point(tl) && get_bitv(tl)) ? 1 : 0;
Point2i tr = Point2i(curx, cury - 1);
- sv += (rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
+ sv += (p_rect.has_point(tr) && get_bitv(tr)) ? 2 : 0;
Point2i bl = Point2i(curx - 1, cury);
- sv += (rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
+ sv += (p_rect.has_point(bl) && get_bitv(bl)) ? 4 : 0;
Point2i br = Point2i(curx, cury);
- sv += (rect.has_point(br) && get_bit(br)) ? 8 : 0;
+ sv += (p_rect.has_point(br) && get_bitv(br)) ? 8 : 0;
ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>());
}
@@ -302,16 +311,16 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
default:
ERR_PRINT("this shouldn't happen.");
}
- //little optimization
- // if previous direction is same as current direction,
- // then we should modify the last vec to current
+ // Small optimization:
+ // If the previous direction is same as the current direction,
+ // then we should modify the last vector to current.
curx += stepx;
cury += stepy;
if (stepx == prevx && stepy == prevy) {
- _points.write[_points.size() - 1].x = (float)(curx - rect.position.x);
- _points.write[_points.size() - 1].y = (float)(cury + rect.position.y);
+ _points.write[_points.size() - 1].x = (float)(curx - p_rect.position.x);
+ _points.write[_points.size() - 1].y = (float)(cury + p_rect.position.y);
} else {
- _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y)));
+ _points.push_back(Vector2((float)(curx - p_rect.position.x), (float)(cury + p_rect.position.y)));
}
count++;
@@ -347,7 +356,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
int index = -1;
float dist = 0.0;
- //not looping first and last point
+ // Not looping first and last point.
for (size_t i = 1, size = v.size(); i < size - 1; ++i) {
float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]);
if (cdist > dist) {
@@ -384,9 +393,9 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, float epsilon) {
int size = points.size();
- // if there are less than 3 points, then we have nothing
+ // If there are less than 3 points, then we have nothing.
ERR_FAIL_COND_V(size < 3, Vector<Vector2>());
- // if there are less than 9 points (but more than 3), then we don't need to reduce it
+ // If there are less than 9 points (but more than 3), then we don't need to reduce it.
if (size < 9) {
return points;
}
@@ -411,9 +420,9 @@ struct FillBitsStackEntry {
};
static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) {
- // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps
+ // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps.
Vector<FillBitsStackEntry> stack;
- // Tracking size since we won't be shrinking the stack vector
+ // Tracking size since we won't be shrinking the stack vector.
int stack_size = 0;
Point2i pos = p_pos;
@@ -432,10 +441,10 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
for (int i = next_i; i <= pos.x + 1; i++) {
for (int j = next_j; j <= pos.y + 1; j++) {
if (popped) {
- // The next loop over j must start normally
+ // The next loop over j must start normally.
next_j = pos.y;
popped = false;
- // Skip because an iteration was already executed with current counter values
+ // Skip because an iteration was already executed with current counter values.
continue;
}
@@ -446,11 +455,11 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
continue;
}
- if (p_map->get_bit(Vector2(i, j))) {
+ if (p_map->get_bit(i, j)) {
continue;
- } else if (p_src->get_bit(Vector2(i, j))) {
- p_map->set_bit(Vector2(i, j), true);
+ } else if (p_src->get_bit(i, j)) {
+ p_map->set_bit(i, j, true);
FillBitsStackEntry se = { pos, i, j };
stack.resize(MAX(stack_size + 1, stack.size()));
@@ -481,7 +490,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
print_verbose("BitMap: Max stack size: " + itos(stack.size()));
}
-Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
+Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon) const {
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect);
print_verbose("BitMap: Rect: " + r);
@@ -493,7 +502,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo
Vector<Vector<Vector2>> polygons;
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
- if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
+ if (!fill->get_bit(j, i) && get_bit(j, i)) {
fill_bits(this, fill, Point2i(j, i), r);
Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
@@ -514,7 +523,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo
return polygons;
}
-void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
+void BitMap::grow_mask(int p_pixels, const Rect2i &p_rect) {
if (p_pixels == 0) {
return;
}
@@ -531,7 +540,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
- if (bit_value == get_bit(Point2(j, i))) {
+ if (bit_value == get_bit(j, i)) {
continue;
}
@@ -542,7 +551,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
bool outside = false;
if ((x < p_rect.position.x) || (x >= p_rect.position.x + p_rect.size.x) || (y < p_rect.position.y) || (y >= p_rect.position.y + p_rect.size.y)) {
- // outside of rectangle counts as bit not set
+ // Outside of rectangle counts as bit not set.
if (!bit_value) {
outside = true;
} else {
@@ -555,7 +564,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
continue;
}
- if (outside || (bit_value == copy->get_bit(Point2(x, y)))) {
+ if (outside || (bit_value == copy->get_bit(x, y))) {
found = true;
break;
}
@@ -566,22 +575,22 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
}
if (found) {
- set_bit(Point2(j, i), bit_value);
+ set_bit(j, i, bit_value);
}
}
}
}
-void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) {
+void BitMap::shrink_mask(int p_pixels, const Rect2i &p_rect) {
grow_mask(-p_pixels, p_rect);
}
-Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
+TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2i &p_rect, float p_epsilon) const {
Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon);
- // Convert result to bindable types
+ // Convert result to bindable types.
- Array result_array;
+ TypedArray<PackedVector2Array> result_array;
result_array.resize(result.size());
for (int i = 0; i < result.size(); i++) {
const Vector<Vector2> &polygon = result[i];
@@ -602,15 +611,25 @@ Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) con
return result_array;
}
-void BitMap::resize(const Size2 &p_new_size) {
+void BitMap::resize(const Size2i &p_new_size) {
+ ERR_FAIL_COND(p_new_size.width < 0 || p_new_size.height < 0);
+ if (p_new_size == get_size()) {
+ return;
+ }
+
Ref<BitMap> new_bitmap;
new_bitmap.instantiate();
new_bitmap->create(p_new_size);
- int lw = MIN(width, p_new_size.width);
- int lh = MIN(height, p_new_size.height);
+ // also allow for upscaling
+ int lw = (width == 0) ? 0 : p_new_size.width;
+ int lh = (height == 0) ? 0 : p_new_size.height;
+
+ float scale_x = ((float)width / p_new_size.width);
+ float scale_y = ((float)height / p_new_size.height);
for (int x = 0; x < lw; x++) {
for (int y = 0; y < lh; y++) {
- new_bitmap->set_bit(Vector2(x, y), get_bit(Vector2(x, y)));
+ bool new_bit = get_bit(x * scale_x, y * scale_y);
+ new_bitmap->set_bit(x, y, new_bit);
}
}
@@ -626,14 +645,16 @@ Ref<Image> BitMap::convert_to_image() const {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
- image->set_pixel(i, j, get_bit(Point2(i, j)) ? Color(1, 1, 1) : Color(0, 0, 0));
+ image->set_pixel(i, j, get_bit(i, j) ? Color(1, 1, 1) : Color(0, 0, 0));
}
}
return image;
}
-void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) {
+void BitMap::blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap) {
+ ERR_FAIL_COND_MSG(p_bitmap.is_null(), "It's not a reference to a valid BitMap object.");
+
int x = p_pos.x;
int y = p_pos.y;
int w = p_bitmap->get_size().width;
@@ -649,8 +670,8 @@ void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) {
if (py < 0 || py >= height) {
continue;
}
- if (p_bitmap->get_bit(Vector2(i, j))) {
- set_bit(Vector2(x, y), true);
+ if (p_bitmap->get_bit(i, j)) {
+ set_bit(px, py, true);
}
}
}
@@ -660,8 +681,10 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1));
- ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit);
- ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit);
+ ClassDB::bind_method(D_METHOD("set_bitv", "position", "bit"), &BitMap::set_bitv);
+ ClassDB::bind_method(D_METHOD("set_bit", "x", "y", "bit"), &BitMap::set_bit);
+ ClassDB::bind_method(D_METHOD("get_bitv", "position"), &BitMap::get_bitv);
+ ClassDB::bind_method(D_METHOD("get_bit", "x", "y"), &BitMap::get_bit);
ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect);
ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count);
@@ -669,7 +692,7 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size);
ClassDB::bind_method(D_METHOD("resize", "new_size"), &BitMap::resize);
- ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &BitMap::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data);
ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask);
@@ -680,5 +703,3 @@ void BitMap::_bind_methods() {
}
BitMap::BitMap() {}
-
-//////////////////////////////////////
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index 0d0d779c32..291ed8c4d0 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -35,6 +35,9 @@
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
+template <typename T>
+class TypedArray;
+
class BitMap : public Resource {
GDCLASS(BitMap, Resource);
OBJ_SAVE_TYPE(BitMap);
@@ -43,9 +46,9 @@ class BitMap : public Resource {
int width = 0;
int height = 0;
- Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
+ Vector<Vector2> _march_square(const Rect2i &p_rect, const Point2i &p_start) const;
- Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const;
+ TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2i &p_rect, float p_epsilon) const;
protected:
void _set_data(const Dictionary &p_d);
@@ -54,24 +57,27 @@ protected:
static void _bind_methods();
public:
- void create(const Size2 &p_size);
+ void create(const Size2i &p_size);
void create_from_image_alpha(const Ref<Image> &p_image, float p_threshold = 0.1);
- void set_bit(const Point2 &p_pos, bool p_value);
- bool get_bit(const Point2 &p_pos) const;
- void set_bit_rect(const Rect2 &p_rect, bool p_value);
+ void set_bitv(const Point2i &p_pos, bool p_value);
+ void set_bit(int p_x, int p_y, bool p_value);
+ void set_bit_rect(const Rect2i &p_rect, bool p_value);
+ bool get_bitv(const Point2i &p_pos) const;
+ bool get_bit(int p_x, int p_y) const;
+
int get_true_bit_count() const;
- Size2 get_size() const;
- void resize(const Size2 &p_new_size);
+ Size2i get_size() const;
+ void resize(const Size2i &p_new_size);
- void grow_mask(int p_pixels, const Rect2 &p_rect);
- void shrink_mask(int p_pixels, const Rect2 &p_rect);
+ void grow_mask(int p_pixels, const Rect2i &p_rect);
+ void shrink_mask(int p_pixels, const Rect2i &p_rect);
- void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap);
+ void blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap);
Ref<Image> convert_to_image() const;
- Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
+ Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon = 2.0) const;
BitMap();
};
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
new file mode 100644
index 0000000000..dfaf82f36a
--- /dev/null
+++ b/scene/resources/bone_map.cpp
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* 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);
+}
+
+void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+ _set_skeleton_bone_name(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 {
+ if (property.name == "bonemap" || property.name == "profile") {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+}
+
+BoneMap::BoneMap() {
+ _validate_bone_map();
+}
+
+BoneMap::~BoneMap() {
+}
+
+//////////////////////////////////////
diff --git a/scene/resources/scene_replication_config.h b/scene/resources/bone_map.h
index b791be9414..a07a776e27 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,63 +28,41 @@
/* 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);
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ static void _bind_methods();
public:
- TypedArray<NodePath> get_properties() const;
-
- void add_property(const NodePath &p_path, int p_index = -1);
- void remove_property(const NodePath &p_path);
+ 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);
+ void _set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); // Avoid to emit signal for editor.
- 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.cpp b/scene/resources/box_shape_3d.cpp
index 1abbf366fd..aac334b4be 100644
--- a/scene/resources/box_shape_3d.cpp
+++ b/scene/resources/box_shape_3d.cpp
@@ -91,7 +91,7 @@ void BoxShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxShape3D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &BoxShape3D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
}
BoxShape3D::BoxShape3D() :
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/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
new file mode 100644
index 0000000000..3c322f32b6
--- /dev/null
+++ b/scene/resources/camera_attributes.cpp
@@ -0,0 +1,493 @@
+/*************************************************************************/
+/* camera_attributes.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 "camera_attributes.h"
+
+#include "core/config/project_settings.h"
+#include "servers/rendering_server.h"
+
+void CameraAttributes::set_exposure_multiplier(float p_multiplier) {
+ exposure_multiplier = p_multiplier;
+ _update_exposure();
+ emit_changed();
+}
+
+float CameraAttributes::get_exposure_multiplier() const {
+ return exposure_multiplier;
+}
+
+void CameraAttributes::set_exposure_sensitivity(float p_sensitivity) {
+ exposure_sensitivity = p_sensitivity;
+ _update_exposure();
+ emit_changed();
+}
+
+float CameraAttributes::get_exposure_sensitivity() const {
+ return exposure_sensitivity;
+}
+
+void CameraAttributes::_update_exposure() {
+ float exposure_normalization = 1.0;
+ // Ignore physical properties if not using physical light units.
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ exposure_normalization = calculate_exposure_normalization();
+ }
+
+ RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, exposure_multiplier, exposure_normalization);
+}
+
+void CameraAttributes::set_auto_exposure_enabled(bool p_enabled) {
+ auto_exposure_enabled = p_enabled;
+ _update_auto_exposure();
+ notify_property_list_changed();
+}
+
+bool CameraAttributes::is_auto_exposure_enabled() const {
+ return auto_exposure_enabled;
+}
+
+void CameraAttributes::set_auto_exposure_speed(float p_auto_exposure_speed) {
+ auto_exposure_speed = p_auto_exposure_speed;
+ _update_auto_exposure();
+}
+
+float CameraAttributes::get_auto_exposure_speed() const {
+ return auto_exposure_speed;
+}
+
+void CameraAttributes::set_auto_exposure_scale(float p_auto_exposure_scale) {
+ auto_exposure_scale = p_auto_exposure_scale;
+ _update_auto_exposure();
+}
+
+float CameraAttributes::get_auto_exposure_scale() const {
+ return auto_exposure_scale;
+}
+
+RID CameraAttributes::get_rid() const {
+ return camera_attributes;
+}
+
+void CameraAttributes::_validate_property(PropertyInfo &p_property) const {
+ if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && p_property.name == "exposure_sensitivity") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ return;
+ }
+
+ if (p_property.name.begins_with("auto_exposure_") && p_property.name != "auto_exposure_enabled" && !auto_exposure_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ return;
+ }
+}
+
+void CameraAttributes::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_exposure_multiplier", "multiplier"), &CameraAttributes::set_exposure_multiplier);
+ ClassDB::bind_method(D_METHOD("get_exposure_multiplier"), &CameraAttributes::get_exposure_multiplier);
+ ClassDB::bind_method(D_METHOD("set_exposure_sensitivity", "sensitivity"), &CameraAttributes::set_exposure_sensitivity);
+ ClassDB::bind_method(D_METHOD("get_exposure_sensitivity"), &CameraAttributes::get_exposure_sensitivity);
+
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_enabled", "enabled"), &CameraAttributes::set_auto_exposure_enabled);
+ ClassDB::bind_method(D_METHOD("is_auto_exposure_enabled"), &CameraAttributes::is_auto_exposure_enabled);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_speed", "exposure_speed"), &CameraAttributes::set_auto_exposure_speed);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_speed"), &CameraAttributes::get_auto_exposure_speed);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_scale", "exposure_grey"), &CameraAttributes::set_auto_exposure_scale);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_scale"), &CameraAttributes::get_auto_exposure_scale);
+
+ ADD_GROUP("Exposure", "exposure");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_sensitivity", PROPERTY_HINT_RANGE, "0.1,32000.0,0.1,suffix:ISO"), "set_exposure_sensitivity", "get_exposure_sensitivity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,2048.0,0.001"), "set_exposure_multiplier", "get_exposure_multiplier");
+
+ ADD_GROUP("Auto Exposure", "auto_exposure_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_auto_exposure_enabled", "is_auto_exposure_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_scale", "get_auto_exposure_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_speed", "get_auto_exposure_speed");
+}
+
+CameraAttributes::CameraAttributes() {
+ camera_attributes = RS::get_singleton()->camera_attributes_create();
+}
+
+CameraAttributes::~CameraAttributes() {
+ RS::get_singleton()->free(camera_attributes);
+}
+
+//////////////////////////////////////////////////////
+/* CameraAttributesPractical */
+
+void CameraAttributesPractical::set_dof_blur_far_enabled(bool p_enabled) {
+ dof_blur_far_enabled = p_enabled;
+ _update_dof_blur();
+ notify_property_list_changed();
+}
+
+bool CameraAttributesPractical::is_dof_blur_far_enabled() const {
+ return dof_blur_far_enabled;
+}
+
+void CameraAttributesPractical::set_dof_blur_far_distance(float p_distance) {
+ dof_blur_far_distance = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_far_distance() const {
+ return dof_blur_far_distance;
+}
+
+void CameraAttributesPractical::set_dof_blur_far_transition(float p_distance) {
+ dof_blur_far_transition = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_far_transition() const {
+ return dof_blur_far_transition;
+}
+
+void CameraAttributesPractical::set_dof_blur_near_enabled(bool p_enabled) {
+ dof_blur_near_enabled = p_enabled;
+ _update_dof_blur();
+ notify_property_list_changed();
+}
+
+bool CameraAttributesPractical::is_dof_blur_near_enabled() const {
+ return dof_blur_near_enabled;
+}
+
+void CameraAttributesPractical::set_dof_blur_near_distance(float p_distance) {
+ dof_blur_near_distance = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_near_distance() const {
+ return dof_blur_near_distance;
+}
+
+void CameraAttributesPractical::set_dof_blur_near_transition(float p_distance) {
+ dof_blur_near_transition = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_near_transition() const {
+ return dof_blur_near_transition;
+}
+
+void CameraAttributesPractical::set_dof_blur_amount(float p_amount) {
+ dof_blur_amount = p_amount;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_amount() const {
+ return dof_blur_amount;
+}
+
+void CameraAttributesPractical::_update_dof_blur() {
+ RS::get_singleton()->camera_attributes_set_dof_blur(
+ get_rid(),
+ dof_blur_far_enabled,
+ dof_blur_far_distance,
+ dof_blur_far_transition,
+ dof_blur_near_enabled,
+ dof_blur_near_distance,
+ dof_blur_near_transition,
+ dof_blur_amount);
+}
+
+float CameraAttributesPractical::calculate_exposure_normalization() const {
+ return exposure_sensitivity / 3072007.0; // Matches exposure normalization for default CameraAttributesPhysical at ISO 100.
+}
+
+void CameraAttributesPractical::set_auto_exposure_min_sensitivity(float p_min) {
+ auto_exposure_min = p_min;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPractical::get_auto_exposure_min_sensitivity() const {
+ return auto_exposure_min;
+}
+
+void CameraAttributesPractical::set_auto_exposure_max_sensitivity(float p_max) {
+ auto_exposure_max = p_max;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPractical::get_auto_exposure_max_sensitivity() const {
+ return auto_exposure_max;
+}
+
+void CameraAttributesPractical::_update_auto_exposure() {
+ RS::get_singleton()->camera_attributes_set_auto_exposure(
+ get_rid(),
+ auto_exposure_enabled,
+ auto_exposure_min * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance
+ auto_exposure_max * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance
+ auto_exposure_speed,
+ auto_exposure_scale);
+ emit_changed();
+}
+
+void CameraAttributesPractical::_validate_property(PropertyInfo &p_property) const {
+ if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) ||
+ (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition"))) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+}
+
+void CameraAttributesPractical::_bind_methods() {
+ // DOF blur
+
+ ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_far_enabled);
+ ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraAttributesPractical::is_dof_blur_far_enabled);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraAttributesPractical::set_dof_blur_far_distance);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraAttributesPractical::get_dof_blur_far_distance);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraAttributesPractical::set_dof_blur_far_transition);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraAttributesPractical::get_dof_blur_far_transition);
+
+ ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_near_enabled);
+ ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraAttributesPractical::is_dof_blur_near_enabled);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraAttributesPractical::set_dof_blur_near_distance);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraAttributesPractical::get_dof_blur_near_distance);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraAttributesPractical::set_dof_blur_near_transition);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraAttributesPractical::get_dof_blur_near_transition);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraAttributesPractical::set_dof_blur_amount);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraAttributesPractical::get_dof_blur_amount);
+
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_max_sensitivity", "max_sensitivity"), &CameraAttributesPractical::set_auto_exposure_max_sensitivity);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_max_sensitivity"), &CameraAttributesPractical::get_auto_exposure_max_sensitivity);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_min_sensitivity", "min_sensitivity"), &CameraAttributesPractical::set_auto_exposure_min_sensitivity);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_min_sensitivity"), &CameraAttributesPractical::get_auto_exposure_min_sensitivity);
+
+ ADD_GROUP("DOF Blur", "dof_blur_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
+
+ ADD_GROUP("Auto Exposure", "auto_exposure_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_sensitivity", PROPERTY_HINT_RANGE, "0,1600,0.01,or_greater,suffic:ISO"), "set_auto_exposure_min_sensitivity", "get_auto_exposure_min_sensitivity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_sensitivity", PROPERTY_HINT_RANGE, "0,64000,0.1,or_greater,suffic:ISO"), "set_auto_exposure_max_sensitivity", "get_auto_exposure_max_sensitivity");
+}
+
+CameraAttributesPractical::CameraAttributesPractical() {
+ _update_dof_blur();
+ _update_exposure();
+ set_auto_exposure_min_sensitivity(0.0);
+ set_auto_exposure_max_sensitivity(800.0);
+ notify_property_list_changed();
+}
+
+CameraAttributesPractical::~CameraAttributesPractical() {
+}
+
+//////////////////////////////////////////////////////
+/* CameraAttributesPhysical */
+
+void CameraAttributesPhysical::set_aperture(float p_aperture) {
+ exposure_aperture = p_aperture;
+ _update_exposure();
+ _update_frustum();
+}
+
+float CameraAttributesPhysical::get_aperture() const {
+ return exposure_aperture;
+}
+
+void CameraAttributesPhysical::set_shutter_speed(float p_shutter_speed) {
+ exposure_shutter_speed = p_shutter_speed;
+ _update_exposure();
+}
+
+float CameraAttributesPhysical::get_shutter_speed() const {
+ return exposure_shutter_speed;
+}
+
+void CameraAttributesPhysical::set_focal_length(float p_focal_length) {
+ frustum_focal_length = p_focal_length;
+ _update_frustum();
+ emit_changed();
+}
+
+float CameraAttributesPhysical::get_focal_length() const {
+ return frustum_focal_length;
+}
+
+void CameraAttributesPhysical::set_focus_distance(float p_focus_distance) {
+ frustum_focus_distance = p_focus_distance;
+ _update_frustum();
+}
+
+float CameraAttributesPhysical::get_focus_distance() const {
+ return frustum_focus_distance;
+}
+
+void CameraAttributesPhysical::set_near(real_t p_near) {
+ frustum_near = p_near;
+ _update_frustum();
+ emit_changed();
+}
+
+real_t CameraAttributesPhysical::get_near() const {
+ return frustum_near;
+}
+
+void CameraAttributesPhysical::set_far(real_t p_far) {
+ frustum_far = p_far;
+ _update_frustum();
+ emit_changed();
+}
+
+real_t CameraAttributesPhysical::get_far() const {
+ return frustum_far;
+}
+
+real_t CameraAttributesPhysical::get_fov() const {
+ return frustum_fov;
+}
+
+void CameraAttributesPhysical::_update_frustum() {
+ //https://en.wikipedia.org/wiki/Circle_of_confusion#Circle_of_confusion_diameter_limit_based_on_d/1500
+ Vector2i sensor_size = Vector2i(36, 24); // Matches high-end DSLR, could be made variable if there is demand.
+ float CoC = sensor_size.length() / 1500.0;
+
+ frustum_fov = Math::rad_to_deg(2 * atan(sensor_size.height / (2 * frustum_focal_length)));
+
+ // Based on https://en.wikipedia.org/wiki/Depth_of_field.
+ float u = MAX(frustum_focus_distance * 1000.0, frustum_focal_length + 1.0); // Focus distance expressed in mm and clamped to at least 1 mm away from lens.
+ float hyperfocal_length = frustum_focal_length + ((frustum_focal_length * frustum_focal_length) / (exposure_aperture * CoC));
+
+ // This computes the start and end of the depth of field. Anything between these two points has a Circle of Confusino so small
+ // that it is not picked up by the camera sensors.
+ // To be properly physically-based, we would run the DoF shader at all depths. To be efficient, we are only running it where the CoC
+ // will be visible, this introduces some value shifts in the near field that we have to compensate for below.
+ float near = ((hyperfocal_length * u) / (hyperfocal_length + (u - frustum_focal_length))) / 1000.0; // In meters.
+ float far = ((hyperfocal_length * u) / (hyperfocal_length - (u - frustum_focal_length))) / 1000.0; // In meters.
+ float scale = (frustum_focal_length / (u - frustum_focal_length)) * (frustum_focal_length / exposure_aperture);
+
+ bool use_far = (far < frustum_far) && (far > 0.0);
+ bool use_near = near > frustum_near;
+ RS::get_singleton()->camera_attributes_set_dof_blur(
+ get_rid(),
+ use_far,
+ u / 1000.0, // Focus distance clampd to focal length expressed in meters.
+ -1.0, // Negative to tell Bokeh effect to use physically-based scaling.
+ use_near,
+ u / 1000.0,
+ -1.0,
+ scale / 5.0); // Arbitrary scaling to get close to how much blur there should be.
+}
+
+float CameraAttributesPhysical::calculate_exposure_normalization() const {
+ const float e = (exposure_aperture * exposure_aperture) * exposure_shutter_speed * (100.0 / exposure_sensitivity);
+ return 1.0 / (e * 1.2);
+}
+
+void CameraAttributesPhysical::set_auto_exposure_min_exposure_value(float p_min) {
+ auto_exposure_min = p_min;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPhysical::get_auto_exposure_min_exposure_value() const {
+ return auto_exposure_min;
+}
+
+void CameraAttributesPhysical::set_auto_exposure_max_exposure_value(float p_max) {
+ auto_exposure_max = p_max;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPhysical::get_auto_exposure_max_exposure_value() const {
+ return auto_exposure_max;
+}
+
+void CameraAttributesPhysical::_update_auto_exposure() {
+ RS::get_singleton()->camera_attributes_set_auto_exposure(
+ get_rid(),
+ auto_exposure_enabled,
+ pow(2.0, auto_exposure_min) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance
+ pow(2.0, auto_exposure_max) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance
+ auto_exposure_speed,
+ auto_exposure_scale);
+ emit_changed();
+}
+
+void CameraAttributesPhysical::_validate_property(PropertyInfo &property) const {
+ if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (property.name == "exposure_aperture" || property.name == "exposure_shutter_speed")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ return;
+ }
+}
+
+void CameraAttributesPhysical::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_aperture", "aperture"), &CameraAttributesPhysical::set_aperture);
+ ClassDB::bind_method(D_METHOD("get_aperture"), &CameraAttributesPhysical::get_aperture);
+ ClassDB::bind_method(D_METHOD("set_shutter_speed", "shutter_speed"), &CameraAttributesPhysical::set_shutter_speed);
+ ClassDB::bind_method(D_METHOD("get_shutter_speed"), &CameraAttributesPhysical::get_shutter_speed);
+
+ ClassDB::bind_method(D_METHOD("set_focal_length", "focal_length"), &CameraAttributesPhysical::set_focal_length);
+ ClassDB::bind_method(D_METHOD("get_focal_length"), &CameraAttributesPhysical::get_focal_length);
+ ClassDB::bind_method(D_METHOD("set_focus_distance", "focus_distance"), &CameraAttributesPhysical::set_focus_distance);
+ ClassDB::bind_method(D_METHOD("get_focus_distance"), &CameraAttributesPhysical::get_focus_distance);
+ ClassDB::bind_method(D_METHOD("set_near", "near"), &CameraAttributesPhysical::set_near);
+ ClassDB::bind_method(D_METHOD("get_near"), &CameraAttributesPhysical::get_near);
+ ClassDB::bind_method(D_METHOD("set_far", "far"), &CameraAttributesPhysical::set_far);
+ ClassDB::bind_method(D_METHOD("get_far"), &CameraAttributesPhysical::get_far);
+ ClassDB::bind_method(D_METHOD("get_fov"), &CameraAttributesPhysical::get_fov);
+
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_max_exposure_value", "exposure_value_max"), &CameraAttributesPhysical::set_auto_exposure_max_exposure_value);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_max_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_max_exposure_value);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_min_exposure_value", "exposure_value_min"), &CameraAttributesPhysical::set_auto_exposure_min_exposure_value);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_min_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_min_exposure_value);
+
+ ADD_GROUP("Frustum", "frustum_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focus_distance", PROPERTY_HINT_RANGE, "0.01,4000.0,0.01,suffix:m"), "set_focus_distance", "get_focus_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focal_length", PROPERTY_HINT_RANGE, "1.0,800.0,0.01,exp,suffix:mm"), "set_focal_length", "get_focal_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far");
+
+ ADD_GROUP("Exposure", "exposure");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_aperture", PROPERTY_HINT_RANGE, "0.5,64.0,0.01,exp,suffix:f-stop"), "set_aperture", "get_aperture");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_shutter_speed", PROPERTY_HINT_RANGE, "0.1,8000.0,0.001,suffix:1/s"), "set_shutter_speed", "get_shutter_speed");
+
+ ADD_GROUP("Auto Exposure", "auto_exposure_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_min_exposure_value", "get_auto_exposure_min_exposure_value");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_max_exposure_value", "get_auto_exposure_max_exposure_value");
+};
+
+CameraAttributesPhysical::CameraAttributesPhysical() {
+ _update_exposure();
+ _update_frustum();
+ set_auto_exposure_min_exposure_value(-8);
+ set_auto_exposure_max_exposure_value(10); // Use a wide range by default to feel more like a real camera.
+ notify_property_list_changed();
+}
+
+CameraAttributesPhysical::~CameraAttributesPhysical() {
+}
diff --git a/scene/resources/camera_attributes.h b/scene/resources/camera_attributes.h
new file mode 100644
index 0000000000..c4c783af29
--- /dev/null
+++ b/scene/resources/camera_attributes.h
@@ -0,0 +1,183 @@
+/*************************************************************************/
+/* camera_attributes.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 CAMERA_ATTRIBUTES_H
+#define CAMERA_ATTRIBUTES_H
+
+#include "core/io/resource.h"
+#include "core/templates/rid.h"
+
+class CameraAttributes : public Resource {
+ GDCLASS(CameraAttributes, Resource);
+
+private:
+ RID camera_attributes;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+ float exposure_multiplier = 1.0;
+ float exposure_sensitivity = 100.0; // In ISO.
+ void _update_exposure();
+
+ bool auto_exposure_enabled = false;
+ float auto_exposure_min = 0.01;
+ float auto_exposure_max = 64.0;
+ float auto_exposure_speed = 0.5;
+ float auto_exposure_scale = 0.4;
+ virtual void _update_auto_exposure(){};
+
+public:
+ virtual RID get_rid() const override;
+ virtual float calculate_exposure_normalization() const { return 1.0; }
+
+ void set_exposure_multiplier(float p_multiplier);
+ float get_exposure_multiplier() const;
+ void set_exposure_sensitivity(float p_sensitivity);
+ float get_exposure_sensitivity() const;
+
+ void set_auto_exposure_enabled(bool p_enabled);
+ bool is_auto_exposure_enabled() const;
+ void set_auto_exposure_speed(float p_auto_exposure_speed);
+ float get_auto_exposure_speed() const;
+ void set_auto_exposure_scale(float p_auto_exposure_scale);
+ float get_auto_exposure_scale() const;
+
+ CameraAttributes();
+ ~CameraAttributes();
+};
+
+class CameraAttributesPractical : public CameraAttributes {
+ GDCLASS(CameraAttributesPractical, CameraAttributes);
+
+private:
+ // DOF blur
+ bool dof_blur_far_enabled = false;
+ float dof_blur_far_distance = 10.0;
+ float dof_blur_far_transition = 5.0;
+
+ bool dof_blur_near_enabled = false;
+ float dof_blur_near_distance = 2.0;
+ float dof_blur_near_transition = 1.0;
+
+ float dof_blur_amount = 0.1;
+ void _update_dof_blur();
+
+ virtual void _update_auto_exposure() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ // DOF blur
+ void set_dof_blur_far_enabled(bool p_enabled);
+ bool is_dof_blur_far_enabled() const;
+ void set_dof_blur_far_distance(float p_distance);
+ float get_dof_blur_far_distance() const;
+ void set_dof_blur_far_transition(float p_distance);
+ float get_dof_blur_far_transition() const;
+
+ void set_dof_blur_near_enabled(bool p_enabled);
+ bool is_dof_blur_near_enabled() const;
+ void set_dof_blur_near_distance(float p_distance);
+ float get_dof_blur_near_distance() const;
+ void set_dof_blur_near_transition(float p_distance);
+ float get_dof_blur_near_transition() const;
+ void set_dof_blur_amount(float p_amount);
+ float get_dof_blur_amount() const;
+
+ void set_auto_exposure_min_sensitivity(float p_min);
+ float get_auto_exposure_min_sensitivity() const;
+ void set_auto_exposure_max_sensitivity(float p_max);
+ float get_auto_exposure_max_sensitivity() const;
+
+ virtual float calculate_exposure_normalization() const override;
+
+ CameraAttributesPractical();
+ ~CameraAttributesPractical();
+};
+
+class CameraAttributesPhysical : public CameraAttributes {
+ GDCLASS(CameraAttributesPhysical, CameraAttributes);
+
+private:
+ // Exposure
+ float exposure_aperture = 16.0; // In f-stops;
+ float exposure_shutter_speed = 100.0; // In 1 / seconds;
+
+ // Camera properties.
+ float frustum_focal_length = 35.0; // In millimeters.
+ float frustum_focus_distance = 10.0; // In Meters.
+ real_t frustum_near = 0.05;
+ real_t frustum_far = 4000.0;
+ real_t frustum_fov = 75.0;
+ void _update_frustum();
+
+ virtual void _update_auto_exposure() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_aperture(float p_aperture);
+ float get_aperture() const;
+
+ void set_shutter_speed(float p_shutter_speed);
+ float get_shutter_speed() const;
+
+ void set_focal_length(float p_focal_length);
+ float get_focal_length() const;
+
+ void set_focus_distance(float p_focus_distance);
+ float get_focus_distance() const;
+
+ void set_near(real_t p_near);
+ real_t get_near() const;
+
+ void set_far(real_t p_far);
+ real_t get_far() const;
+
+ real_t get_fov() const;
+
+ void set_auto_exposure_min_exposure_value(float p_min);
+ float get_auto_exposure_min_exposure_value() const;
+ void set_auto_exposure_max_exposure_value(float p_max);
+ float get_auto_exposure_max_exposure_value() const;
+
+ virtual float calculate_exposure_normalization() const override;
+
+ CameraAttributesPhysical();
+ ~CameraAttributesPhysical();
+};
+
+#endif // CAMERA_ATTRIBUTES_H
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp
deleted file mode 100644
index ebe2aa4dba..0000000000
--- a/scene/resources/camera_effects.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*************************************************************************/
-/* camera_effects.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 "camera_effects.h"
-
-#include "servers/rendering_server.h"
-
-RID CameraEffects::get_rid() const {
- return camera_effects;
-}
-
-// DOF blur
-
-void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) {
- dof_blur_far_enabled = p_enabled;
- _update_dof_blur();
- notify_property_list_changed();
-}
-
-bool CameraEffects::is_dof_blur_far_enabled() const {
- return dof_blur_far_enabled;
-}
-
-void CameraEffects::set_dof_blur_far_distance(float p_distance) {
- dof_blur_far_distance = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_far_distance() const {
- return dof_blur_far_distance;
-}
-
-void CameraEffects::set_dof_blur_far_transition(float p_distance) {
- dof_blur_far_transition = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_far_transition() const {
- return dof_blur_far_transition;
-}
-
-void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) {
- dof_blur_near_enabled = p_enabled;
- _update_dof_blur();
- notify_property_list_changed();
-}
-
-bool CameraEffects::is_dof_blur_near_enabled() const {
- return dof_blur_near_enabled;
-}
-
-void CameraEffects::set_dof_blur_near_distance(float p_distance) {
- dof_blur_near_distance = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_near_distance() const {
- return dof_blur_near_distance;
-}
-
-void CameraEffects::set_dof_blur_near_transition(float p_distance) {
- dof_blur_near_transition = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_near_transition() const {
- return dof_blur_near_transition;
-}
-
-void CameraEffects::set_dof_blur_amount(float p_amount) {
- dof_blur_amount = p_amount;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_amount() const {
- return dof_blur_amount;
-}
-
-void CameraEffects::_update_dof_blur() {
- RS::get_singleton()->camera_effects_set_dof_blur(
- camera_effects,
- dof_blur_far_enabled,
- dof_blur_far_distance,
- dof_blur_far_transition,
- dof_blur_near_enabled,
- dof_blur_near_distance,
- dof_blur_near_transition,
- dof_blur_amount);
-}
-
-// Custom exposure
-
-void CameraEffects::set_override_exposure_enabled(bool p_enabled) {
- override_exposure_enabled = p_enabled;
- _update_override_exposure();
- notify_property_list_changed();
-}
-
-bool CameraEffects::is_override_exposure_enabled() const {
- return override_exposure_enabled;
-}
-
-void CameraEffects::set_override_exposure(float p_exposure) {
- override_exposure = p_exposure;
- _update_override_exposure();
-}
-
-float CameraEffects::get_override_exposure() const {
- return override_exposure;
-}
-
-void CameraEffects::_update_override_exposure() {
- RS::get_singleton()->camera_effects_set_custom_exposure(
- camera_effects,
- override_exposure_enabled,
- override_exposure);
-}
-
-// Private methods, constructor and destructor
-
-void CameraEffects::_validate_property(PropertyInfo &property) const {
- if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) ||
- (!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) ||
- (!override_exposure_enabled && property.name == "override_exposure")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
- }
-}
-
-void CameraEffects::_bind_methods() {
- // DOF blur
-
- ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraEffects::set_dof_blur_far_enabled);
- ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraEffects::is_dof_blur_far_enabled);
- ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraEffects::set_dof_blur_far_distance);
- ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraEffects::get_dof_blur_far_distance);
- ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraEffects::set_dof_blur_far_transition);
- ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraEffects::get_dof_blur_far_transition);
-
- ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraEffects::set_dof_blur_near_enabled);
- ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraEffects::is_dof_blur_near_enabled);
- ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraEffects::set_dof_blur_near_distance);
- ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraEffects::get_dof_blur_near_distance);
- ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraEffects::set_dof_blur_near_transition);
- ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraEffects::get_dof_blur_near_transition);
-
- ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraEffects::set_dof_blur_amount);
- ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount);
-
- ADD_GROUP("DOF Blur", "dof_blur_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
-
- // Override exposure
-
- ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enabled"), &CameraEffects::set_override_exposure_enabled);
- ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled);
- ClassDB::bind_method(D_METHOD("set_override_exposure", "exposure"), &CameraEffects::set_override_exposure);
- ClassDB::bind_method(D_METHOD("get_override_exposure"), &CameraEffects::get_override_exposure);
-
- ADD_GROUP("Override Exposure", "override_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enabled"), "set_override_exposure_enabled", "is_override_exposure_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure");
-}
-
-CameraEffects::CameraEffects() {
- camera_effects = RS::get_singleton()->camera_effects_create();
-
- _update_dof_blur();
- _update_override_exposure();
-}
-
-CameraEffects::~CameraEffects() {
- RS::get_singleton()->free(camera_effects);
-}
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index aa6cc4aded..b16059c218 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -227,9 +227,9 @@ bool CanvasItemMaterial::get_particles_anim_loop() const {
return particles_anim_loop;
}
-void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("particles_anim_") && !particles_animation) {
- property.usage = PROPERTY_USAGE_NONE;
+void CanvasItemMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("particles_anim_") && !particles_animation) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index 7c44c125a8..7eaf5051d4 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -64,7 +64,7 @@ private:
uint32_t key = 0;
static uint32_t hash(const MaterialKey &p_key) {
- return hash_djb2_one_32(p_key.key);
+ return hash_murmur3_one_32(p_key.key);
}
bool operator==(const MaterialKey &p_key) const {
return key == p_key.key;
@@ -117,7 +117,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_blend_mode(BlendMode p_blend_mode);
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index c7bd4cb698..eb27ffaf35 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -109,8 +109,8 @@ void CapsuleShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape2D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape2D::get_height);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_height", "get_height");
ADD_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
}
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index d708706ff2..b0454004a0 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -40,8 +40,8 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
Vector3 d(0, height * 0.5 - radius, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
@@ -113,8 +113,8 @@ void CapsuleShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape3D::get_height);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
}
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/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index c287de9ede..ff60162180 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -56,7 +56,7 @@ void CircleShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CircleShape2D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CircleShape2D::get_radius);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_radius", "get_radius");
}
Rect2 CircleShape2D::get_rect() const {
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.cpp b/scene/resources/concave_polygon_shape_3d.cpp
index ab2c1da327..b91f0e4f1c 100644
--- a/scene/resources/concave_polygon_shape_3d.cpp
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -33,7 +33,7 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
- RBSet<DrawEdge> edges;
+ HashSet<DrawEdge, DrawEdge> edges;
int index_count = faces.size();
ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>());
@@ -50,9 +50,9 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points;
points.resize(edges.size() * 2);
int idx = 0;
- for (RBSet<DrawEdge>::Element *E = edges.front(); E; E = E->next()) {
- points.write[idx + 0] = E->get().a;
- points.write[idx + 1] = E->get().b;
+ for (const DrawEdge &E : edges) {
+ points.write[idx + 0] = E.a;
+ points.write[idx + 1] = E.b;
idx += 2;
}
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index 5337deb5fb..68feacfa25 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -42,12 +42,12 @@ class ConcavePolygonShape3D : public Shape3D {
struct DrawEdge {
Vector3 a;
Vector3 b;
- bool operator<(const DrawEdge &p_edge) const {
- if (a == p_edge.a) {
- return b < p_edge.b;
- } else {
- return a < p_edge.a;
- }
+ static uint32_t hash(const DrawEdge &p_edge) {
+ uint32_t h = hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.a));
+ return hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.b), h);
+ }
+ bool operator==(const DrawEdge &p_edge) const {
+ return (a == p_edge.a && b == p_edge.b);
}
DrawEdge(const Vector3 &p_a = Vector3(), const Vector3 &p_b = Vector3()) {
@@ -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/curve.cpp b/scene/resources/curve.cpp
index 34cbd3a360..0ea5264935 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -32,24 +32,25 @@
#include "core/core_string_names.h"
-template <class T>
-static _FORCE_INLINE_ T _bezier_interp(real_t p_t, T p_start, T p_control_1, T p_control_2, T p_end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - p_t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = p_t * p_t;
- real_t t3 = t2 * p_t;
-
- return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
-}
-
const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
Curve::Curve() {
}
-int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
+void Curve::set_point_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ if (_points.size() >= p_count) {
+ _points.resize(p_count);
+ mark_dirty();
+ } else {
+ for (int i = p_count - _points.size(); i > 0; i--) {
+ _add_point(Vector2());
+ }
+ }
+ notify_property_list_changed();
+}
+
+int Curve::_add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
// Add a point and preserve order
// Curve bounds is in 0..1
@@ -100,6 +101,13 @@ int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_t
return ret;
}
+int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
+ int ret = _add_point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode);
+ notify_property_list_changed();
+
+ return ret;
+}
+
int Curve::get_index(real_t p_offset) const {
// Lower-bound float binary search
@@ -205,15 +213,21 @@ Curve::TangentMode Curve::get_point_right_mode(int p_index) const {
return _points[p_index].right_mode;
}
-void Curve::remove_point(int p_index) {
+void Curve::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, _points.size());
_points.remove_at(p_index);
mark_dirty();
}
+void Curve::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
+}
+
void Curve::clear_points() {
_points.clear();
mark_dirty();
+ notify_property_list_changed();
}
void Curve::set_point_value(int p_index, real_t p_position) {
@@ -226,8 +240,8 @@ void Curve::set_point_value(int p_index, real_t p_position) {
int Curve::set_point_offset(int p_index, real_t p_offset) {
ERR_FAIL_INDEX_V(p_index, _points.size(), -1);
Point p = _points[p_index];
- remove_point(p_index);
- int i = add_point(Vector2(p_offset, p.position.y));
+ _remove_point(p_index);
+ int i = _add_point(Vector2(p_offset, p.position.y));
_points.write[i].left_tangent = p.left_tangent;
_points.write[i].right_tangent = p.right_tangent;
_points.write[i].left_mode = p.left_mode;
@@ -299,7 +313,7 @@ void Curve::set_max_value(real_t p_max) {
emit_signal(SNAME(SIGNAL_RANGE_CHANGED));
}
-real_t Curve::interpolate(real_t p_offset) const {
+real_t Curve::sample(real_t p_offset) const {
if (_points.size() == 0) {
return 0;
}
@@ -319,10 +333,10 @@ real_t Curve::interpolate(real_t p_offset) const {
return _points[0].position.y;
}
- return interpolate_local_nocheck(i, local);
+ return sample_local_nocheck(i, local);
}
-real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) const {
+real_t Curve::sample_local_nocheck(int p_index, real_t p_local_offset) const {
const Point a = _points[p_index];
const Point b = _points[p_index + 1];
@@ -350,7 +364,7 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
real_t yac = a.position.y + d * a.right_tangent;
real_t ybc = b.position.y - d * b.left_tangent;
- real_t y = _bezier_interp(p_local_offset, a.position.y, yac, ybc, b.position.y);
+ real_t y = Math::bezier_interpolate(a.position.y, yac, ybc, b.position.y, p_local_offset);
return y;
}
@@ -409,7 +423,6 @@ void Curve::set_data(const Array p_input) {
p.position = p_input[i];
p.left_tangent = p_input[i + 1];
p.right_tangent = p_input[i + 2];
- // TODO For some reason the compiler won't convert from Variant to enum
int left_mode = p_input[i + 3];
int right_mode = p_input[i + 4];
p.left_mode = (TangentMode)left_mode;
@@ -417,6 +430,7 @@ void Curve::set_data(const Array p_input) {
}
mark_dirty();
+ notify_property_list_changed();
}
void Curve::bake() {
@@ -426,7 +440,7 @@ void Curve::bake() {
for (int i = 1; i < _bake_resolution - 1; ++i) {
real_t x = i / static_cast<real_t>(_bake_resolution);
- real_t y = interpolate(x);
+ real_t y = sample(x);
_baked_cache.write[i] = y;
}
@@ -445,7 +459,7 @@ void Curve::set_bake_resolution(int p_resolution) {
_baked_cache_dirty = true;
}
-real_t Curve::interpolate_baked(real_t p_offset) const {
+real_t Curve::sample_baked(real_t p_offset) const {
if (_baked_cache_dirty) {
// Last-second bake if not done already
const_cast<Curve *>(this)->bake();
@@ -472,7 +486,7 @@ real_t Curve::interpolate_baked(real_t p_offset) const {
fi = 0;
}
- // Interpolate
+ // Sample
if (i + 1 < _baked_cache.size()) {
real_t t = fi - i;
return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t);
@@ -490,16 +504,99 @@ void Curve::ensure_default_setup(real_t p_min, real_t p_max) {
}
}
+bool Curve::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ Vector2 position = p_value.operator Vector2();
+ set_point_offset(point_index, position.x);
+ set_point_value(point_index, position.y);
+ return true;
+ } else if (property == "left_tangent") {
+ set_point_left_tangent(point_index, p_value);
+ return true;
+ } else if (property == "left_mode") {
+ int mode = p_value;
+ set_point_left_mode(point_index, (TangentMode)mode);
+ return true;
+ } else if (property == "right_tangent") {
+ set_point_right_tangent(point_index, p_value);
+ return true;
+ } else if (property == "right_mode") {
+ int mode = p_value;
+ set_point_right_mode(point_index, (TangentMode)mode);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Curve::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ r_ret = get_point_position(point_index);
+ return true;
+ } else if (property == "left_tangent") {
+ r_ret = get_point_left_tangent(point_index);
+ return true;
+ } else if (property == "left_mode") {
+ r_ret = get_point_left_mode(point_index);
+ return true;
+ } else if (property == "right_tangent") {
+ r_ret = get_point_right_tangent(point_index);
+ return true;
+ } else if (property == "right_mode") {
+ r_ret = get_point_right_mode(point_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Curve::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < _points.size(); i++) {
+ PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ if (i != 0) {
+ pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/left_tangent", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::INT, vformat("point_%d/left_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ if (i != _points.size() - 1) {
+ pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/right_tangent", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::INT, vformat("point_%d/right_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+ }
+}
+
void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve::get_point_count);
+ ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "left_tangent", "right_tangent", "left_mode", "right_mode"), &Curve::add_point, DEFVAL(0), DEFVAL(0), DEFVAL(TANGENT_FREE), DEFVAL(TANGENT_FREE));
ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points);
ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Curve::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value);
ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_offset);
- ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate);
- ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked);
+ ClassDB::bind_method(D_METHOD("sample", "offset"), &Curve::sample);
+ ClassDB::bind_method(D_METHOD("sample_baked", "offset"), &Curve::sample_baked);
ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent);
ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_right_tangent);
ClassDB::bind_method(D_METHOD("get_point_left_mode", "index"), &Curve::get_point_left_mode);
@@ -523,6 +620,7 @@ void Curve::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_max_value", "get_max_value");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+ ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED));
@@ -535,7 +633,20 @@ int Curve2D::get_point_count() const {
return points.size();
}
-void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
+void Curve2D::set_point_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ if (points.size() >= p_count) {
+ points.resize(p_count);
+ mark_dirty();
+ } else {
+ for (int i = p_count - points.size(); i > 0; i--) {
+ _add_point(Vector2());
+ }
+ }
+ notify_property_list_changed();
+}
+
+void Curve2D::_add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
Point n;
n.position = p_position;
n.in = p_in;
@@ -546,16 +657,19 @@ void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Ve
points.push_back(n);
}
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
+ _add_point(p_position, p_in, p_out, p_atpos);
+ notify_property_list_changed();
}
void Curve2D::set_point_position(int p_index, const Vector2 &p_position) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].position = p_position;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector2 Curve2D::get_point_position(int p_index) const {
@@ -567,8 +681,7 @@ void Curve2D::set_point_in(int p_index, const Vector2 &p_in) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].in = p_in;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector2 Curve2D::get_point_in(int p_index) const {
@@ -580,8 +693,7 @@ void Curve2D::set_point_out(int p_index, const Vector2 &p_out) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].out = p_out;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector2 Curve2D::get_point_out(int p_index) const {
@@ -589,22 +701,26 @@ Vector2 Curve2D::get_point_out(int p_index) const {
return points[p_index].out;
}
-void Curve2D::remove_point(int p_index) {
+void Curve2D::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
points.remove_at(p_index);
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve2D::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
}
void Curve2D::clear_points() {
if (!points.is_empty()) {
points.clear();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+ notify_property_list_changed();
}
}
-Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
+Vector2 Curve2D::sample(int p_index, const real_t p_offset) const {
int pc = points.size();
ERR_FAIL_COND_V(pc == 0, Vector2());
@@ -619,30 +735,35 @@ Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
Vector2 p3 = points[p_index + 1].position;
Vector2 p2 = p3 + points[p_index + 1].in;
- return _bezier_interp(p_offset, p0, p1, p2, p3);
+ return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
-Vector2 Curve2D::interpolatef(real_t p_findex) const {
+Vector2 Curve2D::samplef(real_t p_findex) const {
if (p_findex < 0) {
p_findex = 0;
} else if (p_findex >= points.size()) {
p_findex = points.size();
}
- return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
+ return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
}
-void Curve2D::_bake_segment2d(HashMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
+void Curve2D::mark_dirty() {
+ baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
real_t mp = p_begin + (p_end - p_begin) * 0.5;
- Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+ Vector2 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector2 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ Vector2 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
Vector2 na = (mid - beg).normalized();
Vector2 nb = (end - mid).normalized();
real_t dp = na.dot(nb);
- if (dp < Math::cos(Math::deg2rad(p_tol))) {
+ if (dp < Math::cos(Math::deg_to_rad(p_tol))) {
r_bake[mp] = mid;
}
@@ -695,7 +816,7 @@ void Curve2D::_bake() const {
np = 1.0;
}
- Vector2 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ Vector2 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
real_t d = position.distance_to(npp);
if (d > bake_interval) {
@@ -708,7 +829,7 @@ void Curve2D::_bake() const {
real_t mid = low + (hi - low) * 0.5;
for (int j = 0; j < iterations; j++) {
- npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
d = position.distance_to(npp);
if (bake_interval < d) {
@@ -762,7 +883,7 @@ real_t Curve2D::get_baked_length() const {
return baked_max_ofs;
}
-Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
+Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
if (baked_cache_dirty) {
_bake();
}
@@ -802,7 +923,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
@@ -825,8 +946,7 @@ PackedVector2Array Curve2D::get_baked_points() const {
void Curve2D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
real_t Curve2D::get_bake_interval() const {
@@ -945,7 +1065,8 @@ void Curve2D::_set_data(const Dictionary &p_data) {
points.write[i].position = r[i * 3 + 2];
}
- baked_cache_dirty = true;
+ mark_dirty();
+ notify_property_list_changed();
}
PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) const {
@@ -954,7 +1075,9 @@ PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) con
if (points.size() == 0) {
return tess;
}
- Vector<HashMap<real_t, Vector2>> midpoints;
+
+ // The current implementation requires a sorted map.
+ Vector<RBMap<real_t, Vector2>> midpoints;
midpoints.resize(points.size() - 1);
@@ -983,9 +1106,68 @@ PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
+bool Curve2D::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ set_point_position(point_index, p_value);
+ return true;
+ } else if (property == "in") {
+ set_point_in(point_index, p_value);
+ return true;
+ } else if (property == "out") {
+ set_point_out(point_index, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Curve2D::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ r_ret = get_point_position(point_index);
+ return true;
+ } else if (property == "in") {
+ r_ret = get_point_in(point_index);
+ return true;
+ } else if (property == "out") {
+ r_ret = get_point_out(point_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Curve2D::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < points.size(); i++) {
+ PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ if (i != 0) {
+ pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/in", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ if (i != points.size() - 1) {
+ pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/out", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+ }
+}
+
void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve2D::set_point_count);
+ ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_in", "idx", "position"), &Curve2D::set_point_in);
@@ -994,24 +1176,25 @@ void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve2D::get_point_out);
ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve2D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve2D::clear_points);
- ClassDB::bind_method(D_METHOD("interpolate", "idx", "t"), &Curve2D::interpolate);
- ClassDB::bind_method(D_METHOD("interpolatef", "fofs"), &Curve2D::interpolatef);
+ ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve2D::sample);
+ ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve2D::samplef);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve2D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve2D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve2D::get_bake_interval);
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length);
- ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve2D::interpolate_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve2D::sample_baked, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point);
ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset);
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve2D::tessellate, DEFVAL(5), DEFVAL(4));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve2D::_get_data);
- ClassDB::bind_method(D_METHOD("_set_data"), &Curve2D::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve2D::_set_data);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+ ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
}
Curve2D::Curve2D() {}
@@ -1027,7 +1210,20 @@ int Curve3D::get_point_count() const {
return points.size();
}
-void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
+void Curve3D::set_point_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ if (points.size() >= p_count) {
+ points.resize(p_count);
+ mark_dirty();
+ } else {
+ for (int i = p_count - points.size(); i > 0; i--) {
+ _add_point(Vector3());
+ }
+ }
+ notify_property_list_changed();
+}
+
+void Curve3D::_add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
Point n;
n.position = p_position;
n.in = p_in;
@@ -1038,16 +1234,19 @@ void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Ve
points.push_back(n);
}
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
+ _add_point(p_position, p_in, p_out, p_atpos);
+ notify_property_list_changed();
}
void Curve3D::set_point_position(int p_index, const Vector3 &p_position) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].position = p_position;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector3 Curve3D::get_point_position(int p_index) const {
@@ -1059,8 +1258,7 @@ void Curve3D::set_point_tilt(int p_index, real_t p_tilt) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].tilt = p_tilt;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
real_t Curve3D::get_point_tilt(int p_index) const {
@@ -1072,8 +1270,7 @@ void Curve3D::set_point_in(int p_index, const Vector3 &p_in) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].in = p_in;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector3 Curve3D::get_point_in(int p_index) const {
@@ -1085,8 +1282,7 @@ void Curve3D::set_point_out(int p_index, const Vector3 &p_out) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].out = p_out;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector3 Curve3D::get_point_out(int p_index) const {
@@ -1094,22 +1290,26 @@ Vector3 Curve3D::get_point_out(int p_index) const {
return points[p_index].out;
}
-void Curve3D::remove_point(int p_index) {
+void Curve3D::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
points.remove_at(p_index);
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve3D::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
}
void Curve3D::clear_points() {
if (!points.is_empty()) {
points.clear();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+ notify_property_list_changed();
}
}
-Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
+Vector3 Curve3D::sample(int p_index, real_t p_offset) const {
int pc = points.size();
ERR_FAIL_COND_V(pc == 0, Vector3());
@@ -1124,30 +1324,35 @@ Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
Vector3 p3 = points[p_index + 1].position;
Vector3 p2 = p3 + points[p_index + 1].in;
- return _bezier_interp(p_offset, p0, p1, p2, p3);
+ return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
-Vector3 Curve3D::interpolatef(real_t p_findex) const {
+Vector3 Curve3D::samplef(real_t p_findex) const {
if (p_findex < 0) {
p_findex = 0;
} else if (p_findex >= points.size()) {
p_findex = points.size();
}
- return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
+ return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
+}
+
+void Curve3D::mark_dirty() {
+ baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
}
-void Curve3D::_bake_segment3d(HashMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
+void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
real_t mp = p_begin + (p_end - p_begin) * 0.5;
- Vector3 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector3 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector3 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+ Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
Vector3 na = (mid - beg).normalized();
Vector3 nb = (end - mid).normalized();
real_t dp = na.dot(nb);
- if (dp < Math::cos(Math::deg2rad(p_tol))) {
+ if (dp < Math::cos(Math::deg_to_rad(p_tol))) {
r_bake[mp] = mid;
}
if (p_depth < p_max_depth) {
@@ -1209,7 +1414,7 @@ void Curve3D::_bake() const {
np = 1.0;
}
- Vector3 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ Vector3 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
real_t d = position.distance_to(npp);
if (d > bake_interval) {
@@ -1222,7 +1427,7 @@ void Curve3D::_bake() const {
real_t mid = low + (hi - low) * 0.5;
for (int j = 0; j < iterations; j++) {
- npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
d = position.distance_to(npp);
if (bake_interval < d) {
@@ -1331,7 +1536,7 @@ real_t Curve3D::get_baked_length() const {
return baked_max_ofs;
}
-Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
+Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
if (baked_cache_dirty) {
_bake();
}
@@ -1371,7 +1576,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
@@ -1384,7 +1589,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
}
}
-real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
+real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
if (baked_cache_dirty) {
_bake();
}
@@ -1424,14 +1629,14 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
return Math::lerp(r[idx], r[idx + 1], (real_t)frac);
}
-Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
+Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
if (baked_cache_dirty) {
_bake();
}
@@ -1466,7 +1671,7 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt)
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
@@ -1599,8 +1804,7 @@ real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
void Curve3D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
real_t Curve3D::get_bake_interval() const {
@@ -1609,8 +1813,7 @@ real_t Curve3D::get_bake_interval() const {
void Curve3D::set_up_vector_enabled(bool p_enable) {
up_vector_enabled = p_enable;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
bool Curve3D::is_up_vector_enabled() const {
@@ -1659,7 +1862,8 @@ void Curve3D::_set_data(const Dictionary &p_data) {
points.write[i].tilt = rt[i];
}
- baked_cache_dirty = true;
+ mark_dirty();
+ notify_property_list_changed();
}
PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) const {
@@ -1668,7 +1872,7 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
if (points.size() == 0) {
return tess;
}
- Vector<HashMap<real_t, Vector3>> midpoints;
+ Vector<RBMap<real_t, Vector3>> midpoints;
midpoints.resize(points.size() - 1);
@@ -1697,9 +1901,78 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
+bool Curve3D::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ set_point_position(point_index, p_value);
+ return true;
+ } else if (property == "in") {
+ set_point_in(point_index, p_value);
+ return true;
+ } else if (property == "out") {
+ set_point_out(point_index, p_value);
+ return true;
+ } else if (property == "tilt") {
+ set_point_tilt(point_index, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Curve3D::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ r_ret = get_point_position(point_index);
+ return true;
+ } else if (property == "in") {
+ r_ret = get_point_in(point_index);
+ return true;
+ } else if (property == "out") {
+ r_ret = get_point_out(point_index);
+ return true;
+ } else if (property == "tilt") {
+ r_ret = get_point_tilt(point_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < points.size(); i++) {
+ PropertyInfo pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/position", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ if (i != 0) {
+ pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/in", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ if (i != points.size() - 1) {
+ pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/tilt", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+}
+
void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve3D::set_point_count);
+ ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_tilt", "idx", "tilt"), &Curve3D::set_point_tilt);
@@ -1710,8 +1983,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve3D::get_point_out);
ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve3D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points);
- ClassDB::bind_method(D_METHOD("interpolate", "idx", "t"), &Curve3D::interpolate);
- ClassDB::bind_method(D_METHOD("interpolatef", "fofs"), &Curve3D::interpolatef);
+ ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample);
+ ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
@@ -1719,8 +1992,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_up_vector_enabled"), &Curve3D::is_up_vector_enabled);
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length);
- ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("interpolate_baked_up_vector", "offset", "apply_tilt"), &Curve3D::interpolate_baked_up_vector, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve3D::sample_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked_up_vector", "offset", "apply_tilt"), &Curve3D::sample_baked_up_vector, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts);
ClassDB::bind_method(D_METHOD("get_baked_up_vectors"), &Curve3D::get_baked_up_vectors);
@@ -1729,10 +2002,11 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
- ClassDB::bind_method(D_METHOD("_set_data"), &Curve3D::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+ ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
ADD_GROUP("Up Vector", "up_vector_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled");
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index f9b172f175..88b6dda096 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -76,12 +76,13 @@ public:
int get_point_count() const { return _points.size(); }
+ void set_point_count(int p_count);
+
int add_point(Vector2 p_position,
real_t left_tangent = 0,
real_t right_tangent = 0,
TangentMode left_mode = TANGENT_FREE,
TangentMode right_mode = TANGENT_FREE);
-
void remove_point(int p_index);
void clear_points();
@@ -99,8 +100,8 @@ public:
real_t get_max_value() const { return _max_value; }
void set_max_value(real_t p_max);
- real_t interpolate(real_t p_offset) const;
- real_t interpolate_local_nocheck(int p_index, real_t p_local_offset) const;
+ real_t sample(real_t p_offset) const;
+ real_t sample_local_nocheck(int p_index, real_t p_local_offset) const;
void clean_dupes();
@@ -122,15 +123,25 @@ public:
void bake();
int get_bake_resolution() const { return _bake_resolution; }
void set_bake_resolution(int p_resolution);
- real_t interpolate_baked(real_t p_offset) const;
+ real_t sample_baked(real_t p_offset) const;
void ensure_default_setup(real_t p_min, real_t p_max);
+ 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;
+
protected:
static void _bind_methods();
private:
void mark_dirty();
+ int _add_point(Vector2 p_position,
+ real_t left_tangent = 0,
+ real_t right_tangent = 0,
+ TangentMode left_mode = TANGENT_FREE,
+ TangentMode right_mode = TANGENT_FREE);
+ void _remove_point(int p_index);
Vector<Point> _points;
bool _baked_cache_dirty = false;
@@ -164,19 +175,29 @@ class Curve2D : public Resource {
mutable Vector<real_t> baked_dist_cache;
mutable real_t baked_max_ofs = 0.0;
+ void mark_dirty();
+
void _bake() const;
real_t bake_interval = 5.0;
- void _bake_segment2d(HashMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
+ void _bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
+ 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;
+
+ void _add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
+ void _remove_point(int p_index);
+
protected:
static void _bind_methods();
public:
int get_point_count() const;
+ void set_point_count(int p_count);
void add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
void set_point_position(int p_index, const Vector2 &p_position);
Vector2 get_point_position(int p_index) const;
@@ -187,14 +208,14 @@ public:
void remove_point(int p_index);
void clear_points();
- Vector2 interpolate(int p_index, real_t p_offset) const;
- Vector2 interpolatef(real_t p_findex) const;
+ Vector2 sample(int p_index, real_t p_offset) const;
+ Vector2 samplef(real_t p_findex) const;
void set_bake_interval(real_t p_tolerance);
real_t get_bake_interval() const;
real_t get_baked_length() const;
- Vector2 interpolate_baked(real_t p_offset, bool p_cubic = false) const;
+ Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const;
PackedVector2Array get_baked_points() const; //useful for going through
Vector2 get_closest_point(const Vector2 &p_to_point) const;
real_t get_closest_offset(const Vector2 &p_to_point) const;
@@ -228,20 +249,30 @@ class Curve3D : public Resource {
mutable Vector<real_t> baked_dist_cache;
mutable real_t baked_max_ofs = 0.0;
+ void mark_dirty();
+
void _bake() const;
real_t bake_interval = 0.2;
bool up_vector_enabled = true;
- void _bake_segment3d(HashMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
+ void _bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
+ 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;
+
+ void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
+ void _remove_point(int p_index);
+
protected:
static void _bind_methods();
public:
int get_point_count() const;
+ void set_point_count(int p_count);
void add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
void set_point_position(int p_index, const Vector3 &p_position);
Vector3 get_point_position(int p_index) const;
@@ -254,8 +285,8 @@ public:
void remove_point(int p_index);
void clear_points();
- Vector3 interpolate(int p_index, real_t p_offset) const;
- Vector3 interpolatef(real_t p_findex) const;
+ Vector3 sample(int p_index, real_t p_offset) const;
+ Vector3 samplef(real_t p_findex) const;
void set_bake_interval(real_t p_tolerance);
real_t get_bake_interval() const;
@@ -263,9 +294,9 @@ public:
bool is_up_vector_enabled() const;
real_t get_baked_length() const;
- Vector3 interpolate_baked(real_t p_offset, bool p_cubic = false) const;
- real_t interpolate_baked_tilt(real_t p_offset) const;
- Vector3 interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const;
+ Vector3 sample_baked(real_t p_offset, bool p_cubic = false) const;
+ real_t sample_baked_tilt(real_t p_offset) const;
+ Vector3 sample_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const;
PackedVector3Array get_baked_points() const; //useful for going through
Vector<real_t> get_baked_tilts() const; //useful for going through
PackedVector3Array get_baked_up_vectors() const;
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index a1fe5c46fb..a5951db8ea 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -40,8 +40,8 @@ Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
@@ -100,8 +100,8 @@ void CylinderShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape3D::get_height);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
CylinderShape3D::CylinderShape3D() :
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 4fb44446d9..869d582935 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -35,6 +35,7 @@
#include "default_theme_icons.gen.h"
#include "scene/resources/font.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/text_server.h"
#include "modules/modules_enabled.gen.h" // For svg.
@@ -50,10 +51,7 @@ static const int default_corner_radius = 3;
static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
- style->set_default_margin(SIDE_LEFT, p_margin_left * scale);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * scale);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale);
- style->set_default_margin(SIDE_TOP, p_margin_top * scale);
+ style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
style->set_corner_radius_all(p_corner_radius);
style->set_anti_aliased(true);
@@ -76,7 +74,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
@@ -85,21 +82,15 @@ static Ref<ImageTexture> generate_icon(int p_index) {
// with integer scales.
const bool upsample = !Math::is_equal_approx(Math::round(scale), scale);
ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false);
+ img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
#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) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
-
- style->set_default_margin(SIDE_LEFT, p_margin_left * scale);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * scale);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale);
- style->set_default_margin(SIDE_TOP, p_margin_top * scale);
-
+ style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
return style;
}
@@ -140,7 +131,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Panel
theme->set_stylebox("panel", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
- theme->set_stylebox("panel_fg", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
// Button
@@ -179,6 +169,27 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "Button", 2 * scale);
+ // MenuBar
+ theme->set_stylebox("normal", "MenuBar", button_normal);
+ theme->set_stylebox("hover", "MenuBar", button_hover);
+ theme->set_stylebox("pressed", "MenuBar", button_pressed);
+ theme->set_stylebox("disabled", "MenuBar", button_disabled);
+ theme->set_stylebox("focus", "MenuBar", focus);
+
+ theme->set_font("font", "MenuBar", Ref<Font>());
+ theme->set_font_size("font_size", "MenuBar", -1);
+ theme->set_constant("outline_size", "MenuBar", 0 * scale);
+
+ theme->set_color("font_color", "MenuBar", control_font_color);
+ theme->set_color("font_pressed_color", "MenuBar", control_font_pressed_color);
+ theme->set_color("font_hover_color", "MenuBar", control_font_hover_color);
+ theme->set_color("font_focus_color", "MenuBar", control_font_focus_color);
+ theme->set_color("font_hover_pressed_color", "MenuBar", control_font_pressed_color);
+ theme->set_color("font_disabled_color", "MenuBar", control_font_disabled_color);
+ theme->set_color("font_outline_color", "MenuBar", Color(1, 1, 1));
+
+ theme->set_constant("h_separation", "MenuBar", 4 * scale);
+
// LinkButton
theme->set_stylebox("focus", "LinkButton", focus);
@@ -226,6 +237,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "OptionButton", control_font_color);
theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_hover_color", "OptionButton", control_font_hover_color);
+ theme->set_color("font_hover_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_focus_color", "OptionButton", control_font_focus_color);
theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color);
theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1));
@@ -233,6 +245,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "OptionButton", 2 * scale);
theme->set_constant("arrow_margin", "OptionButton", 4 * scale);
theme->set_constant("outline_size", "OptionButton", 0);
+ theme->set_constant("modulate_arrow", "OptionButton", false);
// MenuButton
@@ -258,15 +271,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// CheckBox
Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty);
- cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale);
- cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale);
- cbx_empty->set_default_margin(SIDE_TOP, 4 * scale);
- cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cbx_empty->set_default_margin_all(4 * scale);
Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale);
- cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale);
- cbx_focus->set_default_margin(SIDE_TOP, 4 * scale);
- cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cbx_focus->set_default_margin_all(4 * scale);
theme->set_stylebox("normal", "CheckBox", cbx_empty);
theme->set_stylebox("pressed", "CheckBox", cbx_empty);
@@ -296,16 +303,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1));
theme->set_constant("h_separation", "CheckBox", 4 * scale);
- theme->set_constant("check_v_adjust", "CheckBox", 0 * scale);
+ theme->set_constant("check_v_offset", "CheckBox", 0 * scale);
theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty);
- cb_empty->set_default_margin(SIDE_LEFT, 6 * scale);
- cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale);
- cb_empty->set_default_margin(SIDE_TOP, 4 * scale);
- cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale);
theme->set_stylebox("normal", "CheckButton", cb_empty);
theme->set_stylebox("pressed", "CheckButton", cb_empty);
@@ -314,15 +318,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("hover_pressed", "CheckButton", cb_empty);
theme->set_stylebox("focus", "CheckButton", focus);
- theme->set_icon("on", "CheckButton", icons["toggle_on"]);
- theme->set_icon("on_disabled", "CheckButton", icons["toggle_on_disabled"]);
- theme->set_icon("off", "CheckButton", icons["toggle_off"]);
- theme->set_icon("off_disabled", "CheckButton", icons["toggle_off_disabled"]);
+ theme->set_icon("checked", "CheckButton", icons["toggle_on"]);
+ theme->set_icon("checked_disabled", "CheckButton", icons["toggle_on_disabled"]);
+ theme->set_icon("unchecked", "CheckButton", icons["toggle_off"]);
+ theme->set_icon("unchecked_disabled", "CheckButton", icons["toggle_off_disabled"]);
- theme->set_icon("on_mirrored", "CheckButton", icons["toggle_on_mirrored"]);
- theme->set_icon("on_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]);
- theme->set_icon("off_mirrored", "CheckButton", icons["toggle_off_mirrored"]);
- theme->set_icon("off_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]);
+ theme->set_icon("checked_mirrored", "CheckButton", icons["toggle_on_mirrored"]);
+ theme->set_icon("checked_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]);
+ theme->set_icon("unchecked_mirrored", "CheckButton", icons["toggle_off_mirrored"]);
+ theme->set_icon("unchecked_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]);
theme->set_font("font", "CheckButton", Ref<Font>());
theme->set_font_size("font_size", "CheckButton", -1);
@@ -336,7 +340,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1));
theme->set_constant("h_separation", "CheckButton", 4 * scale);
- theme->set_constant("check_v_adjust", "CheckButton", 0 * scale);
+ theme->set_constant("check_v_offset", "CheckButton", 0 * scale);
theme->set_constant("outline_size", "CheckButton", 0);
// Label
@@ -401,8 +405,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ProgressBar
- theme->set_stylebox("bg", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6));
- theme->set_stylebox("fg", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6));
+ theme->set_stylebox("background", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6));
+ theme->set_stylebox("fill", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6));
theme->set_font("font", "ProgressBar", Ref<Font>());
theme->set_font_size("font_size", "ProgressBar", -1);
@@ -467,6 +471,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));
@@ -565,12 +570,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxEmpty> empty;
empty.instantiate();
- theme->set_stylebox("bg", "ScrollContainer", empty);
+ theme->set_stylebox("panel", "ScrollContainer", empty);
// Window
theme->set_stylebox("embedded_border", "Window", sb_expand(make_flat_stylebox(style_popup_color, 10, 28, 10, 8), 8, 32, 8, 6));
- theme->set_constant("scaleborder_size", "Window", 4 * scale);
theme->set_font("title_font", "Window", Ref<Font>());
theme->set_font_size("title_font_size", "Window", -1);
@@ -587,12 +591,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Dialogs
- theme->set_constant("margin", "Dialogs", 8 * scale);
- theme->set_constant("button_margin", "Dialogs", 32 * scale);
-
- // AcceptDialog
-
- theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0));
+ // AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
+ theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 8 * scale, 8 * scale, 8 * scale, 8 * scale));
+ theme->set_constant("buttons_separation", "AcceptDialog", 10 * scale);
// File Dialog
@@ -603,9 +604,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]);
theme->set_icon("folder", "FileDialog", icons["folder"]);
theme->set_icon("file", "FileDialog", icons["file"]);
- theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7));
+ theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1));
+ theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1));
+ theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25));
// Popup
@@ -620,16 +621,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine);
separator_horizontal->set_thickness(Math::round(scale));
separator_horizontal->set_color(style_separator_color);
- separator_horizontal->set_default_margin(SIDE_LEFT, default_margin);
- separator_horizontal->set_default_margin(SIDE_TOP, 0);
- separator_horizontal->set_default_margin(SIDE_RIGHT, default_margin);
- separator_horizontal->set_default_margin(SIDE_BOTTOM, 0);
+ separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0);
Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate();
separator_vertical->set_vertical(true);
- separator_vertical->set_default_margin(SIDE_LEFT, 0);
- separator_vertical->set_default_margin(SIDE_TOP, default_margin);
- separator_vertical->set_default_margin(SIDE_RIGHT, 0);
- separator_vertical->set_default_margin(SIDE_BOTTOM, default_margin);
+ separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin);
// Always display a border for PopupMenus so they can be distinguished from their background.
Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color);
@@ -646,9 +641,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("labeled_separator_right", "PopupMenu", separator_horizontal);
theme->set_icon("checked", "PopupMenu", icons["checked"]);
+ theme->set_icon("checked_disabled", "PopupMenu", icons["checked"]);
theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]);
+ theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked"]);
theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]);
+ theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked"]);
theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]);
+ theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked"]);
theme->set_icon("submenu", "PopupMenu", icons["popup_menu_arrow_right"]);
theme->set_icon("submenu_mirrored", "PopupMenu", icons["popup_menu_arrow_left"]);
@@ -665,6 +664,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_color("font_separator_outline_color", "PopupMenu", Color(1, 1, 1));
+ theme->set_constant("indent", "PopupMenu", 10 * scale);
theme->set_constant("h_separation", "PopupMenu", 4 * scale);
theme->set_constant("v_separation", "PopupMenu", 4 * scale);
theme->set_constant("outline_size", "PopupMenu", 0);
@@ -705,14 +705,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("resizer_color", "GraphNode", control_font_color);
theme->set_constant("separation", "GraphNode", 2 * scale);
theme->set_constant("title_offset", "GraphNode", 26 * scale);
+ theme->set_constant("title_h_offset", "GraphNode", 0);
theme->set_constant("close_offset", "GraphNode", 22 * scale);
theme->set_constant("close_h_offset", "GraphNode", 22 * scale);
theme->set_constant("port_offset", "GraphNode", 0);
// Tree
- theme->set_stylebox("bg", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
- theme->set_stylebox("bg_focus", "Tree", focus);
+ theme->set_stylebox("panel", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
+ theme->set_stylebox("focus", "Tree", focus);
theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("cursor", "Tree", focus);
@@ -743,7 +744,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "Tree", control_font_pressed_color);
theme->set_color("font_outline_color", "Tree", Color(1, 1, 1));
theme->set_color("guide_color", "Tree", Color(0.7, 0.7, 0.7, 0.25));
- theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2));
+ theme->set_color("drop_position_color", "Tree", Color(1, 1, 1));
theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
@@ -765,8 +766,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ItemList
- theme->set_stylebox("bg", "ItemList", make_flat_stylebox(style_normal_color));
- theme->set_stylebox("bg_focus", "ItemList", focus);
+ theme->set_stylebox("panel", "ItemList", make_flat_stylebox(style_normal_color));
+ theme->set_stylebox("focus", "ItemList", focus);
theme->set_constant("h_separation", "ItemList", 4);
theme->set_constant("v_separation", "ItemList", 2);
theme->set_constant("icon_margin", "ItemList", 4);
@@ -778,7 +779,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "ItemList", control_font_lower_color);
theme->set_color("font_selected_color", "ItemList", control_font_pressed_color);
theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1));
- theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1));
+ theme->set_color("guide_color", "ItemList", Color(0.7, 0.7, 0.7, 0.25));
theme->set_stylebox("selected", "ItemList", make_flat_stylebox(style_selected_color));
theme->set_stylebox("selected_focus", "ItemList", make_flat_stylebox(style_selected_color));
theme->set_stylebox("cursor", "ItemList", focus);
@@ -803,6 +804,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected);
theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled);
theme->set_stylebox("panel", "TabContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
+ theme->set_stylebox("tabbar_background", "TabContainer", make_empty_stylebox(0, 0, 0, 0));
theme->set_icon("increment", "TabContainer", icons["scroll_button_right"]);
theme->set_icon("increment_highlight", "TabContainer", icons["scroll_button_right_hl"]);
@@ -918,8 +920,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("panel", "TooltipPanel",
make_flat_stylebox(Color(0, 0, 0, 0.5), 2 * default_margin, 0.5 * default_margin, 2 * default_margin, 0.5 * default_margin));
- theme->set_font("font", "TooltipLabel", Ref<Font>());
theme->set_font_size("font_size", "TooltipLabel", -1);
+ theme->set_font("font", "TooltipLabel", Ref<Font>());
theme->set_color("font_color", "TooltipLabel", control_font_color);
theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0));
@@ -939,7 +941,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);
@@ -970,9 +971,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Containers
+ theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
+ theme->set_icon("v_grabber", "SplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "HSplitContainer", icons["hsplitter"]);
+ theme->set_constant("separation", "BoxContainer", 4 * scale);
theme->set_constant("separation", "HBoxContainer", 4 * scale);
theme->set_constant("separation", "VBoxContainer", 4 * scale);
theme->set_constant("margin_left", "MarginContainer", 0 * scale);
@@ -981,10 +985,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("margin_bottom", "MarginContainer", 0 * scale);
theme->set_constant("h_separation", "GridContainer", 4 * scale);
theme->set_constant("v_separation", "GridContainer", 4 * scale);
+ theme->set_constant("separation", "SplitContainer", 12 * scale);
theme->set_constant("separation", "HSplitContainer", 12 * scale);
theme->set_constant("separation", "VSplitContainer", 12 * scale);
+ theme->set_constant("minimum_grab_thickness", "SplitContainer", 6 * scale);
+ theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * scale);
+ theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * scale);
+ theme->set_constant("autohide", "SplitContainer", 1 * scale);
theme->set_constant("autohide", "HSplitContainer", 1 * scale);
theme->set_constant("autohide", "VSplitContainer", 1 * scale);
+ theme->set_constant("h_separation", "FlowContainer", 4 * scale);
+ theme->set_constant("v_separation", "FlowContainer", 4 * scale);
theme->set_constant("h_separation", "HFlowContainer", 4 * scale);
theme->set_constant("v_separation", "HFlowContainer", 4 * scale);
theme->set_constant("h_separation", "VFlowContainer", 4 * scale);
@@ -1004,13 +1015,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3));
theme->set_color("selection_stroke", "GraphEdit", Color(1, 1, 1, 0.8));
theme->set_color("activity", "GraphEdit", Color(1, 1, 1));
- theme->set_constant("bezier_len_pos", "GraphEdit", 80 * scale);
- theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale);
// Visual Node Ports
- theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale);
- theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale);
+ theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale);
+ theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale);
theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0);
@@ -1029,16 +1038,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
default_style = make_flat_stylebox(Color(1, 0.365, 0.365), 4, 4, 4, 4, 0, false, 2);
}
-void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, bool p_font_antialiased, bool p_font_msdf, bool p_font_generate_mipmaps) {
+void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, TextServer::FontAntialiasing p_font_antialiasing, bool p_font_msdf, bool p_font_generate_mipmaps) {
Ref<Theme> t;
t.instantiate();
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()) {
@@ -1048,61 +1057,40 @@ 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_antialiasing(p_font_antialiasing);
+ 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();
- 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();
- data->set_embolden(1.2);
- data->set_transform(Transform2D(1.0, 0.4, 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();
- data->set_transform(Transform2D(1.0, 0.4, 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);
- Theme::set_default(t);
- Theme::set_fallback_base_scale(default_scale);
- Theme::set_fallback_icon(default_icon);
- Theme::set_fallback_style(default_style);
- Theme::set_fallback_font(default_font);
- Theme::set_fallback_font_size(default_font_size * default_scale);
-}
+ ThemeDB::get_singleton()->set_default_theme(t);
-void clear_default_theme() {
- Theme::set_project_default(nullptr);
- Theme::set_default(nullptr);
- Theme::set_fallback_icon(nullptr);
- Theme::set_fallback_style(nullptr);
- Theme::set_fallback_font(nullptr);
+ ThemeDB::get_singleton()->set_fallback_base_scale(default_scale);
+ ThemeDB::get_singleton()->set_fallback_icon(default_icon);
+ ThemeDB::get_singleton()->set_fallback_stylebox(default_style);
+ ThemeDB::get_singleton()->set_fallback_font(default_font);
+ ThemeDB::get_singleton()->set_fallback_font_size(default_font_size * default_scale);
}
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index f777330a07..003934ce90 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -36,7 +36,6 @@
const int default_font_size = 16;
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale);
-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();
+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, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
-#endif
+#endif // DEFAULT_THEME_H
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 5d1e07f6cd..ebdaaaa95f 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -94,13 +94,30 @@ Color Environment::get_bg_color() const {
return bg_color;
}
-void Environment::set_bg_energy(float p_energy) {
- bg_energy = p_energy;
- RS::get_singleton()->environment_set_bg_energy(environment, p_energy);
+void Environment::set_bg_energy_multiplier(float p_multiplier) {
+ bg_energy_multiplier = p_multiplier;
+ _update_bg_energy();
}
-float Environment::get_bg_energy() const {
- return bg_energy;
+float Environment::get_bg_energy_multiplier() const {
+ return bg_energy_multiplier;
+}
+
+void Environment::set_bg_intensity(float p_exposure_value) {
+ bg_intensity = p_exposure_value;
+ _update_bg_energy();
+}
+
+float Environment::get_bg_intensity() const {
+ return bg_intensity;
+}
+
+void Environment::_update_bg_energy() {
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, bg_intensity);
+ } else {
+ RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, 1.0);
+ }
}
void Environment::set_canvas_max_layer(int p_max_layer) {
@@ -214,63 +231,12 @@ float Environment::get_tonemap_white() const {
return tonemap_white;
}
-void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) {
- tonemap_auto_exposure_enabled = p_enabled;
- _update_tonemap();
- notify_property_list_changed();
-}
-
-bool Environment::is_tonemap_auto_exposure_enabled() const {
- return tonemap_auto_exposure_enabled;
-}
-
-void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) {
- tonemap_auto_exposure_min = p_auto_exposure_min;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_min() const {
- return tonemap_auto_exposure_min;
-}
-
-void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) {
- tonemap_auto_exposure_max = p_auto_exposure_max;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_max() const {
- return tonemap_auto_exposure_max;
-}
-
-void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) {
- tonemap_auto_exposure_speed = p_auto_exposure_speed;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_speed() const {
- return tonemap_auto_exposure_speed;
-}
-
-void Environment::set_tonemap_auto_exposure_grey(float p_auto_exposure_grey) {
- tonemap_auto_exposure_grey = p_auto_exposure_grey;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_grey() const {
- return tonemap_auto_exposure_grey;
-}
-
void Environment::_update_tonemap() {
RS::get_singleton()->environment_set_tonemap(
environment,
RS::EnvironmentToneMapper(tone_mapper),
tonemap_exposure,
- tonemap_white,
- tonemap_auto_exposure_enabled,
- tonemap_auto_exposure_min,
- tonemap_auto_exposure_max,
- tonemap_auto_exposure_speed,
- tonemap_auto_exposure_grey);
+ tonemap_white);
}
// SSR
@@ -852,6 +818,15 @@ float Environment::get_fog_aerial_perspective() const {
return fog_aerial_perspective;
}
+void Environment::set_fog_sky_affect(float p_sky_affect) {
+ fog_sky_affect = p_sky_affect;
+ _update_fog();
+}
+
+float Environment::get_fog_sky_affect() const {
+ return fog_sky_affect;
+}
+
void Environment::_update_fog() {
RS::get_singleton()->environment_set_fog(
environment,
@@ -862,13 +837,28 @@ void Environment::_update_fog() {
fog_density,
fog_height,
fog_height_density,
- fog_aerial_perspective);
+ fog_aerial_perspective,
+ fog_sky_affect);
}
// Volumetric Fog
void Environment::_update_volumetric_fog() {
- RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_albedo, volumetric_fog_emission, volumetric_fog_emission_energy, volumetric_fog_anisotropy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount, volumetric_fog_ambient_inject);
+ RS::get_singleton()->environment_set_volumetric_fog(
+ environment,
+ volumetric_fog_enabled,
+ volumetric_fog_density,
+ volumetric_fog_albedo,
+ volumetric_fog_emission,
+ volumetric_fog_emission_energy,
+ volumetric_fog_anisotropy,
+ volumetric_fog_length,
+ volumetric_fog_detail_spread,
+ volumetric_fog_gi_inject,
+ volumetric_fog_temporal_reproject,
+ volumetric_fog_temporal_reproject_amount,
+ volumetric_fog_ambient_inject,
+ volumetric_fog_sky_affect);
}
void Environment::set_volumetric_fog_enabled(bool p_enable) {
@@ -946,6 +936,15 @@ float Environment::get_volumetric_fog_ambient_inject() const {
return volumetric_fog_ambient_inject;
}
+void Environment::set_volumetric_fog_sky_affect(float p_sky_affect) {
+ volumetric_fog_sky_affect = p_sky_affect;
+ _update_volumetric_fog();
+}
+
+float Environment::get_volumetric_fog_sky_affect() const {
+ return volumetric_fog_sky_affect;
+}
+
void Environment::set_volumetric_fog_temporal_reprojection_enabled(bool p_enable) {
volumetric_fog_temporal_reproject = p_enable;
_update_volumetric_fog();
@@ -1037,53 +1036,56 @@ void Environment::_update_adjustment() {
// Private methods, constructor and destructor
-void Environment::_validate_property(PropertyInfo &property) const {
- if (property.name == "sky" || property.name == "sky_custom_fov" || property.name == "sky_rotation" || property.name == "ambient_light/sky_contribution") {
+void Environment::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sky" || p_property.name == "sky_custom_fov" || p_property.name == "sky_rotation" || p_property.name == "ambient_light_sky_contribution") {
if (bg_mode != BG_SKY && ambient_source != AMBIENT_SOURCE_SKY && reflection_source != REFLECTION_SOURCE_SKY) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "fog_aerial_perspective") {
+ if (p_property.name == "fog_aerial_perspective") {
if (bg_mode != BG_SKY) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "background_color") {
+ if (p_property.name == "background_color") {
if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "background_canvas_max_layer") {
+ if (p_property.name == "background_canvas_max_layer") {
if (bg_mode != BG_CANVAS) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "background_camera_feed_id") {
+ if (p_property.name == "background_camera_feed_id") {
if (bg_mode != BG_CAMERA_FEED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
+ if (p_property.name == "background_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
static const char *hide_prefixes[] = {
"fog_",
"volumetric_fog_",
- "auto_exposure_",
"ssr_",
"ssao_",
"ssil_",
@@ -1095,7 +1097,6 @@ void Environment::_validate_property(PropertyInfo &property) const {
};
static const char *high_end_prefixes[] = {
- "auto_exposure_",
"ssr_",
"ssao_",
nullptr
@@ -1107,8 +1108,8 @@ void Environment::_validate_property(PropertyInfo &property) const {
String prefix = String(*prefixes);
String enabled = prefix + "enabled";
- if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with(prefix) && p_property.name != enabled && !bool(get(enabled))) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
@@ -1120,8 +1121,8 @@ void Environment::_validate_property(PropertyInfo &property) const {
while (*prefixes) {
String prefix = String(*prefixes);
- if (property.name.begins_with(prefix)) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with(prefix)) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
@@ -1162,8 +1163,10 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_sky_rotation"), &Environment::get_sky_rotation);
ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color);
ClassDB::bind_method(D_METHOD("get_bg_color"), &Environment::get_bg_color);
- ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy);
- ClassDB::bind_method(D_METHOD("get_bg_energy"), &Environment::get_bg_energy);
+ ClassDB::bind_method(D_METHOD("set_bg_energy_multiplier", "energy"), &Environment::set_bg_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_bg_energy_multiplier"), &Environment::get_bg_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("set_bg_intensity", "energy"), &Environment::set_bg_intensity);
+ ClassDB::bind_method(D_METHOD("get_bg_intensity"), &Environment::get_bg_intensity);
ClassDB::bind_method(D_METHOD("set_canvas_max_layer", "layer"), &Environment::set_canvas_max_layer);
ClassDB::bind_method(D_METHOD("get_canvas_max_layer"), &Environment::get_canvas_max_layer);
ClassDB::bind_method(D_METHOD("set_camera_feed_id", "id"), &Environment::set_camera_feed_id);
@@ -1172,14 +1175,16 @@ void Environment::_bind_methods() {
ADD_GROUP("Background", "background_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Canvas,Keep,Camera Feed"), "set_background", "get_background");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy", "get_bg_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy_multiplier", "get_bg_energy_multiplier");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_intensity", PROPERTY_HINT_RANGE, "0,100000,0.01,suffix:nt"), "set_bg_intensity", "get_bg_intensity");
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "background_canvas_max_layer", PROPERTY_HINT_RANGE, "-1000,1000,1"), "set_canvas_max_layer", "get_canvas_max_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "background_camera_feed_id", PROPERTY_HINT_RANGE, "1,10,1"), "set_camera_feed_id", "get_camera_feed_id");
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_sky_custom_fov", "get_sky_custom_fov");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation"), "set_sky_rotation", "get_sky_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_sky_custom_fov", "get_sky_custom_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_sky_rotation", "get_sky_rotation");
// Ambient light
@@ -1211,27 +1216,11 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure);
ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white);
ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_enabled", "enabled"), &Environment::set_tonemap_auto_exposure_enabled);
- ClassDB::bind_method(D_METHOD("is_tonemap_auto_exposure_enabled"), &Environment::is_tonemap_auto_exposure_enabled);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey);
ADD_GROUP("Tonemap", "tonemap_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES"), "set_tonemapper", "get_tonemapper");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white");
- ADD_GROUP("Auto Exposure", "auto_exposure_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure_enabled", "is_tonemap_auto_exposure_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed");
// SSR
@@ -1249,8 +1238,8 @@ void Environment::_bind_methods() {
ADD_GROUP("SSR", "ssr_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssr_enabled"), "set_ssr_enabled", "is_ssr_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ssr_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_in", "get_ssr_fade_in");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_out", "get_ssr_fade_out");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_depth_tolerance", PROPERTY_HINT_RANGE, "0.01,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance");
// SSAO
@@ -1277,7 +1266,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssao_enabled"), "set_ssao_enabled", "is_ssao_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater"), "set_ssao_radius", "get_ssao_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_intensity", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_ssao_intensity", "get_ssao_intensity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING), "set_ssao_power", "get_ssao_power");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssao_power", "get_ssao_power");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_detail", PROPERTY_HINT_RANGE, "0,5,0.01"), "set_ssao_detail", "get_ssao_detail");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_horizon", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_horizon", "get_ssao_horizon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_sharpness", "get_ssao_sharpness");
@@ -1298,7 +1287,7 @@ void Environment::_bind_methods() {
ADD_GROUP("SSIL", "ssil_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssil_enabled"), "set_ssil_enabled", "is_ssil_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater"), "set_ssil_radius", "get_ssil_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater,suffix:m"), "set_ssil_radius", "get_ssil_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_intensity", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_ssil_intensity", "get_ssil_intensity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssil_sharpness", "get_ssil_sharpness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_normal_rejection", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssil_normal_rejection", "get_ssil_normal_rejection");
@@ -1337,8 +1326,10 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_RANGE, "1,8,1"), "set_sdfgi_cascades", "get_sdfgi_cascades");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_max_distance", "get_sdfgi_max_distance");
+ // Don't store the values of `sdfgi_cascade0_distance` and `sdfgi_max_distance`
+ // as they're derived from `sdfgi_min_cell_size`.
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater", PROPERTY_USAGE_EDITOR), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater", PROPERTY_USAGE_EDITOR), "set_sdfgi_max_distance", "get_sdfgi_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_y_scale", PROPERTY_HINT_ENUM, "50% (Compact),75% (Balanced),100% (Sparse)"), "set_sdfgi_y_scale", "get_sdfgi_y_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_energy"), "set_sdfgi_energy", "get_sdfgi_energy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_normal_bias"), "set_sdfgi_normal_bias", "get_sdfgi_normal_bias");
@@ -1417,16 +1408,20 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fog_aerial_perspective", "aerial_perspective"), &Environment::set_fog_aerial_perspective);
ClassDB::bind_method(D_METHOD("get_fog_aerial_perspective"), &Environment::get_fog_aerial_perspective);
+ ClassDB::bind_method(D_METHOD("set_fog_sky_affect", "sky_affect"), &Environment::set_fog_sky_affect);
+ ClassDB::bind_method(D_METHOD("get_fog_sky_affect"), &Environment::get_fog_sky_affect);
+
ADD_GROUP("Fog", "fog_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color");
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"), "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");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_sky_affect", "get_fog_sky_affect");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_less,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_less,or_greater"), "set_fog_height_density", "get_fog_height_density");
ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled);
@@ -1448,6 +1443,8 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_ambient_inject", "enabled"), &Environment::set_volumetric_fog_ambient_inject);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_ambient_inject"), &Environment::get_volumetric_fog_ambient_inject);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_sky_affect", "sky_affect"), &Environment::set_volumetric_fog_sky_affect);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_sky_affect"), &Environment::get_volumetric_fog_sky_affect);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_enabled", "enabled"), &Environment::set_volumetric_fog_temporal_reprojection_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_temporal_reprojection_enabled"), &Environment::is_volumetric_fog_temporal_reprojection_enabled);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_amount", "temporal_reprojection_amount"), &Environment::set_volumetric_fog_temporal_reprojection_amount);
@@ -1462,11 +1459,12 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_anisotropy", PROPERTY_HINT_RANGE, "-0.9,0.9,0.01"), "set_volumetric_fog_anisotropy", "get_volumetric_fog_anisotropy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_volumetric_fog_sky_affect", "get_volumetric_fog_sky_affect");
ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.0,0.999,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.5,0.99,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount");
// Adjustment
@@ -1547,6 +1545,7 @@ Environment::Environment() {
_update_fog();
_update_adjustment();
_update_volumetric_fog();
+ _update_bg_energy();
notify_property_list_changed();
}
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index b71fe8904a..507a0cee39 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -92,9 +92,11 @@ private:
float bg_sky_custom_fov = 0.0;
Vector3 bg_sky_rotation;
Color bg_color;
- float bg_energy = 1.0;
int bg_canvas_max_layer = 0;
int bg_camera_feed_id = 1;
+ float bg_energy_multiplier = 1.0;
+ float bg_intensity = 30000.0; // Measured in nits or candela/m^2
+ void _update_bg_energy();
// Ambient light
Color ambient_color;
@@ -108,11 +110,6 @@ private:
ToneMapper tone_mapper = TONE_MAPPER_LINEAR;
float tonemap_exposure = 1.0;
float tonemap_white = 1.0;
- bool tonemap_auto_exposure_enabled = false;
- float tonemap_auto_exposure_min = 0.05;
- float tonemap_auto_exposure_max = 8.0;
- float tonemap_auto_exposure_speed = 0.5;
- float tonemap_auto_exposure_grey = 0.4;
void _update_tonemap();
// SSR
@@ -175,13 +172,14 @@ 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;
+ float fog_sky_affect = 1.0;
void _update_fog();
@@ -194,8 +192,9 @@ 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;
+ float volumetric_fog_sky_affect = 1.0;
bool volumetric_fog_temporal_reproject = true;
float volumetric_fog_temporal_reproject_amount = 0.9;
void _update_volumetric_fog();
@@ -211,7 +210,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
#ifndef DISABLE_DEPRECATED
// Kept for compatibility from 3.x to 4.0.
bool _set(const StringName &p_name, const Variant &p_value);
@@ -231,8 +230,10 @@ public:
Vector3 get_sky_rotation() const;
void set_bg_color(const Color &p_color);
Color get_bg_color() const;
- void set_bg_energy(float p_energy);
- float get_bg_energy() const;
+ void set_bg_energy_multiplier(float p_energy);
+ float get_bg_energy_multiplier() const;
+ void set_bg_intensity(float p_energy);
+ float get_bg_intensity() const;
void set_canvas_max_layer(int p_max_layer);
int get_canvas_max_layer() const;
void set_camera_feed_id(int p_id);
@@ -257,16 +258,6 @@ public:
float get_tonemap_exposure() const;
void set_tonemap_white(float p_white);
float get_tonemap_white() const;
- void set_tonemap_auto_exposure_enabled(bool p_enabled);
- bool is_tonemap_auto_exposure_enabled() const;
- void set_tonemap_auto_exposure_min(float p_auto_exposure_min);
- float get_tonemap_auto_exposure_min() const;
- void set_tonemap_auto_exposure_max(float p_auto_exposure_max);
- float get_tonemap_auto_exposure_max() const;
- void set_tonemap_auto_exposure_speed(float p_auto_exposure_speed);
- float get_tonemap_auto_exposure_speed() const;
- void set_tonemap_auto_exposure_grey(float p_auto_exposure_grey);
- float get_tonemap_auto_exposure_grey() const;
// SSR
void set_ssr_enabled(bool p_enabled);
@@ -385,6 +376,8 @@ public:
float get_fog_height_density() const;
void set_fog_aerial_perspective(float p_aerial_perspective);
float get_fog_aerial_perspective() const;
+ void set_fog_sky_affect(float p_sky_affect);
+ float get_fog_sky_affect() const;
// Volumetric Fog
void set_volumetric_fog_enabled(bool p_enable);
@@ -407,6 +400,8 @@ public:
float get_volumetric_fog_gi_inject() const;
void set_volumetric_fog_ambient_inject(float p_ambient_inject);
float get_volumetric_fog_ambient_inject() const;
+ void set_volumetric_fog_sky_affect(float p_sky_affect);
+ float get_volumetric_fog_sky_affect() const;
void set_volumetric_fog_temporal_reprojection_enabled(bool p_enable);
bool is_volumetric_fog_temporal_reprojection_enabled() const;
void set_volumetric_fog_temporal_reprojection_amount(float p_amount);
diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp
index a05ef0c779..46b44d681f 100644
--- a/scene/resources/fog_material.cpp
+++ b/scene/resources/fog_material.cpp
@@ -122,7 +122,7 @@ void FogMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_density_texture", "density_texture"), &FogMaterial::set_density_texture);
ClassDB::bind_method(D_METHOD("get_density_texture"), &FogMaterial::get_density_texture);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_lesser"), "set_density", "get_density");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "-8.0,8.0,0.0001,or_greater,or_less"), "set_density", "get_density");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_albedo", "get_albedo");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_falloff", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_height_falloff", "get_height_falloff");
@@ -148,11 +148,11 @@ void FogMaterial::_update_shader() {
shader_type fog;
uniform float density : hint_range(0, 1, 0.0001) = 1.0;
-uniform vec4 albedo : hint_color = vec4(1.0);
-uniform vec4 emission : hint_color = vec4(0, 0, 0, 1);
+uniform vec4 albedo : source_color = vec4(1.0);
+uniform vec4 emission : source_color = vec4(0, 0, 0, 1);
uniform float height_falloff = 0.0;
uniform float edge_fade = 0.1;
-uniform sampler3D density_texture: hint_white;
+uniform sampler3D density_texture: hint_default_white;
void fog() {
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index d586abac14..bbc4029764 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,431 +38,560 @@
#include "core/templates/hashfuncs.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
+#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.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 */
+/*************************************************************************/
+
+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);
+
+ 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("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("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));
+
+ // 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)));
+
+ // 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("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("get_supported_feature_list"), &Font::get_supported_feature_list);
+ ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &Font::get_supported_variation_list);
+ ClassDB::bind_method(D_METHOD("get_face_count"), &Font::get_face_count);
+}
+
+void Font::_update_rids_fb(const Ref<Font> &p_f, int p_depth) const {
+ ERR_FAIL_COND(p_depth > MAX_FALLBACK_DEPTH);
+ if (p_f.is_valid()) {
+ RID rid = p_f->_get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
+ }
+ const TypedArray<Font> &_fallbacks = p_f->get_fallbacks();
+ for (int i = 0; i < _fallbacks.size(); i++) {
+ _update_rids_fb(_fallbacks[i], p_depth + 1);
}
}
}
-_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_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::_update_rids() const {
+ rids.clear();
+ _update_rids_fb(const_cast<Font *>(this), 0);
+ dirty_rids = false;
}
-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);
+void Font::_invalidate_rids() {
+ rids.clear();
+ dirty_rids = true;
- ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data);
- ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data);
+ cache.clear();
+ cache_wrap.clear();
- ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
- ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
+ emit_changed();
+}
- 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);
+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;
+}
- 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);
+void Font::reset_state() {
+ _invalidate_rids();
+}
- 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);
+// 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();
+}
- 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);
+TypedArray<Font> Font::get_fallbacks() const {
+ return fallbacks;
+}
- 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);
+// Output.
+TypedArray<RID> Font::get_rids() const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ return rids;
+}
- 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);
+// 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_msdf_size", "msdf_size"), &FontData::set_msdf_size);
- ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontData::get_msdf_size);
+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_fixed_size", "fixed_size"), &FontData::set_fixed_size);
- ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontData::get_fixed_size);
+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_force_autohinter", "force_autohinter"), &FontData::set_force_autohinter);
- ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontData::is_force_autohinter);
+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_hinting", "hinting"), &FontData::set_hinting);
- ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting);
+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_subpixel_positioning", "subpixel_positioning"), &FontData::set_subpixel_positioning);
- ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontData::get_subpixel_positioning);
+String Font::get_font_name() const {
+ return TS->font_get_name(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("set_embolden", "strength"), &FontData::set_embolden);
- ClassDB::bind_method(D_METHOD("get_embolden"), &FontData::get_embolden);
+String Font::get_font_style_name() const {
+ return TS->font_get_style_name(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &FontData::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &FontData::get_transform);
+BitField<TextServer::FontStyle> Font::get_font_style() const {
+ return TS->font_get_style(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontData::set_oversampling);
- ClassDB::bind_method(D_METHOD("get_oversampling"), &FontData::get_oversampling);
+Dictionary Font::get_opentype_features() const {
+ return Dictionary();
+}
- ClassDB::bind_method(D_METHOD("find_cache", "variation_coordinates"), &FontData::find_cache);
+// 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("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);
+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("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);
+ 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_variation_coordinates", "cache_index", "variation_coordinates"), &FontData::set_variation_coordinates);
- ClassDB::bind_method(D_METHOD("get_variation_coordinates", "cache_index"), &FontData::get_variation_coordinates);
+ 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_ascent", "cache_index", "size", "ascent"), &FontData::set_ascent);
- ClassDB::bind_method(D_METHOD("get_ascent", "cache_index", "size"), &FontData::get_ascent);
+ return buffer->get_size();
+}
- 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);
+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_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);
+ 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_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);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- 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);
+ return lines_buffer->get_size();
+}
- 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);
+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("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);
+ 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_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);
+ 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("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);
+ 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("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->draw(p_canvas_item, ofs, p_modulate);
+}
- 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);
+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_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);
+ 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_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);
+ 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_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);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- 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->draw(p_canvas_item, ofs, p_modulate);
+}
- 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);
+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("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);
+ 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("render_range", "cache_index", "size", "start", "end"), &FontData::render_range);
- ClassDB::bind_method(D_METHOD("render_glyph", "cache_index", "size", "index"), &FontData::render_glyph);
+ 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_cache_rid", "cache_index"), &FontData::get_cache_rid);
+ 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_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->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
+}
- 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);
+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("set_opentype_feature_overrides", "overrides"), &FontData::set_opentype_feature_overrides);
- ClassDB::bind_method(D_METHOD("get_opentype_feature_overrides"), &FontData::get_opentype_feature_overrides);
+ 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("has_char", "char"), &FontData::has_char);
- ClassDB::bind_method(D_METHOD("get_supported_chars"), &FontData::get_supported_chars);
+ 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_glyph_index", "size", "char", "variation_selector"), &FontData::get_glyph_index);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- 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->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
+}
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning");
- ADD_PROPERTY(PropertyInfo(Variant::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");
+// 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 Size2();
}
-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;
+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") {
- 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;
- }
+ }
+ 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;
}
-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);
+// Helper functions.
+bool Font::has_char(char32_t p_char) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
return true;
}
- 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 false;
}
-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));
- }
- 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));
+String Font::get_supported_chars() const {
+ if (dirty_rids) {
+ _update_rids();
}
- 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));
- }
-
- 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 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;
- 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() {
+}
+
+/*************************************************************************/
+/* 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_antialiasing(cache[p_cache_index], antialiasing);
+ 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();
@@ -508,7 +638,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();
@@ -608,7 +738,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();
@@ -664,7 +794,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();
@@ -693,7 +823,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();
@@ -736,12 +866,480 @@ 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_antialiasing", "antialiasing"), &FontFile::set_antialiasing);
+ ClassDB::bind_method(D_METHOD("get_antialiasing"), &FontFile::get_antialiasing);
+
+ 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::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing");
+ 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) + "/";
+ TypedArray<Vector2i> 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));
+ }
+ PackedInt32Array 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) {
+ TypedArray<Vector2i> 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();
+
+ antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
+ 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;
+ antialiasing = TextServer::FONT_ANTIALIASING_NONE;
mipmaps = false;
msdf = false;
force_autohinter = false;
@@ -755,7 +1353,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;
@@ -781,10 +1379,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
@@ -830,7 +1428,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
while (!f->eof_reached() && f->get_position() <= off + block_size) {
if (c == '\0') {
String base_dir = p_path.get_base_dir();
- String file = base_dir.plus_file(String::utf8(cs.ptr(), cs.length()));
+ String file = base_dir.path_join(String::utf8(cs.ptr(), cs.length()));
if (RenderingServer::get_singleton() != nullptr) {
Ref<Image> img;
img.instantiate();
@@ -1011,12 +1609,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")) {
@@ -1063,7 +1661,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
}
if (keys.has("file")) {
String base_dir = p_path.get_base_dir();
- String file = base_dir.plus_file(keys["file"]);
+ String file = base_dir.path_join(keys["file"]);
if (RenderingServer::get_singleton() != nullptr) {
Ref<Image> img;
img.instantiate();
@@ -1201,13 +1799,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);
@@ -1216,35 +1814,31 @@ 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;
- if (data_ptr != nullptr) {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->font_set_data_ptr(cache[i], data_ptr, data_size);
- }
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->font_set_data_ptr(cache[i], data_ptr, data_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();
- if (data_ptr != nullptr) {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->font_set_data_ptr(cache[i], data_ptr, data_size);
- }
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->font_set_data_ptr(cache[i], data_ptr, data_size);
}
}
}
-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);
@@ -1253,52 +1847,37 @@ 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) {
- if (antialiased != p_antialiased) {
- antialiased = p_antialiased;
+void FontFile::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) {
+ if (antialiasing != p_antialiasing) {
+ antialiasing = p_antialiasing;
for (int i = 0; i < cache.size(); i++) {
_ensure_rid(i);
- TS->font_set_antialiased(cache[i], antialiased);
+ TS->font_set_antialiasing(cache[i], antialiasing);
}
emit_changed();
}
}
-bool FontData::is_antialiased() const {
- return antialiased;
+TextServer::FontAntialiasing FontFile::get_antialiasing() const {
+ return antialiasing;
}
-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++) {
@@ -1309,11 +1888,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++) {
@@ -1324,11 +1903,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++) {
@@ -1339,11 +1918,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++) {
@@ -1354,11 +1933,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++) {
@@ -1369,11 +1948,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++) {
@@ -1384,11 +1963,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++) {
@@ -1399,11 +1978,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++) {
@@ -1414,41 +1993,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++) {
@@ -1459,17 +2008,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];
@@ -1505,19 +2057,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]);
@@ -1526,952 +2087,997 @@ void FontData::remove_cache(int p_cache_index) {
emit_changed();
}
-Array FontData::get_size_cache_list(int p_cache_index) const {
+TypedArray<Vector2i> 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 {
- ERR_FAIL_COND_V(p_cache_index < 0, Array());
+PackedInt32Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
_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 {
+TypedArray<Vector2i> 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]);
+FontFile::FontFile() {
}
-Dictionary FontData::get_supported_variation_list() const {
- _ensure_rid(0);
- return TS->font_supported_variation_list(cache[0]);
-}
-
-FontData::FontData() {
- /* NOP */
-}
-
-FontData::~FontData() {
+FontFile::~FontFile() {
_clear_cache();
}
/*************************************************************************/
+/* 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"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom"), "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();
}
- 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());
+ if (base_font.is_valid()) {
+ return base_font;
+ }
+
+ // Check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ List<StringName> theme_types;
+ ThemeDB::get_singleton()->get_project_theme()->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 (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->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();
-}
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ if (ThemeDB::get_singleton()->get_default_theme().is_valid()) {
+ List<StringName> theme_types;
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
-void Font::set_data(int p_idx, const Ref<FontData> &p_data) {
- ERR_FAIL_COND(p_data.is_null());
- ERR_FAIL_INDEX(p_idx, data.size());
-
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
- }
-
- data.write[p_idx] = p_data;
- rids.write[p_idx] = RID();
- Dictionary data_var_list = p_data->get_supported_variation_list();
- for (int j = 0; j < data_var_list.size(); j++) {
- int32_t tag = data_var_list.get_key_at_index(j);
- Vector3i value = data_var_list.get_value_at_index(j);
- if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
- variation_coordinates[TS->tag_to_name(tag)] = value.z;
+ for (const StringName &E : theme_types) {
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->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 = ThemeDB::get_singleton()->get_default_theme()->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() {
}
-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_antialiasing", "antialiasing"), &SystemFont::set_antialiasing);
+ ClassDB::bind_method(D_METHOD("get_antialiasing"), &SystemFont::get_antialiasing);
- uint64_t hash = p_text.hash64();
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_flags, hash);
- }
- hash = hash_djb2_one_64(p_size, hash);
+ 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_multichannel_signed_distance_field", "msdf"), &SystemFont::set_multichannel_signed_distance_field);
+ ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &SystemFont::is_multichannel_signed_distance_field);
+
+ 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::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing");
+ 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::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
+ 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_djb2_one_float(p_width), hash);
- wrp_hash = hash_djb2_one_64(p_flags, wrp_hash);
- wrp_hash = hash_djb2_one_64(p_size, wrp_hash);
+ 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_antialiasing(antialiasing);
+ file->set_generate_mipmaps(mipmaps);
+ file->set_force_autohinter(force_autohinter);
+ file->set_hinting(hinting);
+ file->set_subpixel_positioning(subpixel_positioning);
+ file->set_multichannel_signed_distance_field(msdf);
+ file->set_oversampling(oversampling);
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
+ base_font = file;
+
+ break;
}
- uint64_t hash = p_text.hash64();
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_flags, hash);
+ 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;
+ antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
+ mipmaps = false;
+ force_autohinter = false;
+ hinting = TextServer::HINTING_LIGHT;
+ subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
+ oversampling = 0.f;
+ msdf = false;
- 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_djb2_one_float(p_width), hash);
- wrp_hash = hash_djb2_one_64(p_flags, wrp_hash);
- wrp_hash = hash_djb2_one_64(p_size, wrp_hash);
+ // Check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ List<StringName> theme_types;
+ ThemeDB::get_singleton()->get_project_theme()->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 (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->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 (ThemeDB::get_singleton()->get_default_theme().is_valid()) {
+ List<StringName> theme_types;
+ ThemeDB::get_singleton()->get_default_theme()->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 (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->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 = ThemeDB::get_singleton()->get_default_theme()->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_antialiasing(TextServer::FontAntialiasing p_antialiasing) {
+ if (antialiasing != p_antialiasing) {
+ antialiasing = p_antialiasing;
+ if (base_font.is_valid()) {
+ base_font->set_antialiasing(antialiasing);
}
- 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;
+TextServer::FontAntialiasing SystemFont::get_antialiasing() const {
+ return antialiasing;
+}
+
+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();
+ }
+}
- if ((p_max_lines > 0) && (i >= p_max_lines)) {
- return;
+bool SystemFont::get_generate_mipmaps() const {
+ return mipmaps;
+}
+
+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_multichannel_signed_distance_field(bool p_msdf) {
+ if (msdf != p_msdf) {
+ msdf = p_msdf;
+ if (base_font.is_valid()) {
+ base_font->set_multichannel_signed_distance_field(msdf);
}
+ 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];
- }
+bool SystemFont::is_multichannel_signed_distance_field() const {
+ return msdf;
+}
+
+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 chars;
}
-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]);
+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 _rids;
+ return RID();
}
-void Font::update_changes() {
- emit_changed();
+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 RID();
}
-Font::Font() {
- cache.set_capacity(128);
- cache_wrap.set_capacity(32);
+int64_t SystemFont::get_face_count() const {
+ return face_indeces.size();
}
-Font::~Font() {
- clear_data();
- cache.clear();
- cache_wrap.clear();
+SystemFont::SystemFont() {
+ /* NOP */
+}
+
+SystemFont::~SystemFont() {
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 96bfe3678b..5cf596b41d 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -37,10 +37,103 @@
#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.
@@ -48,7 +141,7 @@ class FontData : public Resource {
size_t data_size = 0;
PackedByteArray data;
- bool antialiased = true;
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
bool mipmaps = false;
bool msdf = false;
int msdf_pixel_range = 16;
@@ -58,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;
@@ -93,16 +189,11 @@ public:
// 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(BitField<TextServer::FontStyle> p_style);
- virtual void set_font_style(uint32_t p_style);
- virtual uint32_t get_font_style() const;
-
- virtual void set_antialiased(bool p_antialiased);
- virtual bool is_antialiased() const;
+ virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing);
+ virtual TextServer::FontAntialiasing get_antialiasing() const;
virtual void set_generate_mipmaps(bool p_generate_mipmaps);
virtual bool get_generate_mipmaps() const;
@@ -128,46 +219,47 @@ 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();
virtual void remove_cache(int p_cache_index);
- virtual Array get_size_cache_list(int p_cache_index) const;
+ virtual TypedArray<Vector2i> get_size_cache_list(int p_cache_index) const;
virtual void clear_size_cache(int p_cache_index);
virtual void remove_size_cache(int p_cache_index, const Vector2i &p_size);
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);
@@ -179,7 +271,7 @@ public:
virtual void set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset);
virtual PackedInt32Array get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const;
- virtual Array get_glyph_list(int p_cache_index, const Vector2i &p_size) const;
+ virtual PackedInt32Array get_glyph_list(int p_cache_index, const Vector2i &p_size) const;
virtual void clear_glyphs(int p_cache_index, const Vector2i &p_size);
virtual void remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph);
@@ -198,7 +290,7 @@ public:
virtual void set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx);
virtual int get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const;
- virtual Array get_kerning_list(int p_cache_index, int p_size) const;
+ virtual TypedArray<Vector2i> get_kerning_list(int p_cache_index, int p_size) const;
virtual void clear_kerning_map(int p_cache_index, int p_size);
virtual void remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair);
@@ -208,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);
@@ -227,100 +315,144 @@ public:
virtual Dictionary get_opentype_feature_overrides() const;
// Base font properties.
- virtual bool has_char(char32_t p_char) const;
- virtual String get_supported_chars() const;
-
virtual int32_t get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector = 0x0000) const;
- virtual Dictionary get_supported_feature_list() const;
- virtual Dictionary get_supported_variation_list() const;
-
- FontData();
- ~FontData();
+ FontFile();
+ ~FontFile();
};
/*************************************************************************/
+/* FontVariation */
+/*************************************************************************/
-class TextLine;
-class TextParagraph;
+class FontVariation : public Font {
+ GDCLASS(FontVariation, Font);
-class Font : public Resource {
- GDCLASS(Font, Resource);
+ struct Variation {
+ Dictionary opentype;
+ real_t embolden = 0.f;
+ int face_index = 0;
+ Transform2D transform;
+ };
- // Shaped string cache.
- mutable LRUCache<uint64_t, Ref<TextLine>> cache;
- mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
-
- // Font data cache.
- Vector<Ref<FontData>> data;
- mutable Vector<RID> rids;
+ mutable Ref<Font> theme_font;
- // Font config.
- Dictionary variation_coordinates;
- int spacing_bottom = 0;
- int spacing_top = 0;
+ Ref<Font> base_font;
- _FORCE_INLINE_ void _data_changed();
- _FORCE_INLINE_ void _ensure_rid(int p_index) const; // Find or create cache record.
+ Variation variation;
+ Dictionary opentype_features;
+ int extra_spacing[TextServer::SPACING_MAX];
protected:
static void _bind_methods();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void _update_rids() const override;
virtual void reset_state() override;
public:
- static const int DEFAULT_FONT_SIZE = 16;
+ 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;
+
+ virtual void set_variation_opentype(const Dictionary &p_coords);
+ virtual Dictionary get_variation_opentype() const;
- Dictionary get_feature_list() const;
+ virtual void set_variation_embolden(float p_strength);
+ virtual float get_variation_embolden() 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_transform(Transform2D p_transform);
+ virtual Transform2D get_variation_transform() const;
- // Font configuration.
- virtual void set_variation_coordinates(const Dictionary &p_variation_coordinates);
- virtual Dictionary get_variation_coordinates() 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();
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
+ 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;
+ bool msdf = false;
+
+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_antialiasing(TextServer::FontAntialiasing p_antialiasing);
+ virtual TextServer::FontAntialiasing get_antialiasing() 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_multichannel_signed_distance_field(bool p_msdf);
+ virtual bool is_multichannel_signed_distance_field() 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.cpp b/scene/resources/gradient.cpp
index a9c44dc6bf..f04eb75d86 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -56,7 +56,7 @@ void Gradient::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color);
ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color);
- ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Gradient::get_color_at_offset);
+ ClassDB::bind_method(D_METHOD("sample", "offset"), &Gradient::get_color_at_offset);
ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count);
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index a3d3449099..2b91331ab0 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -92,10 +92,6 @@ public:
void set_interpolation_mode(InterpolationMode p_interp_mode);
InterpolationMode get_interpolation_mode();
- _FORCE_INLINE_ float cubic_interpolate(float p0, float p1, float p2, float p3, float x) {
- return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
- }
-
_FORCE_INLINE_ Color get_color_at_offset(float p_offset) {
if (points.is_empty()) {
return Color(0, 0, 0, 1);
@@ -126,7 +122,7 @@ public:
}
}
- // Return interpolated value.
+ // Return sampled value.
if (points[middle].offset > p_offset) {
middle--;
}
@@ -161,10 +157,10 @@ public:
const Point &pointP3 = points[p3];
float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset);
- float r = cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
- float g = cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
- float b = cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
- float a = cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
+ float r = Math::cubic_interpolate(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.cpp b/scene/resources/immediate_mesh.cpp
index 044477e744..90cc3ea5f4 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -340,8 +340,8 @@ Array ImmediateMesh::surface_get_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, int(surfaces.size()), Array());
return RS::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
}
-Array ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const {
- return Array();
+TypedArray<Array> ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const {
+ return TypedArray<Array>();
}
Dictionary ImmediateMesh::surface_get_lods(int p_surface) const {
return Dictionary();
diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h
index e5f627ae8e..0dad62f555 100644
--- a/scene/resources/immediate_mesh.h
+++ b/scene/resources/immediate_mesh.h
@@ -97,7 +97,7 @@ public:
virtual int surface_get_array_len(int p_idx) const override;
virtual int surface_get_array_index_len(int p_idx) const override;
virtual Array surface_get_arrays(int p_surface) const override;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const override;
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
virtual Dictionary surface_get_lods(int p_surface) const override;
virtual uint32_t surface_get_format(int p_idx) const override;
virtual PrimitiveType surface_get_primitive_type(int p_idx) const override;
@@ -115,4 +115,4 @@ public:
~ImmediateMesh();
};
-#endif // IMMEDIATEMESH_H
+#endif // IMMEDIATE_MESH_H
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 0fbd29b1a6..de3d502102 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -154,7 +154,7 @@ Mesh::BlendShapeMode ImporterMesh::get_blend_shape_mode() const {
return blend_shape_mode;
}
-void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
+void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX);
Surface s;
@@ -254,7 +254,20 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma
mesh.unref();
}
-void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) {
+#define VERTEX_SKIN_FUNC(bone_count, vert_idx, read_array, write_array, transform_array, bone_array, weight_array) \
+ Vector3 transformed_vert = Vector3(); \
+ for (unsigned int weight_idx = 0; weight_idx < bone_count; weight_idx++) { \
+ int bone_idx = bone_array[vert_idx * bone_count + weight_idx]; \
+ float w = weight_array[vert_idx * bone_count + weight_idx]; \
+ if (w < FLT_EPSILON) { \
+ continue; \
+ } \
+ ERR_FAIL_INDEX(bone_idx, static_cast<int>(transform_array.size())); \
+ transformed_vert += transform_array[bone_idx].xform(read_array[vert_idx]) * w; \
+ } \
+ write_array[vert_idx] = transformed_vert;
+
+void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array) {
if (!SurfaceTool::simplify_scale_func) {
return;
}
@@ -265,6 +278,12 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
return;
}
+ LocalVector<Transform3D> bone_transform_vector;
+ for (int i = 0; i < p_bone_transform_array.size(); i++) {
+ ERR_FAIL_COND(p_bone_transform_array[i].get_type() != Variant::TRANSFORM3D);
+ bone_transform_vector.push_back(p_bone_transform_array[i]);
+ }
+
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
continue;
@@ -276,6 +295,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
Vector<Vector3> normals = surfaces[i].arrays[RS::ARRAY_NORMAL];
Vector<Vector2> uvs = surfaces[i].arrays[RS::ARRAY_TEX_UV];
Vector<Vector2> uv2s = surfaces[i].arrays[RS::ARRAY_TEX_UV2];
+ Vector<int> bones = surfaces[i].arrays[RS::ARRAY_BONES];
+ Vector<float> weights = surfaces[i].arrays[RS::ARRAY_WEIGHTS];
unsigned int index_count = indices.size();
unsigned int vertex_count = vertices.size();
@@ -301,9 +322,25 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
- float normal_merge_threshold = Math::cos(Math::deg2rad(p_normal_merge_angle));
- float normal_pre_split_threshold = Math::cos(Math::deg2rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
- float normal_split_threshold = Math::cos(Math::deg2rad(p_normal_split_angle));
+ if (bones.size() > 0 && weights.size() && bone_transform_vector.size() > 0) {
+ Vector3 *vertices_ptrw = vertices.ptrw();
+
+ // Apply bone transforms to regular surface.
+ unsigned int bone_weight_length = surfaces[i].flags & Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS ? 8 : 4;
+
+ const int *bo = bones.ptr();
+ const float *we = weights.ptr();
+
+ for (unsigned int j = 0; j < vertex_count; j++) {
+ VERTEX_SKIN_FUNC(bone_weight_length, j, vertices_ptr, vertices_ptrw, bone_transform_vector, bo, we)
+ }
+
+ vertices_ptr = vertices.ptr();
+ }
+
+ float normal_merge_threshold = Math::cos(Math::deg_to_rad(p_normal_merge_angle));
+ float normal_pre_split_threshold = Math::cos(Math::deg_to_rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
+ float normal_split_threshold = Math::cos(Math::deg_to_rad(p_normal_split_angle));
const Vector3 *normals_ptr = normals.ptr();
HashMap<Vector3, LocalVector<Pair<int, int>>> unique_vertices;
@@ -331,6 +368,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
bool is_uvs_close = (!uvs_ptr || uvs_ptr[j].distance_squared_to(uvs_ptr[idx.second]) < CMP_EPSILON2);
bool is_uv2s_close = (!uv2s_ptr || uv2s_ptr[j].distance_squared_to(uv2s_ptr[idx.second]) < CMP_EPSILON2);
+ ERR_FAIL_INDEX(idx.second, normals.size());
bool is_normals_close = normals[idx.second].dot(n) > normal_merge_threshold;
if (is_uvs_close && is_uv2s_close && is_normals_close) {
vertex_remap.push_back(idx.first);
@@ -1046,6 +1084,10 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
+ if (!rnormals.size()) {
+ continue;
+ }
+
int vertex_ofs = vertices.size() / 3;
vertices.resize((vertex_ofs + vc) * 3);
@@ -1086,6 +1128,9 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
} else {
for (int j = 0; j < ic / 3; j++) {
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 0], rvertices.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 1], rvertices.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 2], rvertices.size(), ERR_INVALID_DATA);
Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
@@ -1185,7 +1230,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
surfaces_tools[i]->index();
Array arrays = surfaces_tools[i]->commit_to_arrays();
- add_surface(surfaces_tools[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
+ add_surface(surfaces_tools[i]->get_primitive_type(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
}
set_lightmap_size_hint(Size2(size_x, size_y));
@@ -1222,7 +1267,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ImporterMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ImporterMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(TypedArray<Array>()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_surface_count"), &ImporterMesh::get_surface_count);
ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &ImporterMesh::get_surface_primitive_type);
@@ -1238,6 +1283,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
+ ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::generate_lods);
ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h
index 8f77597a58..088a77edd1 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"
@@ -93,7 +93,7 @@ public:
int get_blend_shape_count() const;
String get_blend_shape_name(int p_blend_shape) const;
- void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint32_t p_flags = 0);
+ void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint32_t p_flags = 0);
int get_surface_count() const;
void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode);
@@ -112,7 +112,7 @@ public:
void set_surface_material(int p_surface, const Ref<Material> &p_material);
- void generate_lods(float p_normal_merge_angle, float p_normal_split_angle);
+ void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
void create_shadow_mesh();
Ref<ImporterMesh> get_shadow_mesh() const;
@@ -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..062d499d50
--- /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 = 3;
+
+ Ref<Font> font;
+ int font_size = Font::DEFAULT_FONT_SIZE;
+ Color font_color = Color(1, 1, 1);
+
+ int outline_size = 0;
+ Color outline_color = Color(1, 1, 1);
+
+ int shadow_size = 1;
+ Color shadow_color = Color(0, 0, 0, 0);
+ 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 8abdfe713f..c1e30dd93c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -31,6 +31,8 @@
#include "material.h"
#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/error/error_macros.h"
#include "core/version.h"
#include "scene/main/scene_tree.h"
#include "scene/scene_string_names.h"
@@ -71,12 +73,12 @@ RID Material::get_rid() const {
return material;
}
-void Material::_validate_property(PropertyInfo &property) const {
- if (!_can_do_next_pass() && property.name == "next_pass") {
- property.usage = PROPERTY_USAGE_NONE;
+void Material::_validate_property(PropertyInfo &p_property) const {
+ if (!_can_do_next_pass() && p_property.name == "next_pass") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (!_can_use_render_priority() && property.name == "render_priority") {
- property.usage = PROPERTY_USAGE_NONE;
+ if (!_can_use_render_priority() && p_property.name == "render_priority") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -154,18 +156,9 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- if (n.find("shader_param/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_param/", "");
- }
- }
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
- set_shader_param(pr, p_value);
+ set_shader_parameter(pr, p_value);
return true;
}
}
@@ -175,24 +168,9 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- if (n.find("shader_param/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_param/", "");
- }
- }
-
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
- HashMap<StringName, Variant>::ConstIterator E = param_cache.find(pr);
- if (E) {
- r_ret = E->value;
- } else {
- r_ret = Variant();
- }
+ r_ret = get_shader_parameter(pr);
return true;
}
}
@@ -202,15 +180,111 @@ 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_shader_uniform_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.capitalize();
+ info.hint_string = "shader_parameter/";
+
+ 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.capitalize();
+ info.hint_string = "shader_parameter/";
+
+ 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 Parameters";
+ info.hint_string = "shader_parameter/";
+ groups["<None>"]["<None>"].push_back(info);
+ }
+
+ PropertyInfo info = E->get();
+ info.name = "shader_parameter/" + info.name;
+ groups[last_group][last_subgroup].push_back(info);
+ }
+
+ List<String> group_names;
+ for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
+ group_names.push_back(group->key);
+ }
+ group_names.sort();
+
+ for (const String &group_name : group_names) {
+ List<String> subgroup_names;
+ HashMap<String, List<PropertyInfo>> &subgroups = groups[group_name];
+ for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = subgroups.begin(); subgroup; ++subgroup) {
+ subgroup_names.push_back(subgroup->key);
+ }
+ subgroup_names.sort();
+ for (const String &subgroup_name : subgroup_names) {
+ List<PropertyInfo> &prop_infos = subgroups[subgroup_name];
+ for (List<PropertyInfo>::Element *item = prop_infos.front(); item; item = item->next()) {
+ p_list->push_back(item->get());
+ }
+ }
+ }
}
}
-bool ShaderMaterial::property_can_revert(const String &p_name) {
+bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
- Variant default_value = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
Variant current_value;
_get(p_name, current_value);
return default_value.get_type() != Variant::NIL && default_value != current_value;
@@ -219,15 +293,15 @@ bool ShaderMaterial::property_can_revert(const String &p_name) {
return false;
}
-Variant ShaderMaterial::property_get_revert(const String &p_name) {
- Variant r_ret;
+bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
- r_ret = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
+ return true;
}
}
- return r_ret;
+ return false;
}
void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
@@ -258,7 +332,7 @@ Ref<Shader> ShaderMaterial::get_shader() const {
return shader;
}
-void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) {
+void ShaderMaterial::set_shader_parameter(const StringName &p_param, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
param_cache.erase(p_param);
RS::get_singleton()->material_set_param(_get_material(), p_param, Variant());
@@ -278,7 +352,7 @@ void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &
}
}
-Variant ShaderMaterial::get_shader_param(const StringName &p_param) const {
+Variant ShaderMaterial::get_shader_parameter(const StringName &p_param) const {
if (param_cache.has(p_param)) {
return param_cache[p_param];
} else {
@@ -293,22 +367,20 @@ void ShaderMaterial::_shader_changed() {
void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader);
ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader);
- ClassDB::bind_method(D_METHOD("set_shader_param", "param", "value"), &ShaderMaterial::set_shader_param);
- ClassDB::bind_method(D_METHOD("get_shader_param", "param"), &ShaderMaterial::get_shader_param);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ShaderMaterial::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ShaderMaterial::property_get_revert);
+ ClassDB::bind_method(D_METHOD("set_shader_parameter", "param", "value"), &ShaderMaterial::set_shader_parameter);
+ ClassDB::bind_method(D_METHOD("get_shader_parameter", "param"), &ShaderMaterial::get_shader_parameter);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader");
}
void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
String f = p_function.operator String();
- if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) {
+ if ((f == "get_shader_parameter" || f == "set_shader_parameter") && p_idx == 0) {
if (shader.is_valid()) {
List<PropertyInfo> pl;
- shader->get_param_list(&pl);
+ shader->get_shader_uniform_list(&pl);
for (const PropertyInfo &E : pl) {
- r_options->push_back(E.name.replace_first("shader_param/", "").quote());
+ r_options->push_back(E.name.replace_first("shader_parameter/", "").quote());
}
}
}
@@ -472,24 +544,33 @@ void BaseMaterial3D::_update_shader() {
}
String texfilter_str;
+ // Force linear filtering for the heightmap texture, as the heightmap effect
+ // looks broken with nearest-neighbor filtering (with and without Deep Parallax).
+ String texfilter_height_str;
switch (texture_filter) {
case TEXTURE_FILTER_NEAREST:
texfilter_str = "filter_nearest";
+ texfilter_height_str = "filter_linear";
break;
case TEXTURE_FILTER_LINEAR:
texfilter_str = "filter_linear";
+ texfilter_height_str = "filter_linear";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
texfilter_str = "filter_nearest_mipmap";
+ texfilter_height_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
texfilter_str = "filter_linear_mipmap";
+ texfilter_height_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC:
texfilter_str = "filter_nearest_mipmap_anisotropic";
+ texfilter_height_str = "filter_linear_mipmap_anisotropic";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC:
texfilter_str = "filter_linear_mipmap_anisotropic";
+ texfilter_height_str = "filter_linear_mipmap_anisotropic";
break;
case TEXTURE_FILTER_MAX:
break; // Internal value, skip.
@@ -497,8 +578,10 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_USE_TEXTURE_REPEAT]) {
texfilter_str += ",repeat_enable";
+ texfilter_height_str += ",repeat_enable";
} else {
texfilter_str += ",repeat_disable";
+ texfilter_height_str += ",repeat_disable";
}
//must create a shader!
@@ -631,8 +714,8 @@ void BaseMaterial3D::_update_shader() {
code += ";\n";
- code += "uniform vec4 albedo : hint_color;\n";
- code += "uniform sampler2D texture_albedo : hint_albedo," + texfilter_str + ";\n";
+ code += "uniform vec4 albedo : source_color;\n";
+ code += "uniform sampler2D texture_albedo : source_color," + texfilter_str + ";\n";
if (grow_enabled) {
code += "uniform float grow;\n";
}
@@ -669,7 +752,7 @@ void BaseMaterial3D::_update_shader() {
//TODO ALL HINTS
if (!orm) {
code += "uniform float roughness : hint_range(0,1);\n";
- code += "uniform sampler2D texture_metallic : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_metallic : hint_default_white," + texfilter_str + ";\n";
code += "uniform vec4 metallic_texture_channel;\n";
switch (roughness_texture_channel) {
case TEXTURE_CHANNEL_RED: {
@@ -704,8 +787,8 @@ void BaseMaterial3D::_update_shader() {
}
if (features[FEATURE_EMISSION]) {
- code += "uniform sampler2D texture_emission : hint_black_albedo," + texfilter_str + ";\n";
- code += "uniform vec4 emission : hint_color;\n";
+ code += "uniform sampler2D texture_emission : source_color, hint_default_black," + texfilter_str + ";\n";
+ code += "uniform vec4 emission : source_color;\n";
code += "uniform float emission_energy;\n";
}
@@ -722,48 +805,48 @@ void BaseMaterial3D::_update_shader() {
if (features[FEATURE_RIM]) {
code += "uniform float rim : hint_range(0,1);\n";
code += "uniform float rim_tint : hint_range(0,1);\n";
- code += "uniform sampler2D texture_rim : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_rim : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_CLEARCOAT]) {
code += "uniform float clearcoat : hint_range(0,1);\n";
code += "uniform float clearcoat_roughness : hint_range(0,1);\n";
- code += "uniform sampler2D texture_clearcoat : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_clearcoat : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_ANISOTROPY]) {
code += "uniform float anisotropy_ratio : hint_range(0,256);\n";
code += "uniform sampler2D texture_flowmap : hint_anisotropy," + texfilter_str + ";\n";
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
- code += "uniform sampler2D texture_ambient_occlusion : hint_white, " + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_ambient_occlusion : hint_default_white, " + texfilter_str + ";\n";
code += "uniform vec4 ao_texture_channel;\n";
code += "uniform float ao_light_affect;\n";
}
if (features[FEATURE_DETAIL]) {
- code += "uniform sampler2D texture_detail_albedo : hint_albedo," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_detail_albedo : source_color," + texfilter_str + ";\n";
code += "uniform sampler2D texture_detail_normal : hint_normal," + texfilter_str + ";\n";
- code += "uniform sampler2D texture_detail_mask : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_detail_mask : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_SUBSURFACE_SCATTERING]) {
code += "uniform float subsurface_scattering_strength : hint_range(0,1);\n";
- code += "uniform sampler2D texture_subsurface_scattering : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_subsurface_scattering : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) {
- code += "uniform vec4 transmittance_color : hint_color;\n";
+ code += "uniform vec4 transmittance_color : source_color;\n";
code += "uniform float transmittance_depth;\n";
- code += "uniform sampler2D texture_subsurface_transmittance : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_subsurface_transmittance : hint_default_white," + texfilter_str + ";\n";
code += "uniform float transmittance_boost;\n";
}
if (features[FEATURE_BACKLIGHT]) {
- code += "uniform vec4 backlight : hint_color;\n";
- code += "uniform sampler2D texture_backlight : hint_black," + texfilter_str + ";\n";
+ code += "uniform vec4 backlight : source_color;\n";
+ code += "uniform sampler2D texture_backlight : hint_default_black," + texfilter_str + ";\n";
}
if (features[FEATURE_HEIGHT_MAPPING]) {
- code += "uniform sampler2D texture_heightmap : hint_black," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_heightmap : hint_default_black," + texfilter_height_str + ";\n";
code += "uniform float heightmap_scale;\n";
code += "uniform int heightmap_min_layers;\n";
code += "uniform int heightmap_max_layers;\n";
@@ -820,6 +903,7 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_FIXED_Y: {
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);\n";
@@ -827,6 +911,7 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_PARTICLES: {
//make billboard
@@ -835,6 +920,8 @@ void BaseMaterial3D::_update_shader() {
code += " mat_world = mat_world * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
//set modelview
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat_world;\n";
+ //set modelview normal
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
//handle animation
code += " float h_frames = float(particles_anim_h_frames);\n";
@@ -845,7 +932,7 @@ void BaseMaterial3D::_update_shader() {
code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
code += " } else {\n";
code += " particle_frame = mod(particle_frame, particle_total_frames);\n";
- code += " }";
+ code += " }\n";
code += " UV /= vec2(h_frames, v_frames);\n";
code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames);\n";
} break;
@@ -965,7 +1052,8 @@ void BaseMaterial3D::_update_shader() {
code += " float num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n";
code += " float layer_depth = 1.0 / num_layers;\n";
code += " float current_layer_depth = 0.0;\n";
- code += " vec2 P = view_dir.xy * heightmap_scale;\n";
+ // Multiply the heightmap scale by 0.01 to improve heightmap scale usability.
+ code += " vec2 P = view_dir.xy * heightmap_scale * 0.01;\n";
code += " vec2 delta = P / num_layers;\n";
code += " vec2 ofs = base_uv;\n";
if (flags[FLAG_INVERT_HEIGHTMAP]) {
@@ -1001,7 +1089,8 @@ void BaseMaterial3D::_update_shader() {
}
// Use offset limiting to improve the appearance of non-deep parallax.
// This reduces the impression of depth, but avoids visible warping in the distance.
- code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale;\n";
+ // Multiply the heightmap scale by 0.01 to improve heightmap scale usability.
+ code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale * 0.01;\n";
}
code += " base_uv=ofs;\n";
@@ -1174,38 +1263,21 @@ void BaseMaterial3D::_update_shader() {
if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) {
if (!RenderingServer::get_singleton()->is_low_end()) {
code += " {\n";
+
if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
code += " float fade_distance = abs((VIEW_MATRIX * MODEL_MATRIX[3]).z);\n";
} else {
- code += " float fade_distance=-VERTEX.z;\n";
+ code += " float fade_distance = -VERTEX.z;\n";
}
+ // Use interleaved gradient noise, which is fast but still looks good.
+ code += " const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);";
+ code += " float fade = clamp(smoothstep(distance_fade_min, distance_fade_max, fade_distance), 0.0, 1.0);\n";
+ // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance.
+ code += " if (fade < 0.001 || fade < fract(magic.z * fract(dot(FRAGCOORD.xy, magic.xy)))) {\n";
+ code += " discard;\n";
+ code += " }\n";
- code += " float fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n";
- code += " int x = int(FRAGCOORD.x) % 4;\n";
- code += " int y = int(FRAGCOORD.y) % 4;\n";
- code += " int index = x + y * 4;\n";
- code += " float limit = 0.0;\n\n";
- code += " if (x < 8) {\n";
- code += " if (index == 0) limit = 0.0625;\n";
- code += " if (index == 1) limit = 0.5625;\n";
- code += " if (index == 2) limit = 0.1875;\n";
- code += " if (index == 3) limit = 0.6875;\n";
- code += " if (index == 4) limit = 0.8125;\n";
- code += " if (index == 5) limit = 0.3125;\n";
- code += " if (index == 6) limit = 0.9375;\n";
- code += " if (index == 7) limit = 0.4375;\n";
- code += " if (index == 8) limit = 0.25;\n";
- code += " if (index == 9) limit = 0.75;\n";
- code += " if (index == 10) limit = 0.125;\n";
- code += " if (index == 11) limit = 0.625;\n";
- code += " if (index == 12) limit = 1.0;\n";
- code += " if (index == 13) limit = 0.5;\n";
- code += " if (index == 14) limit = 0.875;\n";
- code += " if (index == 15) limit = 0.375;\n";
- code += " }\n\n";
- code += " if (fade < limit)\n";
- code += " discard;\n";
code += " }\n\n";
}
@@ -1419,13 +1491,27 @@ Color BaseMaterial3D::get_emission() const {
return emission;
}
-void BaseMaterial3D::set_emission_energy(float p_emission_energy) {
- emission_energy = p_emission_energy;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy);
+void BaseMaterial3D::set_emission_energy_multiplier(float p_emission_energy_multiplier) {
+ emission_energy_multiplier = p_emission_energy_multiplier;
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity);
+ } else {
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier);
+ }
+}
+
+float BaseMaterial3D::get_emission_energy_multiplier() const {
+ return emission_energy_multiplier;
+}
+
+void BaseMaterial3D::set_emission_intensity(float p_emission_intensity) {
+ ERR_FAIL_COND_EDMSG(!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"), "Cannot set material emission intensity when Physical Light Units disabled.");
+ emission_intensity = p_emission_intensity;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, emission_energy_multiplier * emission_intensity);
}
-float BaseMaterial3D::get_emission_energy() const {
- return emission_energy;
+float BaseMaterial3D::get_emission_intensity() const {
+ return emission_intensity;
}
void BaseMaterial3D::set_normal_scale(float p_normal_scale) {
@@ -1691,12 +1777,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();
}
@@ -1773,55 +1868,65 @@ void BaseMaterial3D::_validate_high_end(const String &text, PropertyInfo &proper
}
}
-void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
- _validate_feature("normal", FEATURE_NORMAL_MAPPING, property);
- _validate_feature("emission", FEATURE_EMISSION, property);
- _validate_feature("rim", FEATURE_RIM, property);
- _validate_feature("clearcoat", FEATURE_CLEARCOAT, property);
- _validate_feature("anisotropy", FEATURE_ANISOTROPY, property);
- _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, property);
- _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, property);
- _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, property);
- _validate_feature("backlight", FEATURE_BACKLIGHT, property);
- _validate_feature("refraction", FEATURE_REFRACTION, property);
- _validate_feature("detail", FEATURE_DETAIL, property);
+void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
+ _validate_feature("normal", FEATURE_NORMAL_MAPPING, p_property);
+ _validate_feature("emission", FEATURE_EMISSION, p_property);
+ _validate_feature("rim", FEATURE_RIM, p_property);
+ _validate_feature("clearcoat", FEATURE_CLEARCOAT, p_property);
+ _validate_feature("anisotropy", FEATURE_ANISOTROPY, p_property);
+ _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, p_property);
+ _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, p_property);
+ _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, p_property);
+ _validate_feature("backlight", FEATURE_BACKLIGHT, p_property);
+ _validate_feature("refraction", FEATURE_REFRACTION, p_property);
+ _validate_feature("detail", FEATURE_DETAIL, p_property);
- _validate_high_end("refraction", property);
- _validate_high_end("subsurf_scatter", property);
- _validate_high_end("anisotropy", property);
- _validate_high_end("clearcoat", property);
- _validate_high_end("heightmap", property);
+ _validate_high_end("refraction", p_property);
+ _validate_high_end("subsurf_scatter", p_property);
+ _validate_high_end("heightmap", p_property);
- if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "grow_amount" && !grow_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "grow_amount" && !grow_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if ((p_property.name == "distance_fade_max_distance" || p_property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if ((p_property.name == "uv1_triplanar_sharpness" || p_property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if ((p_property.name == "uv2_triplanar_sharpness" || p_property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
// you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash
@@ -1830,96 +1935,96 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa;
// alpha scissor slider isn't needed when alpha antialiasing is enabled
- if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
// alpha hash scale slider is only needed if transparency is alpha hash
- if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "alpha_antialiasing_mode" && !can_select_aa) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_antialiasing_mode" && !can_select_aa) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
// we can't choose an antialiasing mode if alpha isn't possible
- if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "blend_mode" && alpha_aa_enabled) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "blend_mode" && alpha_aa_enabled) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "heightmap_min_layers" || p_property.name == "heightmap_max_layers") && !deep_parallax) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
if (orm) {
- if (property.name == "shading_mode") {
+ if (p_property.name == "shading_mode") {
// Vertex not supported in ORM mode, since no individual roughness.
- property.hint_string = "Unshaded,Per-Pixel";
+ p_property.hint_string = "Unshaded,Per-Pixel";
}
- if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("roughness") || p_property.name.begins_with("metallic") || p_property.name.begins_with("ao_texture")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
} else {
- if (property.name == "orm_texture") {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "orm_texture") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
if (shading_mode != SHADING_MODE_PER_PIXEL) {
if (shading_mode != SHADING_MODE_PER_VERTEX) {
//these may still work per vertex
- if (property.name.begins_with("ao")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("ao")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("metallic")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("metallic")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("rim")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("rim")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("roughness")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("roughness")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("subsurf_scatter")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("subsurf_scatter")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
//these definitely only need per pixel
- if (property.name.begins_with("anisotropy")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("anisotropy")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("clearcoat")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("clearcoat")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("normal")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("normal")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("backlight")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("backlight")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("transmittance")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("transmittance")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -1952,8 +2057,9 @@ Vector3 BaseMaterial3D::get_uv1_offset() const {
}
void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) {
- uv1_triplanar_sharpness = p_sharpness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, p_sharpness);
+ // Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
+ uv1_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
}
float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
@@ -1979,8 +2085,9 @@ Vector3 BaseMaterial3D::get_uv2_offset() const {
}
void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) {
- uv2_triplanar_sharpness = p_sharpness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, p_sharpness);
+ // Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
+ uv2_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
}
float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
@@ -2200,7 +2307,7 @@ Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transpar
if (p_fixed_size) {
hash |= 1 << 9;
}
- hash = hash_djb2_one_64(p_filter, hash);
+ hash = hash_murmur3_one_64(p_filter, hash);
if (materials_for_2d.has(hash)) {
if (r_shader_rid) {
@@ -2361,8 +2468,11 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission", "emission"), &BaseMaterial3D::set_emission);
ClassDB::bind_method(D_METHOD("get_emission"), &BaseMaterial3D::get_emission);
- ClassDB::bind_method(D_METHOD("set_emission_energy", "emission_energy"), &BaseMaterial3D::set_emission_energy);
- ClassDB::bind_method(D_METHOD("get_emission_energy"), &BaseMaterial3D::get_emission_energy);
+ ClassDB::bind_method(D_METHOD("set_emission_energy_multiplier", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_emission_energy_multiplier"), &BaseMaterial3D::get_emission_energy_multiplier);
+
+ ClassDB::bind_method(D_METHOD("set_emission_intensity", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_intensity);
+ ClassDB::bind_method(D_METHOD("get_emission_intensity"), &BaseMaterial3D::get_emission_intensity);
ClassDB::bind_method(D_METHOD("set_normal_scale", "normal_scale"), &BaseMaterial3D::set_normal_scale);
ClassDB::bind_method(D_METHOD("get_normal_scale"), &BaseMaterial3D::get_normal_scale);
@@ -2537,7 +2647,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");
@@ -2559,8 +2669,8 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Albedo", "albedo_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo_color"), "set_albedo", "get_albedo");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "albedo_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_ALBEDO);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_tex_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_tex_msdf"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_MSDF);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_texture_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_texture_msdf"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_MSDF);
ADD_GROUP("ORM", "orm_");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orm_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_ORM);
@@ -2579,12 +2689,14 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Emission", "emission_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy_multiplier", "get_emission_energy_multiplier");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_intensity", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:nt"), "set_emission_intensity", "get_emission_intensity");
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator");
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);
@@ -2624,7 +2736,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);
@@ -2657,14 +2769,14 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_DETAIL_NORMAL);
ADD_GROUP("UV1", "uv1_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale"), "set_uv1_scale", "get_uv1_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale", PROPERTY_HINT_LINK), "set_uv1_scale", "get_uv1_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_offset"), "set_uv1_offset", "get_uv1_offset");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_TRIPLANAR);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv1_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv1_triplanar_blend_sharpness", "get_uv1_triplanar_blend_sharpness");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_world_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_WORLD_TRIPLANAR);
ADD_GROUP("UV2", "uv2_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale"), "set_uv2_scale", "get_uv2_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale", PROPERTY_HINT_LINK), "set_uv2_scale", "get_uv2_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_offset"), "set_uv2_offset", "get_uv2_offset");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_TRIPLANAR);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv2_triplanar_blend_sharpness", "get_uv2_triplanar_blend_sharpness");
@@ -2689,22 +2801,22 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Grow", "grow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "grow"), "set_grow_enabled", "is_grow_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_amount", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_grow", "get_grow");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_amount", PROPERTY_HINT_RANGE, "-16,16,0.001,suffix:m"), "set_grow", "get_grow");
ADD_GROUP("Transform", "");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_point_size"), "set_flag", "get_flag", FLAG_USE_POINT_SIZE);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1,suffix:px"), "set_point_size", "get_point_size");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_proximity_fade_distance", "get_proximity_fade_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("MSDF", "msdf_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_outline_size", PROPERTY_HINT_RANGE, "1,250,1"), "set_msdf_outline_size", "get_msdf_outline_size");
ADD_GROUP("Distance Fade", "distance_fade_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "distance_fade_mode", PROPERTY_HINT_ENUM, "Disabled,PixelAlpha,PixelDither,ObjectDither"), "set_distance_fade", "get_distance_fade");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
BIND_ENUM_CONSTANT(TEXTURE_ALBEDO);
BIND_ENUM_CONSTANT(TEXTURE_METALLIC);
@@ -2841,14 +2953,14 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_roughness(1.0);
set_metallic(0.0);
set_emission(Color(0, 0, 0));
- set_emission_energy(1.0);
+ set_emission_energy_multiplier(1.0);
set_normal_scale(1);
set_rim(1.0);
set_rim_tint(0.5);
set_clearcoat(1);
set_clearcoat_roughness(0.5);
set_anisotropy(0);
- set_heightmap_scale(0.05);
+ set_heightmap_scale(5.0);
set_subsurface_scattering_strength(0);
set_backlight(Color(0, 0, 0));
set_transmittance_color(Color(1, 1, 1, 1));
@@ -2869,7 +2981,9 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
- set_alpha_scissor_threshold(0.05);
+ // Alpha scissor threshold of 0.5 matches the glTF specification and Label3D default.
+ // <https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphacutoff>
+ set_alpha_scissor_threshold(0.5);
set_alpha_hash_scale(1.0);
set_alpha_antialiasing_edge(0.3);
@@ -2967,7 +3081,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
{ "flags_no_depth_test", "no_depth_test" },
{ "flags_use_point_size", "use_point_size" },
{ "flags_fixed_size", "fixed_Size" },
- { "flags_albedo_tex_force_srg", "albedo_tex_force_srgb" },
+ { "flags_albedo_tex_force_srgb", "albedo_texture_force_srgb" },
{ "flags_do_not_receive_shadows", "disable_receive_shadows" },
{ "flags_disable_ambient_light", "disable_ambient_light" },
{ "params_diffuse_mode", "diffuse_mode" },
@@ -2992,6 +3106,8 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
{ "depth_flip_binormal", "heightmap_flip_binormal" },
{ "depth_texture", "heightmap_texture" },
+ { "emission_energy", "emission_energy_multiplier" },
+
{ nullptr, nullptr },
};
diff --git a/scene/resources/material.h b/scene/resources/material.h
index b845fd68c8..dd9589c577 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -54,7 +54,7 @@ protected:
virtual bool _can_do_next_pass() const;
virtual bool _can_use_render_priority() const;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(RID, _get_shader_rid)
GDVIRTUAL0RC(Shader::Mode, _get_shader_mode)
@@ -88,8 +88,8 @@ protected:
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;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
static void _bind_methods();
@@ -104,8 +104,8 @@ public:
void set_shader(const Ref<Shader> &p_shader);
Ref<Shader> get_shader() const;
- void set_shader_param(const StringName &p_param, const Variant &p_value);
- Variant get_shader_param(const StringName &p_param) const;
+ void set_shader_parameter(const StringName &p_param, const Variant &p_value);
+ Variant get_shader_parameter(const StringName &p_param) const;
virtual Shader::Mode get_shader_mode() const override;
@@ -456,7 +456,8 @@ private:
float metallic = 0.0f;
float roughness = 0.0f;
Color emission;
- float emission_energy = 0.0f;
+ float emission_energy_multiplier = 1.0f;
+ float emission_intensity = 1000.0f; // In nits, equivalent to indoor lighting.
float normal_scale = 0.0f;
float rim = 0.0f;
float rim_tint = 0.0f;
@@ -542,7 +543,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
virtual bool _can_do_next_pass() const override { return true; }
virtual bool _can_use_render_priority() const override { return true; }
@@ -562,8 +563,11 @@ public:
void set_emission(const Color &p_emission);
Color get_emission() const;
- void set_emission_energy(float p_emission_energy);
- float get_emission_energy() const;
+ void set_emission_energy_multiplier(float p_emission_energy_multiplier);
+ float get_emission_energy_multiplier() const;
+
+ void set_emission_intensity(float p_emission_intensity);
+ float get_emission_intensity() const;
void set_normal_scale(float p_normal_scale);
float get_normal_scale() const;
@@ -809,4 +813,4 @@ public:
//////////////////////
-#endif
+#endif // MATERIAL_H
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index ab1873ffe9..b42e65c8df 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -32,11 +32,10 @@
#include "core/math/convex_hull.h"
#include "core/templates/pair.h"
+#include "scene/resources/surface_tool.h"
+
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
-#include "surface_tool.h"
-
-#include <stdlib.h>
Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
@@ -72,13 +71,13 @@ Array Mesh::surface_get_arrays(int p_surface) const {
return Array();
}
-Array Mesh::surface_get_blend_shape_arrays(int p_surface) const {
- Array ret;
+TypedArray<Array> Mesh::surface_get_blend_shape_arrays(int p_surface) const {
+ TypedArray<Array> ret;
if (GDVIRTUAL_REQUIRED_CALL(_surface_get_blend_shape_arrays, p_surface, ret)) {
return ret;
}
- return Array();
+ return TypedArray<Array>();
}
Dictionary Mesh::surface_get_lods(int p_surface) const {
@@ -161,32 +160,50 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
return triangle_mesh;
}
- int facecount = 0;
+ int faces_size = 0;
for (int i = 0; i < get_surface_count(); i++) {
- if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) {
- continue;
- }
-
- if (surface_get_format(i) & ARRAY_FORMAT_INDEX) {
- facecount += surface_get_array_index_len(i);
- } else {
- facecount += surface_get_array_len(i);
+ switch (surface_get_primitive_type(i)) {
+ case PRIMITIVE_TRIANGLES: {
+ int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
+ // Don't error if zero, it's valid (we'll just skip it later).
+ ERR_CONTINUE_MSG((len % 3) != 0, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLES).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len));
+ faces_size += len;
+ } break;
+ case PRIMITIVE_TRIANGLE_STRIP: {
+ int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
+ // Don't error if zero, it's valid (we'll just skip it later).
+ ERR_CONTINUE_MSG(len != 0 && len < 3, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLE_STRIP).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len));
+ faces_size += (len == 0) ? 0 : (len - 2) * 3;
+ } break;
+ default: {
+ } break;
}
}
- if (facecount == 0 || (facecount % 3) != 0) {
+ if (faces_size == 0) {
return triangle_mesh;
}
Vector<Vector3> faces;
- faces.resize(facecount);
+ faces.resize(faces_size);
+ Vector<int32_t> surface_indices;
+ surface_indices.resize(faces_size / 3);
Vector3 *facesw = faces.ptrw();
+ int32_t *surface_indicesw = surface_indices.ptrw();
int widx = 0;
for (int i = 0; i < get_surface_count(); i++) {
- if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) {
+ Mesh::PrimitiveType primitive = surface_get_primitive_type(i);
+ if (primitive != PRIMITIVE_TRIANGLES && primitive != PRIMITIVE_TRIANGLE_STRIP) {
+ continue;
+ }
+ int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
+ if ((primitive == PRIMITIVE_TRIANGLES && (len == 0 || (len % 3) != 0)) ||
+ (primitive == PRIMITIVE_TRIANGLE_STRIP && len < 3) ||
+ (surface_get_format(i) & ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)) {
+ // Error was already shown, just skip (including zero).
continue;
}
@@ -195,23 +212,48 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
int vc = surface_get_array_len(i);
Vector<Vector3> vertices = a[ARRAY_VERTEX];
+ ERR_FAIL_COND_V(vertices.is_empty(), Ref<TriangleMesh>());
const Vector3 *vr = vertices.ptr();
+ int32_t from_index = widx / 3;
+
if (surface_get_format(i) & ARRAY_FORMAT_INDEX) {
int ic = surface_get_array_index_len(i);
Vector<int> indices = a[ARRAY_INDEX];
const int *ir = indices.ptr();
- for (int j = 0; j < ic; j++) {
- int index = ir[j];
- facesw[widx++] = vr[index];
+ if (primitive == PRIMITIVE_TRIANGLES) {
+ for (int j = 0; j < ic; j++) {
+ int index = ir[j];
+ facesw[widx++] = vr[index];
+ }
+ } else { // PRIMITIVE_TRIANGLE_STRIP
+ for (int j = 2; j < ic; j++) {
+ facesw[widx++] = vr[ir[j - 2]];
+ facesw[widx++] = vr[ir[j - 1]];
+ facesw[widx++] = vr[ir[j]];
+ }
}
} else {
- for (int j = 0; j < vc; j++) {
- facesw[widx++] = vr[j];
+ if (primitive == PRIMITIVE_TRIANGLES) {
+ for (int j = 0; j < vc; j++) {
+ facesw[widx++] = vr[j];
+ }
+ } else { // PRIMITIVE_TRIANGLE_STRIP
+ for (int j = 2; j < vc; j++) {
+ facesw[widx++] = vr[j - 2];
+ facesw[widx++] = vr[j - 1];
+ facesw[widx++] = vr[j];
+ }
}
}
+
+ int32_t to_index = widx / 3;
+
+ for (int j = from_index; j < to_index; j++) {
+ surface_indicesw[j] = i;
+ }
}
triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
@@ -220,6 +262,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;
@@ -280,6 +380,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;
@@ -757,27 +865,6 @@ static Mesh::PrimitiveType _old_primitives[7] = {
};
#endif // DISABLE_DEPRECATED
-// Convert Octahedron-mapped normalized vector back to Cartesian
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_norm(const Vector2 v) {
- Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y)));
- float t = MAX(-res.z, 0.0f);
- res.x += t * -SIGN(res.x);
- res.y += t * -SIGN(res.y);
- return res.normalized();
-}
-
-// Convert Octahedron-mapped normalized tangent vector back to Cartesian
-// out_sign provides the direction for the original cartesian tangent
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_tangent(const Vector2 v, float *out_sign) {
- Vector2 v_decompressed = v;
- v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1;
- Vector3 res = _oct_to_norm(v_decompressed);
- *out_sign = SIGN(v[1]);
- return res;
-}
-
void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) {
uint32_t dst_vertex_stride;
uint32_t dst_attribute_stride;
@@ -848,127 +935,93 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) {
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
- const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
-
- const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+ int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+ dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767);
+ dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767);
}
- src_offset += sizeof(int8_t) * 2;
+ src_offset += sizeof(int16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
- const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
-
- const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+ int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+ dst[0] = src[0];
+ dst[1] = src[1];
}
src_offset += sizeof(int16_t) * 2;
}
} else { // No Octahedral compression
if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) {
- const float multiplier = 1.f / 127.f * 1023.0f;
-
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ const Vector3 original_normal(src[0], src[1], src[2]);
+ Vector2 res = original_normal.octahedron_encode();
- *dst = 0;
- *dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
- *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint32_t);
+ src_offset += sizeof(uint16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ const Vector3 original_normal(src[0], src[1], src[2]);
+ Vector2 res = original_normal.octahedron_encode();
- *dst = 0;
- *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
- *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(float) * 3;
+ src_offset += sizeof(uint16_t) * 2;
}
}
} break;
case OLD_ARRAY_TANGENT: {
if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
- if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8
+ if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
- const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
- float out_sign;
- const Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
- if (out_sign > 0) {
- *dst |= 3 << 30;
- }
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+ dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(int8_t) * 2;
- } else { // int16
+ src_offset += sizeof(uint16_t) * 2;
+ } else { // int16 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
- const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
- float out_sign;
- Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
- if (out_sign > 0) {
- *dst |= 3 << 30;
- }
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+ dst[0] = (uint16_t)CLAMP((src[0] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP((src[1] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(int16_t) * 2;
+ src_offset += sizeof(uint16_t) * 2;
}
} else { // No Octahedral compression
if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) {
- const float multiplier = 1.f / 127.f * 1023.0f;
-
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
- *dst = 0;
- *dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
- *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
- if (src[3] > 0) {
- *dst |= 3 << 30;
- }
+ const Vector3 original_tangent(src[0], src[1], src[2]);
+ Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint32_t);
+ src_offset += sizeof(uint16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
- *dst = 0;
- *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
- *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
- if (src[3] > 0) {
- *dst |= 3 << 30;
- }
+ const Vector3 original_tangent(src[0], src[1], src[2]);
+ Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(float) * 4;
+ src_offset += sizeof(uint16_t) * 2;
}
}
} break;
@@ -1561,7 +1614,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
emit_changed();
}
-void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) {
+void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) {
ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX);
RS::SurfaceData surface;
@@ -1587,8 +1640,8 @@ Array ArrayMesh::surface_get_arrays(int p_surface) const {
return RenderingServer::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
}
-Array ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const {
- ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
+TypedArray<Array> ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), TypedArray<Array>());
return RenderingServer::get_singleton()->mesh_surface_get_blend_shape_arrays(mesh, p_surface);
}
@@ -2067,7 +2120,7 @@ void ArrayMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_blend_shape_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_blend_shape_names", "_get_blend_shape_names");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shadow_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh"), "set_shadow_mesh", "get_shadow_mesh");
}
@@ -2096,7 +2149,7 @@ ArrayMesh::~ArrayMesh() {
void PlaceholderMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_aabb", "aabb"), &PlaceholderMesh::set_aabb);
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb", PROPERTY_HINT_NONE, ""), "set_aabb", "get_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_aabb", "get_aabb");
}
PlaceholderMesh::PlaceholderMesh() {
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index b166d12ead..5ed4164117 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;
@@ -62,7 +63,7 @@ protected:
GDVIRTUAL1RC(int, _surface_get_array_len, int)
GDVIRTUAL1RC(int, _surface_get_array_index_len, int)
GDVIRTUAL1RC(Array, _surface_get_arrays, int)
- GDVIRTUAL1RC(Array, _surface_get_blend_shape_arrays, int)
+ GDVIRTUAL1RC(TypedArray<Array>, _surface_get_blend_shape_arrays, int)
GDVIRTUAL1RC(Dictionary, _surface_get_lods, int)
GDVIRTUAL1RC(uint32_t, _surface_get_format, int)
GDVIRTUAL1RC(uint32_t, _surface_get_primitive_type, int)
@@ -143,13 +144,14 @@ public:
ARRAY_FLAG_USE_DYNAMIC_UPDATE = RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE,
ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS,
+ ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY,
};
virtual int get_surface_count() const;
virtual int surface_get_array_len(int p_idx) const;
virtual int surface_get_array_index_len(int p_idx) const;
virtual Array surface_get_arrays(int p_surface) const;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const;
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const;
virtual Dictionary surface_get_lods(int p_surface) const;
virtual uint32_t surface_get_format(int p_idx) const;
virtual PrimitiveType surface_get_primitive_type(int p_idx) const;
@@ -161,13 +163,12 @@ 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);
- Ref<Shape3D> create_trimesh_shape() const;
- Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
-
Ref<Mesh> create_outline(float p_margin) const;
void set_lightmap_size_hint(const Size2i &p_size);
@@ -210,6 +211,8 @@ public:
static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
+ Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
+ Ref<Shape3D> create_trimesh_shape() const;
virtual int get_builtin_bind_pose_count() const;
virtual Transform3D get_builtin_bind_pose(int p_index) const;
@@ -262,12 +265,12 @@ protected:
static void _bind_methods();
public:
- void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
+ void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes = TypedArray<Array>(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
Array surface_get_arrays(int p_surface) const override;
- Array surface_get_blend_shape_arrays(int p_surface) const override;
+ TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
Dictionary surface_get_lods(int p_surface) const override;
void add_blend_shape(const StringName &p_name);
@@ -342,7 +345,7 @@ public:
virtual int surface_get_array_len(int p_idx) const override { return 0; }
virtual int surface_get_array_index_len(int p_idx) const override { return 0; }
virtual Array surface_get_arrays(int p_surface) const override { return Array(); }
- virtual Array surface_get_blend_shape_arrays(int p_surface) const override { return Array(); }
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override { return TypedArray<Array>(); }
virtual Dictionary surface_get_lods(int p_surface) const override { return Dictionary(); }
virtual uint32_t surface_get_format(int p_idx) const override { return 0; }
virtual PrimitiveType surface_get_primitive_type(int p_idx) const override { return PRIMITIVE_TRIANGLES; }
@@ -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 5168bf83eb..2d3f9d9afc 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -100,14 +100,14 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
for (const KeyValue<int, Item> &E : item_map) {
- String name = "item/" + itos(E.key) + "/";
- p_list->push_back(PropertyInfo(Variant::STRING, name + "name"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "mesh_transform"));
- p_list->push_back(PropertyInfo(Variant::ARRAY, name + "shapes"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "navmesh_transform"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + "preview", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER));
+ String name = vformat("%s/%d/", PNAME("item"), E.key);
+ p_list->push_back(PropertyInfo(Variant::STRING, name + PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ 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));
}
}
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 4105bd6960..79acb41c4e 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -33,8 +33,8 @@
#include "core/io/resource.h"
#include "core/templates/rb_map.h"
-#include "mesh.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/resources/mesh.h"
#include "shape_3d.h"
class MeshLibrary : public Resource {
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index e5fc61ade5..ff4a7a4560 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -340,13 +340,13 @@ void MultiMesh::_bind_methods() {
#ifndef DISABLE_DEPRECATED
// Kept for compatibility from 3.x to 4.0.
- ClassDB::bind_method(D_METHOD("_set_transform_array"), &MultiMesh::_set_transform_array);
+ ClassDB::bind_method(D_METHOD("_set_transform_array", "array"), &MultiMesh::_set_transform_array);
ClassDB::bind_method(D_METHOD("_get_transform_array"), &MultiMesh::_get_transform_array);
- ClassDB::bind_method(D_METHOD("_set_transform_2d_array"), &MultiMesh::_set_transform_2d_array);
+ ClassDB::bind_method(D_METHOD("_set_transform_2d_array", "array"), &MultiMesh::_set_transform_2d_array);
ClassDB::bind_method(D_METHOD("_get_transform_2d_array"), &MultiMesh::_get_transform_2d_array);
- ClassDB::bind_method(D_METHOD("_set_color_array"), &MultiMesh::_set_color_array);
+ ClassDB::bind_method(D_METHOD("_set_color_array", "array"), &MultiMesh::_set_color_array);
ClassDB::bind_method(D_METHOD("_get_color_array"), &MultiMesh::_get_color_array);
- ClassDB::bind_method(D_METHOD("_set_custom_data_array"), &MultiMesh::_set_custom_data_array);
+ ClassDB::bind_method(D_METHOD("_set_custom_data_array", "array"), &MultiMesh::_set_custom_data_array);
ClassDB::bind_method(D_METHOD("_get_custom_data_array"), &MultiMesh::_get_custom_data_array);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_transform_array", "_get_transform_array");
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 7813de94ca..90ea879012 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 // DEBUG_ENABLED
+
void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND(p_mesh.is_null());
@@ -38,6 +42,7 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ WARN_PRINT("A mesh surface was skipped when creating a NavigationMesh due to wrong primitive type in the source mesh. Mesh surface must be made out of triangles.");
continue;
}
Array arr = p_mesh->surface_get_arrays(i);
@@ -46,6 +51,7 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
Vector<Vector3> varr = arr[Mesh::ARRAY_VERTEX];
Vector<int> iarr = arr[Mesh::ARRAY_INDEX];
if (varr.size() == 0 || iarr.size() == 0) {
+ WARN_PRINT("A mesh surface was skipped when creating a NavigationMesh due to an empty vertex or index array.");
continue;
}
@@ -270,6 +276,24 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
return filter_walkable_low_height_spans;
}
+void NavigationMesh::set_filter_baking_aabb(const AABB &p_aabb) {
+ filter_baking_aabb = p_aabb;
+ notify_property_list_changed();
+}
+
+AABB NavigationMesh::get_filter_baking_aabb() const {
+ return filter_baking_aabb;
+}
+
+void NavigationMesh::set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset) {
+ filter_baking_aabb_offset = p_aabb_offset;
+ notify_property_list_changed();
+}
+
+Vector3 NavigationMesh::get_filter_baking_aabb_offset() const {
+ return filter_baking_aabb_offset;
+}
+
void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) {
vertices = p_vertices;
notify_property_list_changed();
@@ -317,89 +341,98 @@ void NavigationMesh::clear_polygons() {
polygons.clear();
}
-Ref<Mesh> NavigationMesh::get_debug_mesh() {
+#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;
}
- Vector<Vector3> vertices = get_vertices();
- const Vector3 *vr = vertices.ptr();
- List<Face3> faces;
- for (int i = 0; i < get_polygon_count(); i++) {
- Vector<int> p = get_polygon(i);
-
- for (int j = 2; j < p.size(); j++) {
- Face3 f;
- f.vertex[0] = vr[p[0]];
- f.vertex[1] = vr[p[j - 1]];
- f.vertex[2] = vr[p[j]];
+ if (!debug_mesh.is_valid()) {
+ debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ } else {
+ debug_mesh->clear_surfaces();
+ }
- faces.push_back(f);
- }
+ if (vertices.size() == 0) {
+ return debug_mesh;
}
- HashMap<_EdgeKey, bool, _EdgeKey> edge_map;
- Vector<Vector3> tmeshfaces;
- tmeshfaces.resize(faces.size() * 3);
-
- {
- Vector3 *tw = tmeshfaces.ptrw();
- int tidx = 0;
-
- for (const Face3 &f : faces) {
- for (int j = 0; j < 3; j++) {
- tw[tidx++] = f.vertex[j];
- _EdgeKey ek;
- ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- if (ek.from < ek.to) {
- SWAP(ek.from, ek.to);
- }
-
- HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek);
-
- if (F) {
- F->value = false;
-
- } else {
- edge_map[ek] = true;
- }
- }
- }
+ int polygon_count = get_polygon_count();
+
+ if (polygon_count < 1) {
+ // no face, no play
+ return debug_mesh;
}
- List<Vector3> lines;
- for (const KeyValue<_EdgeKey, bool> &E : edge_map) {
- if (E.value) {
- lines.push_back(E.key.from);
- lines.push_back(E.key.to);
- }
+ // 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]]);
}
- Vector<Vector3> varr;
- varr.resize(lines.size());
- {
- Vector3 *w = varr.ptrw();
- int idx = 0;
- for (const Vector3 &E : lines) {
- w[idx++] = E;
+ 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()));
+
+ 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 = Ref<ArrayMesh>(memnew(ArrayMesh));
+ 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(0, debug_geometry_face_material);
- if (!lines.size()) {
- return debug_mesh;
- }
+ // if enabled build geometry edge line surface
+ bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
- Array arr;
- arr.resize(Mesh::ARRAY_MAX);
- arr[Mesh::ARRAY_VERTEX] = varr;
+ if (enabled_edge_lines) {
+ Vector<Vector3> line_vertex_array;
+ line_vertex_array.resize(polygon_count * 6);
- debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
+ 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(1, debug_geometry_edge_material);
+ }
return debug_mesh;
}
+#endif // DEBUG_ENABLED
void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);
@@ -467,6 +500,10 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_filter_walkable_low_height_spans", "filter_walkable_low_height_spans"), &NavigationMesh::set_filter_walkable_low_height_spans);
ClassDB::bind_method(D_METHOD("get_filter_walkable_low_height_spans"), &NavigationMesh::get_filter_walkable_low_height_spans);
+ ClassDB::bind_method(D_METHOD("set_filter_baking_aabb", "baking_aabb"), &NavigationMesh::set_filter_baking_aabb);
+ ClassDB::bind_method(D_METHOD("get_filter_baking_aabb"), &NavigationMesh::get_filter_baking_aabb);
+ ClassDB::bind_method(D_METHOD("set_filter_baking_aabb_offset", "baking_aabb_offset"), &NavigationMesh::set_filter_baking_aabb_offset);
+ ClassDB::bind_method(D_METHOD("get_filter_baking_aabb_offset"), &NavigationMesh::get_filter_baking_aabb_offset);
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMesh::set_vertices);
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMesh::get_vertices);
@@ -484,29 +521,40 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name");
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_height", "get_agent_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/max_slope", PROPERTY_HINT_RANGE, "0.0,90.0,0.1"), "set_agent_max_slope", "get_agent_max_slope");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
+ ADD_GROUP("Sampling", "sample_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
+ ADD_GROUP("Geometry", "geometry_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
+ ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh"));
+ ADD_GROUP("Cells", "cell_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height");
+ ADD_GROUP("Agents", "agent_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:m"), "set_agent_height", "get_agent_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:m"), "set_agent_radius", "get_agent_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_max_climb", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:m"), "set_agent_max_climb", "get_agent_max_climb");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_max_slope", PROPERTY_HINT_RANGE, "0.02,90.0,0.01,degrees"), "set_agent_max_slope", "get_agent_max_slope");
+ ADD_GROUP("Regions", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region_min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region_merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size");
+ ADD_GROUP("Edges", "edge_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater,suffix:m"), "set_edge_max_length", "get_edge_max_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater,suffix:m"), "set_edge_max_error", "get_edge_max_error");
+ ADD_GROUP("Polygons", "polygon_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon_verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
+ ADD_GROUP("Details", "detail_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_distance", "get_detail_sample_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_max_error", "get_detail_sample_max_error");
+ ADD_GROUP("Filters", "filter_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "filter_baking_aabb"), "set_filter_baking_aabb", "get_filter_baking_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "filter_baking_aabb_offset"), "set_filter_baking_aabb_offset", "get_filter_baking_aabb_offset");
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED);
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE);
@@ -524,20 +572,57 @@ void NavigationMesh::_bind_methods() {
BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX);
}
-void NavigationMesh::_validate_property(PropertyInfo &property) const {
- if (property.name == "geometry/collision_mask") {
+void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "geometry_collision_mask") {
if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
- if (property.name == "geometry/source_group_name") {
+ if (p_property.name == "geometry_source_group_name") {
if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
}
+#ifndef DISABLE_DEPRECATED
+bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ if (name.find("/") != -1) {
+ // Compatibility with pre-3.5 "category/path" property names.
+ name = name.replace("/", "_");
+ if (name == "sample_partition_type_sample_partition_type") {
+ set("sample_partition_type", p_value);
+ } else if (name == "filter_filter_walkable_low_height_spans") {
+ set("filter_walkable_low_height_spans", p_value);
+ } else {
+ set(name, p_value);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const {
+ String name = p_name;
+ if (name.find("/") != -1) {
+ // Compatibility with pre-3.5 "category/path" property names.
+ name = name.replace("/", "_");
+ if (name == "sample_partition_type_sample_partition_type") {
+ r_ret = get("sample_partition_type");
+ } else if (name == "filter_filter_walkable_low_height_spans") {
+ r_ret = get("filter_walkable_low_height_spans");
+ } else {
+ r_ret = get(name);
+ }
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
NavigationMesh::NavigationMesh() {}
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 4d8611c3c9..5ddbd75dcb 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -33,8 +33,6 @@
#include "scene/resources/mesh.h"
-class Mesh;
-
class NavigationMesh : public Resource {
GDCLASS(NavigationMesh, Resource);
@@ -60,7 +58,12 @@ class NavigationMesh : public Resource {
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
+
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+#endif // DISABLE_DEPRECATED
void _set_polygons(const Array &p_array);
Array _get_polygons() const;
@@ -88,13 +91,13 @@ public:
};
protected:
- float cell_size = 0.3f;
- float cell_height = 0.2f;
- float agent_height = 2.0f;
- float agent_radius = 1.0f;
- float agent_max_climb = 0.9f;
+ float cell_size = 0.25f;
+ float cell_height = 0.25f;
+ float agent_height = 1.5f;
+ float agent_radius = 0.5f;
+ float agent_max_climb = 0.25f;
float agent_max_slope = 45.0f;
- float region_min_size = 8.0f;
+ float region_min_size = 2.0f;
float region_merge_size = 20.0f;
float edge_max_length = 12.0f;
float edge_max_error = 1.3f;
@@ -112,6 +115,8 @@ protected:
bool filter_low_hanging_obstacles = false;
bool filter_ledge_spans = false;
bool filter_walkable_low_height_spans = false;
+ AABB filter_baking_aabb;
+ Vector3 filter_baking_aabb_offset;
public:
// Recast settings
@@ -181,6 +186,12 @@ public:
void set_filter_walkable_low_height_spans(bool p_value);
bool get_filter_walkable_low_height_spans() const;
+ void set_filter_baking_aabb(const AABB &p_aabb);
+ AABB get_filter_baking_aabb() const;
+
+ void set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset);
+ Vector3 get_filter_baking_aabb_offset() const;
+
void create_from_mesh(const Ref<Mesh> &p_mesh);
void set_vertices(const Vector<Vector3> &p_vertices);
@@ -191,7 +202,9 @@ public:
Vector<int> get_polygon(int p_idx);
void clear_polygons();
- Ref<Mesh> get_debug_mesh();
+#ifdef DEBUG_ENABLED
+ Ref<ArrayMesh> get_debug_mesh();
+#endif // DEBUG_ENABLED
NavigationMesh();
};
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index c7b1981aed..e0bedad595 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -35,6 +35,7 @@
#include "core/core_string_names.h"
#include "core/io/missing_resource.h"
#include "core/io/resource_loader.h"
+#include "core/templates/local_vector.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/node_3d.h"
#include "scene/gui/control.h"
@@ -43,7 +44,7 @@
#include "scene/property_utils.h"
#define PACKED_SCENE_VERSION 2
-
+#define META_POINTER_PROPERTY_BASE "metadata/_editor_prop_ptr_"
bool SceneState::can_instantiate() const {
return nodes.size() > 0;
}
@@ -53,7 +54,7 @@ static Array _sanitize_node_pinned_properties(Node *p_node) {
if (pinned.is_empty()) {
return Array();
}
- RBSet<StringName> storable_properties;
+ HashSet<StringName> storable_properties;
p_node->get_storable_properties(storable_properties);
int i = 0;
do {
@@ -108,6 +109,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
+ LocalVector<DeferredNodePathProperties> deferred_node_paths;
+
for (int i = 0; i < nc; i++) {
const NodeData &n = nd[i];
@@ -230,9 +233,28 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
for (int j = 0; j < nprop_count; j++) {
bool valid;
- ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+
ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
+ if (nprops[j].name & FLAG_PATH_PROPERTY_IS_NODE) {
+ uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1);
+ ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // If editor, just set the metadata and be it
+ node->set(META_POINTER_PROPERTY_BASE + String(snames[name_idx]), props[nprops[j].value]);
+ } else {
+ // Do an actual deferred sed of the property path.
+ DeferredNodePathProperties dnp;
+ dnp.path = props[nprops[j].value];
+ dnp.base = node;
+ dnp.property = snames[name_idx];
+ deferred_node_paths.push_back(dnp);
+ }
+ continue;
+ }
+
+ ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+
if (snames[nprops[j].name] == CoreStringNames::get_singleton()->_script) {
//work around to avoid old script variables from disappearing, should be the proper fix to:
//https://github.com/godotengine/godot/issues/2958
@@ -257,25 +279,36 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
Ref<Resource> res = value;
if (res.is_valid()) {
if (res->is_local_to_scene()) {
- HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
-
- if (E) {
- value = E->value;
+ // In a situation where a local-to-scene resource is used in a child node of a non-editable instance,
+ // we need to avoid the parent scene from overriding the resource potentially also used in the root
+ // of the instantiated scene. That would to the instance having two different instances of the resource.
+ // Since at this point it's too late to propagate the resource instance in the parent scene to all the relevant
+ // nodes in the instance (and that would require very complex bookkepping), what we do instead is
+ // tampering the resource object already there with the values from the node in the parent scene and
+ // then tell this node to reference that resource.
+ if (n.instance >= 0) {
+ Ref<Resource> node_res = node->get(snames[nprops[j].name]);
+ if (node_res.is_valid()) {
+ node_res->copy_from(res);
+ node_res->configure_for_local_scene(node, resources_local_to_scene);
+ value = node_res;
+ }
} else {
+ HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
Node *base = i == 0 ? node : ret_nodes[0];
-
- if (p_edit_state == GEN_EDIT_STATE_MAIN || p_edit_state == GEN_EDIT_STATE_MAIN_INHERITED) {
- //for the main scene, use the resource as is
- res->configure_for_local_scene(base, resources_local_to_scene);
- resources_local_to_scene[res] = res;
-
+ if (E) {
+ value = E->value;
} else {
- //for instances, a copy must be made
- Node *base2 = i == 0 ? node : ret_nodes[0];
- Ref<Resource> local_dupe = res->duplicate_for_local_scene(base2, resources_local_to_scene);
- resources_local_to_scene[res] = local_dupe;
- res = local_dupe;
- value = local_dupe;
+ if (p_edit_state == GEN_EDIT_STATE_MAIN) {
+ //for the main scene, use the resource as is
+ res->configure_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = res;
+ } else {
+ //for instances, a copy must be made
+ Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = local_dupe;
+ value = local_dupe;
+ }
}
}
//must make a copy, because this res is local to scene
@@ -369,8 +402,16 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
}
+ for (uint32_t i = 0; i < deferred_node_paths.size(); i++) {
+ const DeferredNodePathProperties &dnp = deferred_node_paths[i];
+ Node *other = dnp.base->get_node_or_null(dnp.path);
+ dnp.base->set(dnp.property, other);
+ }
+
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
- E.value->setup_local_to_scene();
+ if (E.value->get_local_scene() == ret_nodes[0]) {
+ E.value->setup_local_to_scene();
+ }
}
//do connections
@@ -406,10 +447,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];
@@ -532,6 +573,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
if (E.name == META_PROPERTY_MISSING_RESOURCES) {
continue; // Ignore this property when packing.
}
+ if (E.name.begins_with(META_POINTER_PROPERTY_BASE)) {
+ continue; // do not save.
+ }
// If instance or inheriting, not saving if property requested so.
if (!states_stack.is_empty()) {
@@ -542,9 +586,16 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
StringName name = E.name;
Variant value = p_node->get(name);
+ bool use_deferred_node_path_bit = false;
- if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
- // Was this missing resource overriden? If so do not save the old value.
+ if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) {
+ value = p_node->get(META_POINTER_PROPERTY_BASE + E.name);
+ if (value.get_type() != Variant::NODE_PATH) {
+ continue; //was never set, ignore.
+ }
+ use_deferred_node_path_bit = true;
+ } else if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
+ // Was this missing resource overridden? If so do not save the old value.
Ref<Resource> ures = value;
if (ures.is_null()) {
value = missing_resource_properties[E.name];
@@ -562,6 +613,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
NodeData::Property prop;
prop.name = _nm_get_string(name, name_map);
prop.value = _vm_get_variant(value, variant_map);
+ if (use_deferred_node_path_bit) {
+ prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
+ }
nd.properties.push_back(prop);
}
@@ -613,7 +667,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
if (states_stack.is_empty() && !is_editable_instance) {
//this node is not part of an instancing process, so save the type
if (missing_node != nullptr) {
- // Its a missing node (type non existant on load).
+ // It's a missing node (type non existent on load).
nd.type = _nm_get_string(missing_node->get_original_class(), name_map);
} else {
nd.type = _nm_get_string(p_node->get_class(), name_map);
@@ -851,9 +905,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));
}
@@ -1018,7 +1070,7 @@ Variant SceneState::get_property_value(int p_node, const StringName &p_property,
const NodeData::Property *p = nodes[p_node].properties.ptr();
for (int i = 0; i < pc; i++) {
- if (p_property == namep[p[i].name]) {
+ if (p_property == namep[p[i].name & FLAG_PROP_NAME_MASK]) {
found = true;
return variants[p[i].value];
}
@@ -1409,7 +1461,19 @@ int SceneState::get_node_property_count(int p_idx) const {
StringName SceneState::get_node_property_name(int p_idx, int p_prop) const {
ERR_FAIL_INDEX_V(p_idx, nodes.size(), StringName());
ERR_FAIL_INDEX_V(p_prop, nodes[p_idx].properties.size(), StringName());
- return names[nodes[p_idx].properties[p_prop].name];
+ return names[nodes[p_idx].properties[p_prop].name & FLAG_PROP_NAME_MASK];
+}
+
+Vector<String> SceneState::get_node_deferred_nodepath_properties(int p_idx) const {
+ Vector<String> ret;
+ ERR_FAIL_INDEX_V(p_idx, nodes.size(), ret);
+ for (int i = 0; i < nodes[p_idx].properties.size(); i++) {
+ uint32_t idx = nodes[p_idx].properties[i].name;
+ if (idx & FLAG_PATH_PROPERTY_IS_NODE) {
+ ret.push_back(names[idx & FLAG_PROP_NAME_MASK]);
+ }
+ }
+ return ret;
}
Variant SceneState::get_node_property_value(int p_idx, int p_prop) const {
@@ -1555,13 +1619,16 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
return nodes.size() - 1;
}
-void SceneState::add_node_property(int p_node, int p_name, int p_value) {
+void SceneState::add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path) {
ERR_FAIL_INDEX(p_node, nodes.size());
ERR_FAIL_INDEX(p_name, names.size());
ERR_FAIL_INDEX(p_value, variants.size());
NodeData::Property prop;
prop.name = p_name;
+ if (p_deferred_node_path) {
+ prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
+ }
prop.value = p_value;
nodes.write[p_node].properties.push_back(prop);
}
@@ -1599,6 +1666,10 @@ void SceneState::add_editable_instance(const NodePath &p_path) {
editable_instances.push_back(p_path);
}
+String SceneState::get_meta_pointer_property(const String &p_property) {
+ return META_POINTER_PROPERTY_BASE + p_property;
+}
+
Vector<String> SceneState::_get_node_groups(int p_idx) const {
Vector<StringName> groups = get_node_groups(p_idx);
Vector<String> ret;
@@ -1684,7 +1755,7 @@ Node *PackedScene::instantiate(GenEditState p_edit_state) const {
s->set_scene_file_path(get_path());
}
- s->notification(Node::NOTIFICATION_INSTANCED);
+ s->notification(Node::NOTIFICATION_SCENE_INSTANTIATED);
return s;
}
@@ -1721,7 +1792,7 @@ void PackedScene::_bind_methods() {
ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack);
ClassDB::bind_method(D_METHOD("instantiate", "edit_state"), &PackedScene::instantiate, DEFVAL(GEN_EDIT_STATE_DISABLED));
ClassDB::bind_method(D_METHOD("can_instantiate"), &PackedScene::can_instantiate);
- ClassDB::bind_method(D_METHOD("_set_bundled_scene"), &PackedScene::_set_bundled_scene);
+ ClassDB::bind_method(D_METHOD("_set_bundled_scene", "scene"), &PackedScene::_set_bundled_scene);
ClassDB::bind_method(D_METHOD("_get_bundled_scene"), &PackedScene::_get_bundled_scene);
ClassDB::bind_method(D_METHOD("get_state"), &PackedScene::get_state);
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 05abb23284..8e1a1d29b6 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -69,6 +69,12 @@ class SceneState : public RefCounted {
Vector<int> groups;
};
+ struct DeferredNodePathProperties {
+ Node *base = nullptr;
+ StringName property;
+ NodePath path;
+ };
+
Vector<NodeData> nodes;
struct ConnectionData {
@@ -104,6 +110,8 @@ public:
FLAG_ID_IS_PATH = (1 << 30),
TYPE_INSTANCED = 0x7FFFFFFF,
FLAG_INSTANCE_IS_PLACEHOLDER = (1 << 30),
+ FLAG_PATH_PROPERTY_IS_NODE = (1 << 30),
+ FLAG_PROP_NAME_MASK = FLAG_PATH_PROPERTY_IS_NODE - 1,
FLAG_MASK = (1 << 24) - 1,
};
@@ -157,6 +165,7 @@ public:
int get_node_property_count(int p_idx) const;
StringName get_node_property_name(int p_idx, int p_prop) const;
Variant get_node_property_value(int p_idx, int p_prop) const;
+ Vector<String> get_node_deferred_nodepath_properties(int p_idx) const;
int get_connection_count() const;
NodePath get_connection_source(int p_idx) const;
@@ -177,7 +186,7 @@ public:
int add_value(const Variant &p_value);
int add_node_path(const NodePath &p_path);
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
- void add_node_property(int p_node, int p_name, int p_value);
+ void add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path = false);
void add_node_group(int p_node, int p_group);
void set_base_scene(int p_idx);
void add_connection(int p_from, int p_to, int p_signal, int p_method, int p_flags, int p_unbinds, const Vector<int> &p_binds);
@@ -186,6 +195,9 @@ public:
virtual void set_last_modified_time(uint64_t p_time) { last_modified_time = p_time; }
uint64_t get_last_modified_time() const { return last_modified_time; }
+ // Used when saving pointers (saves a path property instead).
+ static String get_meta_pointer_property(const String &p_property);
+
SceneState();
};
@@ -237,4 +249,4 @@ public:
VARIANT_ENUM_CAST(PackedScene::GenEditState)
-#endif // SCENE_PRELOADER_H
+#endif // PACKED_SCENE_H
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particle_process_material.cpp
index 587b84a11d..e51c786786 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* particles_material.cpp */
+/* particle_process_material.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,17 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "particles_material.h"
+#include "particle_process_material.h"
#include "core/version.h"
-Mutex ParticlesMaterial::material_mutex;
-SelfList<ParticlesMaterial>::List *ParticlesMaterial::dirty_materials = nullptr;
-HashMap<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData, ParticlesMaterial::MaterialKey> ParticlesMaterial::shader_map;
-ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = nullptr;
+Mutex ParticleProcessMaterial::material_mutex;
+SelfList<ParticleProcessMaterial>::List *ParticleProcessMaterial::dirty_materials = nullptr;
+HashMap<ParticleProcessMaterial::MaterialKey, ParticleProcessMaterial::ShaderData, ParticleProcessMaterial::MaterialKey> ParticleProcessMaterial::shader_map;
+ParticleProcessMaterial::ShaderNames *ParticleProcessMaterial::shader_names = nullptr;
-void ParticlesMaterial::init_shaders() {
- dirty_materials = memnew(SelfList<ParticlesMaterial>::List);
+void ParticleProcessMaterial::init_shaders() {
+ dirty_materials = memnew(SelfList<ParticleProcessMaterial>::List);
shader_names = memnew(ShaderNames);
@@ -98,6 +98,17 @@ void ParticlesMaterial::init_shaders() {
shader_names->emission_ring_radius = "emission_ring_radius";
shader_names->emission_ring_inner_radius = "emission_ring_inner_radius";
+ shader_names->turbulence_enabled = "turbulence_enabled";
+ shader_names->turbulence_noise_strength = "turbulence_noise_strength";
+ shader_names->turbulence_noise_scale = "turbulence_noise_scale";
+ shader_names->turbulence_noise_speed = "turbulence_noise_speed";
+ shader_names->turbulence_noise_speed_random = "turbulence_noise_speed_random";
+ shader_names->turbulence_influence_over_life = "turbulence_influence_over_life";
+ shader_names->turbulence_influence_min = "turbulence_influence_min";
+ shader_names->turbulence_influence_max = "turbulence_influence_max";
+ shader_names->turbulence_initial_displacement_min = "turbulence_initial_displacement_min";
+ shader_names->turbulence_initial_displacement_max = "turbulence_initial_displacement_max";
+
shader_names->gravity = "gravity";
shader_names->lifetime_randomness = "lifetime_randomness";
@@ -110,14 +121,14 @@ void ParticlesMaterial::init_shaders() {
shader_names->collision_bounce = "collision_bounce";
}
-void ParticlesMaterial::finish_shaders() {
+void ParticleProcessMaterial::finish_shaders() {
memdelete(dirty_materials);
dirty_materials = nullptr;
memdelete(shader_names);
}
-void ParticlesMaterial::_update_shader() {
+void ParticleProcessMaterial::_update_shader() {
dirty_materials->remove(&element);
MaterialKey mk = _compute_key();
@@ -141,11 +152,10 @@ void ParticlesMaterial::_update_shader() {
shader_map[mk].users++;
return;
}
-
//must create a shader!
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
- String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticlesMaterial.\n\n";
+ String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticleProcessMaterial.\n\n";
code += "shader_type particles;\n";
@@ -197,14 +207,14 @@ void ParticlesMaterial::_update_shader() {
code += "uniform vec3 emission_box_extents;\n";
} break;
case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += "uniform sampler2D emission_texture_normal : hint_black;\n";
+ code += "uniform sampler2D emission_texture_normal : hint_default_black;\n";
[[fallthrough]];
}
case EMISSION_SHAPE_POINTS: {
- code += "uniform sampler2D emission_texture_points : hint_black;\n";
+ code += "uniform sampler2D emission_texture_points : hint_default_black;\n";
code += "uniform int emission_texture_point_count;\n";
if (emission_color_texture.is_valid()) {
- code += "uniform sampler2D emission_texture_color : hint_white;\n";
+ code += "uniform sampler2D emission_texture_color : hint_default_white;\n";
}
} break;
case EMISSION_SHAPE_RING: {
@@ -228,7 +238,7 @@ void ParticlesMaterial::_update_shader() {
code += "uniform bool sub_emitter_keep_velocity;\n";
}
- code += "uniform vec4 color_value : hint_color;\n";
+ code += "uniform vec4 color_value : source_color;\n";
code += "uniform vec3 gravity;\n";
@@ -277,11 +287,82 @@ void ParticlesMaterial::_update_shader() {
code += "uniform sampler2D anim_offset_texture : repeat_disable;\n";
}
- if (collision_enabled) {
+ if (collision_mode == COLLISION_RIGID) {
code += "uniform float collision_friction;\n";
code += "uniform float collision_bounce;\n";
}
+ if (turbulence_enabled) {
+ code += "uniform float turbulence_noise_strength;\n";
+ code += "uniform float turbulence_noise_scale;\n";
+ code += "uniform float turbulence_influence_min;\n";
+ code += "uniform float turbulence_influence_max;\n";
+ code += "uniform float turbulence_initial_displacement_min;\n";
+ code += "uniform float turbulence_initial_displacement_max;\n";
+ code += "uniform float turbulence_noise_speed_random;\n";
+ code += "uniform vec3 turbulence_noise_speed = vec3(1.0, 1.0, 1.0);\n";
+ if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) {
+ code += "uniform sampler2D turbulence_influence_over_life;\n";
+ }
+ if (turbulence_color_ramp.is_valid()) {
+ code += "uniform sampler2D turbulence_color_ramp;\n";
+ }
+ code += "\n";
+
+ //functions for 3D noise / turbulence
+ code += "\n\n";
+ code += "// 3D Noise with friendly permission by Inigo Quilez\n";
+ code += "vec3 hash_noise( vec3 p ) {\n";
+ code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n";
+ code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n";
+ code += "}\n";
+ code += "\n";
+ code += "float noise( vec3 p) {\n";
+ code += " vec3 i = floor(p);;\n";
+ code += " vec3 f = fract(p);\n ";
+ code += " vec3 u = f * f * (3.0 - 2.0 * f);\n";
+ code += "\n";
+ code += " return 2.0*mix( mix( mix( dot( hash_noise( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), dot( hash_noise( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x),\n";
+ code += " mix( dot( hash_noise( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), dot( hash_noise( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y),\n";
+ code += " mix( mix( dot( hash_noise( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), dot( hash_noise( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x),\n";
+ code += " mix( dot( hash_noise( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), dot( hash_noise( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z);\n";
+ code += "}\n\n";
+ code += "// Curl 3D and noise_3d function with friendly permission by Isaac Cohen\n";
+ code += "vec3 noise_3d(vec3 p) {\n";
+ code += " float s = noise(p);\n";
+ code += " float s1 = noise(vec3(p.y - 19.1, p.z + 33.4, p.x + 47.2));\n";
+ code += " float s2 = noise(vec3(p.z + 74.2, p.x - 124.5, p.y + 99.4));\n";
+ code += " vec3 c = vec3(s, s1, s2);\n";
+ code += " return c;\n";
+ code += "}\n\n";
+ code += "vec3 curl_3d(vec3 p, float c) {\n";
+ code += " float epsilon = 0.001 + c;\n";
+ code += " vec3 dx = vec3(epsilon, 0.0, 0.0);\n";
+ code += " vec3 dy = vec3(0.0, epsilon, 0.0);\n";
+ code += " vec3 dz = vec3(0.0, 0.0, epsilon);\n";
+ code += " vec3 x0 = noise_3d(p - dx).xyz;\n";
+ code += " vec3 x1 = noise_3d(p + dx).xyz;\n";
+ code += " vec3 y0 = noise_3d(p - dy).xyz;\n";
+ code += " vec3 y1 = noise_3d(p + dy).xyz;\n";
+ code += " vec3 z0 = noise_3d(p - dz).xyz;\n";
+ code += " vec3 z1 = noise_3d(p + dz).xyz;\n";
+ code += " float x = y1.z - y0.z - z1.y + z0.y;\n";
+ code += " float y = z1.x - z0.x - x1.z + x0.z;\n";
+ code += " float z = x1.y - x0.y - y1.x + y0.x;\n";
+ code += " float divisor = 1.0 / (2.0 * epsilon);\n";
+ code += " return vec3(normalize(vec3(x, y, z) * divisor));\n";
+ code += "}\n";
+ code += "vec3 get_noise_direction(vec3 pos, vec3 emission_pos, vec3 time_noise) {\n";
+ code += " float adj_contrast = max((turbulence_noise_strength - 1.0), 0.0) * 70.0;\n";
+ code += " vec3 noise_time = (vec3(TIME) * turbulence_noise_speed) + time_noise;\n";
+ code += " vec3 noise_pos = (pos * turbulence_noise_scale) - emission_pos;\n";
+ code += " vec3 diff = pos - emission_pos;\n";
+ code += " vec3 noise_direction = curl_3d(noise_pos + noise_time - diff, adj_contrast);\n";
+ code += " noise_direction = mix(0.9 * noise_direction, noise_direction, turbulence_noise_strength - 9.0);\n";
+ code += " return noise_direction;\n";
+ code += "}\n";
+ }
+
//need a random function
code += "\n\n";
code += "float rand_from_seed(inout uint seed) {\n";
@@ -463,8 +544,18 @@ void ParticlesMaterial::_update_shader() {
break;
}
}
-
code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ // Apply noise/turbulence: initial displacement.
+ if (turbulence_enabled) {
+ if (get_turbulence_noise_speed_random() >= 0.0) {
+ code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n";
+ } else {
+ code += " const vec3 time_noise = vec3(0.0);\n";
+ }
+ code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n";
+ code += " float turb_init_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));";
+ code += " TRANSFORM[3].xyz += noise_direction * turb_init_displacement;\n";
+ }
code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " VELOCITY.z = 0.0;\n";
@@ -483,11 +574,16 @@ void ParticlesMaterial::_update_shader() {
if (color_initial_ramp.is_valid()) {
code += " float color_initial_rand = rand_from_seed(alt_seed);\n";
}
-
code += " float pi = 3.14159;\n";
code += " float degree_to_rad = pi / 180.0;\n";
code += "\n";
+ if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
+ code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
+ code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
+ code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
+ }
+
code += " CUSTOM.y += DELTA / LIFETIME;\n";
code += " float tv = CUSTOM.y / CUSTOM.w;\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
@@ -564,7 +660,7 @@ void ParticlesMaterial::_update_shader() {
code += " vec3 diff = pos - org;\n";
code += " force += length(diff) > 0.0 ? normalize(diff) * tex_radial_accel * mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n";
code += " // apply tangential acceleration;\n";
- code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed))\n;";
+ code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed));\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n";
@@ -578,6 +674,43 @@ void ParticlesMaterial::_update_shader() {
code += " // apply attractor forces\n";
code += " VELOCITY += force * DELTA;\n";
+
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
+ }
+
+ // Apply noise/turbulence.
+ if (turbulence_enabled) {
+ code += " // apply turbulence\n";
+ if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) {
+ code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(tv, 0.0), 0.0).r;\n";
+ } else {
+ code += " const float turbulence_influence = 1.0;\n";
+ }
+ code += " \n";
+ if (get_turbulence_noise_speed_random() >= 0.0) {
+ code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n";
+ } else {
+ code += " const vec3 time_noise = vec3(0.0);\n";
+ }
+ code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n";
+ // If collision happened, turbulence is no longer applied.
+ // We don't need this check when the collision mode is "hide on contact",
+ // as the particle will be hidden anyway.
+ String extra_tab = "";
+ if (collision_mode != COLLISION_RIGID) {
+ code += " if (!COLLIDED) {\n";
+ extra_tab = " ";
+ }
+ code += extra_tab + " \n";
+ code += extra_tab + " float vel_mag = length(VELOCITY);\n";
+ code += extra_tab + " float vel_infl = clamp(mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed)) * turbulence_influence, 0.0, 1.0);\n";
+ code += extra_tab + " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n";
+ if (collision_mode != COLLISION_RIGID) {
+ code += " }";
+ }
+ }
+ code += " \n";
code += " // orbit velocity\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " float orbit_amount = tex_orbit_velocity * mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n";
@@ -589,9 +722,6 @@ void ParticlesMaterial::_update_shader() {
code += " }\n";
}
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
- }
code += " float dmp = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n";
code += " if (dmp * tex_damping > 0.0) {\n";
code += " float v = length(VELOCITY);\n";
@@ -695,24 +825,46 @@ void ParticlesMaterial::_update_shader() {
code += " TRANSFORM[3] = origin;\n";
}
}
- //scale by scale
+
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ code += " TRANSFORM[3].z = 0.0;\n";
+ }
+
+ if (collision_mode == COLLISION_RIGID) {
+ code += " if (COLLIDED) {\n";
+ code += " if (length(VELOCITY) > 3.0) {\n";
+ code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n";
+ code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
+ code += " VELOCITY = mix(VELOCITY,vec3(0.0),clamp(collision_friction, 0.0, 1.0));\n";
+ code += " } else {\n";
+ code += " VELOCITY = vec3(0.0);\n";
+ // If turbulence is enabled, set the noise direction to up so the turbulence color is "neutral"
+ if (turbulence_enabled) {
+ code += " noise_direction = vec3(1.0, 0.0, 0.0);\n";
+ }
+ code += " }\n";
+ code += " }\n";
+ }
+
+ // scale by scale
code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
-
code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
- if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
- }
- if (collision_enabled) {
+
+ if (collision_mode == COLLISION_RIGID) {
code += " if (COLLIDED) {\n";
code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n";
code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n";
code += " }\n";
+ } else if (collision_mode == COLLISION_HIDE_ON_CONTACT) {
+ code += " if (COLLIDED) {\n";
+ code += " ACTIVE = false;\n";
+ code += " }\n";
}
+
if (sub_emitter_mode != SUB_EMITTER_DISABLED) {
code += " int emit_count = 0;\n";
switch (sub_emitter_mode) {
@@ -722,11 +874,9 @@ void ParticlesMaterial::_update_shader() {
code += " if (DELTA >= interval_rem) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_COLLISION: {
- //not implemented yet
code += " if (COLLIDED) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_END: {
- //not implemented yet
code += " float unit_delta = DELTA/LIFETIME;\n";
code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter
code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n";
@@ -758,7 +908,7 @@ void ParticlesMaterial::_update_shader() {
RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
}
-void ParticlesMaterial::flush_changes() {
+void ParticleProcessMaterial::flush_changes() {
MutexLock lock(material_mutex);
while (dirty_materials->first()) {
@@ -766,7 +916,7 @@ void ParticlesMaterial::flush_changes() {
}
}
-void ParticlesMaterial::_queue_shader_change() {
+void ParticleProcessMaterial::_queue_shader_change() {
MutexLock lock(material_mutex);
if (is_initialized && !element.in_list()) {
@@ -774,40 +924,40 @@ void ParticlesMaterial::_queue_shader_change() {
}
}
-bool ParticlesMaterial::_is_shader_dirty() const {
+bool ParticleProcessMaterial::_is_shader_dirty() const {
MutexLock lock(material_mutex);
return element.in_list();
}
-void ParticlesMaterial::set_direction(Vector3 p_direction) {
+void ParticleProcessMaterial::set_direction(Vector3 p_direction) {
direction = p_direction;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction);
}
-Vector3 ParticlesMaterial::get_direction() const {
+Vector3 ParticleProcessMaterial::get_direction() const {
return direction;
}
-void ParticlesMaterial::set_spread(float p_spread) {
+void ParticleProcessMaterial::set_spread(float p_spread) {
spread = p_spread;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
}
-float ParticlesMaterial::get_spread() const {
+float ParticleProcessMaterial::get_spread() const {
return spread;
}
-void ParticlesMaterial::set_flatness(float p_flatness) {
+void ParticleProcessMaterial::set_flatness(float p_flatness) {
flatness = p_flatness;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
}
-float ParticlesMaterial::get_flatness() const {
+float ParticleProcessMaterial::get_flatness() const {
return flatness;
}
-void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) {
+void ParticleProcessMaterial::set_param_min(Parameter p_param, float p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_min[p_param] = p_value;
@@ -852,18 +1002,27 @@ void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_min, p_value);
} break;
+ case PARAM_TURB_VEL_INFLUENCE: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_min, p_value);
+ } break;
+ case PARAM_TURB_INIT_DISPLACEMENT: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_min, p_value);
+ } break;
+ case PARAM_TURB_INFLUENCE_OVER_LIFE: {
+ // Can't happen, but silences warning
+ } break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
}
-float ParticlesMaterial::get_param_min(Parameter p_param) const {
+float ParticleProcessMaterial::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return params_min[p_param];
}
-void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) {
+void ParticleProcessMaterial::set_param_max(Parameter p_param, float p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_max[p_param] = p_value;
@@ -908,12 +1067,21 @@ void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_max, p_value);
} break;
+ case PARAM_TURB_VEL_INFLUENCE: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_max, p_value);
+ } break;
+ case PARAM_TURB_INIT_DISPLACEMENT: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_max, p_value);
+ } break;
+ case PARAM_TURB_INFLUENCE_OVER_LIFE: {
+ // Can't happen, but silences warning
+ } break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
}
-float ParticlesMaterial::get_param_max(Parameter p_param) const {
+float ParticleProcessMaterial::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return params_max[p_param];
@@ -928,7 +1096,7 @@ static void _adjust_curve_range(const Ref<Texture2D> &p_texture, float p_min, fl
curve_tex->ensure_default_setup(p_min, p_max);
}
-void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture) {
+void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
tex_parameters[p_param] = p_texture;
@@ -982,6 +1150,16 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid);
} break;
+ case PARAM_TURB_INFLUENCE_OVER_LIFE: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_over_life, tex_rid);
+ _adjust_curve_range(p_texture, 0, 1);
+ } break;
+ case PARAM_TURB_VEL_INFLUENCE: {
+ // Can't happen, but silences warning
+ } break;
+ case PARAM_TURB_INIT_DISPLACEMENT: {
+ // Can't happen, but silences warning
+ } break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
@@ -989,22 +1167,22 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D
_queue_shader_change();
}
-Ref<Texture2D> ParticlesMaterial::get_param_texture(Parameter p_param) const {
+Ref<Texture2D> ParticleProcessMaterial::get_param_texture(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture2D>());
return tex_parameters[p_param];
}
-void ParticlesMaterial::set_color(const Color &p_color) {
+void ParticleProcessMaterial::set_color(const Color &p_color) {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
color = p_color;
}
-Color ParticlesMaterial::get_color() const {
+Color ParticleProcessMaterial::get_color() const {
return color;
}
-void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
+void ParticleProcessMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
color_ramp = p_texture;
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid);
@@ -1012,11 +1190,11 @@ void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
notify_property_list_changed();
}
-Ref<Texture2D> ParticlesMaterial::get_color_ramp() const {
+Ref<Texture2D> ParticleProcessMaterial::get_color_ramp() const {
return color_ramp;
}
-void ParticlesMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) {
+void ParticleProcessMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) {
color_initial_ramp = p_texture;
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, tex_rid);
@@ -1024,11 +1202,11 @@ void ParticlesMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture)
notify_property_list_changed();
}
-Ref<Texture2D> ParticlesMaterial::get_color_initial_ramp() const {
+Ref<Texture2D> ParticleProcessMaterial::get_color_initial_ramp() const {
return color_initial_ramp;
}
-void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
+void ParticleProcessMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
particle_flags[p_particle_flag] = p_enable;
_queue_shader_change();
@@ -1037,117 +1215,165 @@ void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_
}
}
-bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const {
+bool ParticleProcessMaterial::get_particle_flag(ParticleFlags p_particle_flag) const {
ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
return particle_flags[p_particle_flag];
}
-void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
+void ParticleProcessMaterial::set_emission_shape(EmissionShape p_shape) {
ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
emission_shape = p_shape;
notify_property_list_changed();
_queue_shader_change();
}
-void ParticlesMaterial::set_emission_sphere_radius(real_t p_radius) {
+void ParticleProcessMaterial::set_emission_sphere_radius(real_t p_radius) {
emission_sphere_radius = p_radius;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
}
-void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
+void ParticleProcessMaterial::set_emission_box_extents(Vector3 p_extents) {
emission_box_extents = p_extents;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
}
-void ParticlesMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) {
+void ParticleProcessMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) {
emission_point_texture = p_points;
RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid);
}
-void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) {
+void ParticleProcessMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) {
emission_normal_texture = p_normals;
RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid);
}
-void ParticlesMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) {
+void ParticleProcessMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) {
emission_color_texture = p_colors;
RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid);
_queue_shader_change();
}
-void ParticlesMaterial::set_emission_point_count(int p_count) {
+void ParticleProcessMaterial::set_emission_point_count(int p_count) {
emission_point_count = p_count;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
}
-void ParticlesMaterial::set_emission_ring_axis(Vector3 p_axis) {
+void ParticleProcessMaterial::set_emission_ring_axis(Vector3 p_axis) {
emission_ring_axis = p_axis;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_axis, p_axis);
}
-void ParticlesMaterial::set_emission_ring_height(real_t p_height) {
+void ParticleProcessMaterial::set_emission_ring_height(real_t p_height) {
emission_ring_height = p_height;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_height, p_height);
}
-void ParticlesMaterial::set_emission_ring_radius(real_t p_radius) {
+void ParticleProcessMaterial::set_emission_ring_radius(real_t p_radius) {
emission_ring_radius = p_radius;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_radius, p_radius);
}
-void ParticlesMaterial::set_emission_ring_inner_radius(real_t p_radius) {
+void ParticleProcessMaterial::set_emission_ring_inner_radius(real_t p_radius) {
emission_ring_inner_radius = p_radius;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_inner_radius, p_radius);
}
-ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const {
+ParticleProcessMaterial::EmissionShape ParticleProcessMaterial::get_emission_shape() const {
return emission_shape;
}
-real_t ParticlesMaterial::get_emission_sphere_radius() const {
+real_t ParticleProcessMaterial::get_emission_sphere_radius() const {
return emission_sphere_radius;
}
-Vector3 ParticlesMaterial::get_emission_box_extents() const {
+Vector3 ParticleProcessMaterial::get_emission_box_extents() const {
return emission_box_extents;
}
-Ref<Texture2D> ParticlesMaterial::get_emission_point_texture() const {
+Ref<Texture2D> ParticleProcessMaterial::get_emission_point_texture() const {
return emission_point_texture;
}
-Ref<Texture2D> ParticlesMaterial::get_emission_normal_texture() const {
+Ref<Texture2D> ParticleProcessMaterial::get_emission_normal_texture() const {
return emission_normal_texture;
}
-Ref<Texture2D> ParticlesMaterial::get_emission_color_texture() const {
+Ref<Texture2D> ParticleProcessMaterial::get_emission_color_texture() const {
return emission_color_texture;
}
-int ParticlesMaterial::get_emission_point_count() const {
+int ParticleProcessMaterial::get_emission_point_count() const {
return emission_point_count;
}
-Vector3 ParticlesMaterial::get_emission_ring_axis() const {
+Vector3 ParticleProcessMaterial::get_emission_ring_axis() const {
return emission_ring_axis;
}
-real_t ParticlesMaterial::get_emission_ring_height() const {
+real_t ParticleProcessMaterial::get_emission_ring_height() const {
return emission_ring_height;
}
-real_t ParticlesMaterial::get_emission_ring_radius() const {
+real_t ParticleProcessMaterial::get_emission_ring_radius() const {
return emission_ring_radius;
}
-real_t ParticlesMaterial::get_emission_ring_inner_radius() const {
+real_t ParticleProcessMaterial::get_emission_ring_inner_radius() const {
return emission_ring_inner_radius;
}
-void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
+void ParticleProcessMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) {
+ turbulence_enabled = p_turbulence_enabled;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled);
+ _queue_shader_change();
+ notify_property_list_changed();
+}
+
+bool ParticleProcessMaterial::get_turbulence_enabled() const {
+ return turbulence_enabled;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) {
+ turbulence_noise_strength = p_turbulence_noise_strength;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_strength, p_turbulence_noise_strength);
+}
+
+float ParticleProcessMaterial::get_turbulence_noise_strength() const {
+ return turbulence_noise_strength;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) {
+ turbulence_noise_scale = p_turbulence_noise_scale;
+ float shader_turbulence_noise_scale = (pow(p_turbulence_noise_scale, 0.25) * 5.6234 / 10.0) * 4.0 - 3.0;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_scale, shader_turbulence_noise_scale);
+}
+
+float ParticleProcessMaterial::get_turbulence_noise_scale() const {
+ return turbulence_noise_scale;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) {
+ turbulence_noise_speed_random = p_turbulence_noise_speed_random;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed_random, p_turbulence_noise_speed_random);
+}
+
+float ParticleProcessMaterial::get_turbulence_noise_speed_random() const {
+ return turbulence_noise_speed_random;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) {
+ turbulence_noise_speed = p_turbulence_noise_speed;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed, turbulence_noise_speed);
+}
+
+Vector3 ParticleProcessMaterial::get_turbulence_noise_speed() const {
+ return turbulence_noise_speed;
+}
+
+void ParticleProcessMaterial::set_gravity(const Vector3 &p_gravity) {
gravity = p_gravity;
Vector3 gset = gravity;
if (gset == Vector3()) {
@@ -1156,243 +1382,281 @@ void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset);
}
-Vector3 ParticlesMaterial::get_gravity() const {
+Vector3 ParticleProcessMaterial::get_gravity() const {
return gravity;
}
-void ParticlesMaterial::set_lifetime_randomness(double p_lifetime) {
+void ParticleProcessMaterial::set_lifetime_randomness(double p_lifetime) {
lifetime_randomness = p_lifetime;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness);
}
-double ParticlesMaterial::get_lifetime_randomness() const {
+double ParticleProcessMaterial::get_lifetime_randomness() const {
return lifetime_randomness;
}
-RID ParticlesMaterial::get_shader_rid() const {
+RID ParticleProcessMaterial::get_shader_rid() const {
ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
return shader_map[current_key].shader;
}
-void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (p_property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (!turbulence_enabled) {
+ if (p_property.name == "turbulence_noise_strength" ||
+ p_property.name == "turbulence_noise_scale" ||
+ p_property.name == "turbulence_noise_speed" ||
+ p_property.name == "turbulence_noise_speed_random" ||
+ p_property.name == "turbulence_influence_over_life" ||
+ p_property.name == "turbulence_influence_min" ||
+ p_property.name == "turbulence_influence_max" ||
+ p_property.name == "turbulence_initial_displacement_min" ||
+ p_property.name == "turbulence_initial_displacement_max") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
- if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "collision_friction" && collision_mode != COLLISION_RIGID) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "collision_bounce" && collision_mode != COLLISION_RIGID) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
-void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
+void ParticleProcessMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
sub_emitter_mode = p_sub_emitter_mode;
_queue_shader_change();
notify_property_list_changed();
}
-ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const {
+ParticleProcessMaterial::SubEmitterMode ParticleProcessMaterial::get_sub_emitter_mode() const {
return sub_emitter_mode;
}
-void ParticlesMaterial::set_sub_emitter_frequency(double p_frequency) {
+void ParticleProcessMaterial::set_sub_emitter_frequency(double p_frequency) {
sub_emitter_frequency = p_frequency;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute
}
-double ParticlesMaterial::get_sub_emitter_frequency() const {
+double ParticleProcessMaterial::get_sub_emitter_frequency() const {
return sub_emitter_frequency;
}
-void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) {
+void ParticleProcessMaterial::set_sub_emitter_amount_at_end(int p_amount) {
sub_emitter_amount_at_end = p_amount;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount);
}
-int ParticlesMaterial::get_sub_emitter_amount_at_end() const {
+int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const {
return sub_emitter_amount_at_end;
}
-void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) {
+void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) {
sub_emitter_keep_velocity = p_enable;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable);
}
-bool ParticlesMaterial::get_sub_emitter_keep_velocity() const {
+bool ParticleProcessMaterial::get_sub_emitter_keep_velocity() const {
return sub_emitter_keep_velocity;
}
-void ParticlesMaterial::set_attractor_interaction_enabled(bool p_enable) {
+void ParticleProcessMaterial::set_attractor_interaction_enabled(bool p_enable) {
attractor_interaction_enabled = p_enable;
_queue_shader_change();
}
-bool ParticlesMaterial::is_attractor_interaction_enabled() const {
+bool ParticleProcessMaterial::is_attractor_interaction_enabled() const {
return attractor_interaction_enabled;
}
-void ParticlesMaterial::set_collision_enabled(bool p_enabled) {
- collision_enabled = p_enabled;
+void ParticleProcessMaterial::set_collision_mode(CollisionMode p_collision_mode) {
+ collision_mode = p_collision_mode;
_queue_shader_change();
+ notify_property_list_changed();
}
-bool ParticlesMaterial::is_collision_enabled() const {
- return collision_enabled;
+ParticleProcessMaterial::CollisionMode ParticleProcessMaterial::get_collision_mode() const {
+ return collision_mode;
}
-void ParticlesMaterial::set_collision_use_scale(bool p_scale) {
+void ParticleProcessMaterial::set_collision_use_scale(bool p_scale) {
collision_scale = p_scale;
_queue_shader_change();
}
-bool ParticlesMaterial::is_collision_using_scale() const {
+bool ParticleProcessMaterial::is_collision_using_scale() const {
return collision_scale;
}
-void ParticlesMaterial::set_collision_friction(float p_friction) {
+void ParticleProcessMaterial::set_collision_friction(float p_friction) {
collision_friction = p_friction;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction);
}
-float ParticlesMaterial::get_collision_friction() const {
+float ParticleProcessMaterial::get_collision_friction() const {
return collision_friction;
}
-void ParticlesMaterial::set_collision_bounce(float p_bounce) {
+void ParticleProcessMaterial::set_collision_bounce(float p_bounce) {
collision_bounce = p_bounce;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce);
}
-float ParticlesMaterial::get_collision_bounce() const {
+float ParticleProcessMaterial::get_collision_bounce() const {
return collision_bounce;
}
-Shader::Mode ParticlesMaterial::get_shader_mode() const {
+Shader::Mode ParticleProcessMaterial::get_shader_mode() const {
return Shader::MODE_PARTICLES;
}
-void ParticlesMaterial::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticlesMaterial::set_direction);
- ClassDB::bind_method(D_METHOD("get_direction"), &ParticlesMaterial::get_direction);
+void ParticleProcessMaterial::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticleProcessMaterial::set_direction);
+ ClassDB::bind_method(D_METHOD("get_direction"), &ParticleProcessMaterial::get_direction);
+
+ ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticleProcessMaterial::set_spread);
+ ClassDB::bind_method(D_METHOD("get_spread"), &ParticleProcessMaterial::get_spread);
+
+ ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticleProcessMaterial::set_flatness);
+ ClassDB::bind_method(D_METHOD("get_flatness"), &ParticleProcessMaterial::get_flatness);
+
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticleProcessMaterial::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticleProcessMaterial::get_param_min);
+
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticleProcessMaterial::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticleProcessMaterial::get_param_max);
+
+ ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticleProcessMaterial::set_param_texture);
+ ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticleProcessMaterial::get_param_texture);
- ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread);
- ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread);
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticleProcessMaterial::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &ParticleProcessMaterial::get_color);
- ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness);
- ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticleProcessMaterial::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticleProcessMaterial::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticlesMaterial::set_param_min);
- ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticlesMaterial::get_param_min);
+ ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticleProcessMaterial::set_color_initial_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticleProcessMaterial::get_color_initial_ramp);
- ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticlesMaterial::set_param_max);
- ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticlesMaterial::get_param_max);
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticleProcessMaterial::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticleProcessMaterial::get_particle_flag);
- ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture);
- ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticleProcessMaterial::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticleProcessMaterial::get_emission_shape);
- ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color);
+ ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticleProcessMaterial::set_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticleProcessMaterial::get_emission_sphere_radius);
- ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp);
- ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp);
+ ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticleProcessMaterial::set_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticleProcessMaterial::get_emission_box_extents);
- ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticlesMaterial::set_color_initial_ramp);
- ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticlesMaterial::get_color_initial_ramp);
+ ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticleProcessMaterial::set_emission_point_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticleProcessMaterial::get_emission_point_texture);
- ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag);
- ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag);
+ ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticleProcessMaterial::set_emission_normal_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticleProcessMaterial::get_emission_normal_texture);
- ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape);
- ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape);
+ ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticleProcessMaterial::set_emission_color_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticleProcessMaterial::get_emission_color_texture);
- ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius);
- ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticleProcessMaterial::set_emission_point_count);
+ ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticleProcessMaterial::get_emission_point_count);
- ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents);
- ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticleProcessMaterial::set_emission_ring_axis);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticleProcessMaterial::get_emission_ring_axis);
- ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture);
- ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticleProcessMaterial::set_emission_ring_height);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticleProcessMaterial::get_emission_ring_height);
- ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture);
- ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticleProcessMaterial::set_emission_ring_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticleProcessMaterial::get_emission_ring_radius);
- ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture);
- ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticleProcessMaterial::set_emission_ring_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticleProcessMaterial::get_emission_ring_inner_radius);
- ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count);
- ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count);
+ ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticleProcessMaterial::get_turbulence_enabled);
+ ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticleProcessMaterial::set_turbulence_enabled);
- ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticlesMaterial::set_emission_ring_axis);
- ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticlesMaterial::get_emission_ring_axis);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticleProcessMaterial::get_turbulence_noise_strength);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticleProcessMaterial::set_turbulence_noise_strength);
- ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticlesMaterial::set_emission_ring_height);
- ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticlesMaterial::get_emission_ring_height);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticleProcessMaterial::get_turbulence_noise_scale);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticleProcessMaterial::set_turbulence_noise_scale);
- ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticlesMaterial::set_emission_ring_radius);
- ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticlesMaterial::get_emission_ring_radius);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticleProcessMaterial::get_turbulence_noise_speed_random);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticleProcessMaterial::set_turbulence_noise_speed_random);
- ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticlesMaterial::set_emission_ring_inner_radius);
- ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticlesMaterial::get_emission_ring_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticleProcessMaterial::get_turbulence_noise_speed);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticleProcessMaterial::set_turbulence_noise_speed);
- ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity);
- ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_gravity"), &ParticleProcessMaterial::get_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticleProcessMaterial::set_gravity);
- ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticlesMaterial::set_lifetime_randomness);
- ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticlesMaterial::get_lifetime_randomness);
+ ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticleProcessMaterial::set_lifetime_randomness);
+ ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticleProcessMaterial::get_lifetime_randomness);
- ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticlesMaterial::get_sub_emitter_mode);
- ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticlesMaterial::set_sub_emitter_mode);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticleProcessMaterial::get_sub_emitter_mode);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticleProcessMaterial::set_sub_emitter_mode);
- ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticlesMaterial::get_sub_emitter_frequency);
- ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticlesMaterial::set_sub_emitter_frequency);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticleProcessMaterial::get_sub_emitter_frequency);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticleProcessMaterial::set_sub_emitter_frequency);
- ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticlesMaterial::get_sub_emitter_amount_at_end);
- ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticlesMaterial::set_sub_emitter_amount_at_end);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end);
- ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticlesMaterial::get_sub_emitter_keep_velocity);
- ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticlesMaterial::set_sub_emitter_keep_velocity);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity);
- ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled);
- ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled);
+ ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticleProcessMaterial::set_attractor_interaction_enabled);
+ ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticleProcessMaterial::is_attractor_interaction_enabled);
- ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &ParticlesMaterial::set_collision_enabled);
- ClassDB::bind_method(D_METHOD("is_collision_enabled"), &ParticlesMaterial::is_collision_enabled);
+ ClassDB::bind_method(D_METHOD("set_collision_mode", "mode"), &ParticleProcessMaterial::set_collision_mode);
+ ClassDB::bind_method(D_METHOD("get_collision_mode"), &ParticleProcessMaterial::get_collision_mode);
- ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale);
- ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale);
+ ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticleProcessMaterial::set_collision_use_scale);
+ ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticleProcessMaterial::is_collision_using_scale);
- ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticlesMaterial::set_collision_friction);
- ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticlesMaterial::get_collision_friction);
+ ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticleProcessMaterial::set_collision_friction);
+ ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticleProcessMaterial::get_collision_friction);
- ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticlesMaterial::set_collision_bounce);
- ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticlesMaterial::get_collision_bounce);
+ ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticleProcessMaterial::set_collision_bounce);
+ ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticleProcessMaterial::get_collision_bounce);
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
@@ -1409,7 +1673,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
- ADD_GROUP("ParticleFlags", "particle_flag_");
+ ADD_GROUP("Particle Flags", "particle_flag_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z);
@@ -1420,35 +1684,35 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1463,24 +1727,37 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
+
+ ADD_GROUP("Turbulence", "turbulence_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_enabled"), "set_turbulence_enabled", "get_turbulence_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_strength", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_turbulence_noise_strength", "get_turbulence_noise_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_scale", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_scale", "get_turbulence_noise_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "turbulence_noise_speed"), "set_turbulence_noise_speed", "get_turbulence_noise_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_speed_random", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_speed_random", "get_turbulence_noise_speed_random");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_TURB_VEL_INFLUENCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_TURB_VEL_INFLUENCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_min", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_min", "get_param_min", PARAM_TURB_INIT_DISPLACEMENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_max", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_max", "get_param_max", PARAM_TURB_INIT_DISPLACEMENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE);
+
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
ADD_GROUP("Sub Emitter", "sub_emitter_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity");
ADD_GROUP("Attractor Interaction", "attractor_interaction_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled");
ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mode", PROPERTY_HINT_ENUM, "Disabled,Rigid,Hide On Contact"), "set_collision_mode", "get_collision_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale");
@@ -1513,14 +1790,23 @@ void ParticlesMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_SHAPE_RING);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
+ BIND_ENUM_CONSTANT(PARAM_TURB_VEL_INFLUENCE);
+ BIND_ENUM_CONSTANT(PARAM_TURB_INIT_DISPLACEMENT);
+ BIND_ENUM_CONSTANT(PARAM_TURB_INFLUENCE_OVER_LIFE);
+
BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED);
BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT);
BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END);
BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION);
BIND_ENUM_CONSTANT(SUB_EMITTER_MAX);
+
+ BIND_ENUM_CONSTANT(COLLISION_DISABLED);
+ BIND_ENUM_CONSTANT(COLLISION_RIGID);
+ BIND_ENUM_CONSTANT(COLLISION_HIDE_ON_CONTACT);
+ BIND_ENUM_CONSTANT(COLLISION_MAX);
}
-ParticlesMaterial::ParticlesMaterial() :
+ParticleProcessMaterial::ParticleProcessMaterial() :
element(this) {
set_direction(Vector3(1, 0, 0));
set_spread(45);
@@ -1556,6 +1842,17 @@ ParticlesMaterial::ParticlesMaterial() :
set_emission_ring_height(1);
set_emission_ring_radius(1);
set_emission_ring_inner_radius(0);
+
+ set_turbulence_enabled(false);
+ set_turbulence_noise_speed(Vector3(0.5, 0.5, 0.5));
+ set_turbulence_noise_strength(1);
+ set_turbulence_noise_scale(9);
+ set_turbulence_noise_speed_random(0);
+ set_param_min(PARAM_TURB_VEL_INFLUENCE, 0.1);
+ set_param_max(PARAM_TURB_VEL_INFLUENCE, 0.1);
+ set_param_min(PARAM_TURB_INIT_DISPLACEMENT, 0.0);
+ set_param_max(PARAM_TURB_INIT_DISPLACEMENT, 0.0);
+
set_gravity(Vector3(0, -9.8, 0));
set_lifetime_randomness(0);
@@ -1565,7 +1862,7 @@ ParticlesMaterial::ParticlesMaterial() :
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
- set_collision_enabled(false);
+ set_collision_mode(COLLISION_DISABLED);
set_collision_bounce(0.0);
set_collision_friction(0.0);
set_collision_use_scale(false);
@@ -1582,7 +1879,7 @@ ParticlesMaterial::ParticlesMaterial() :
_queue_shader_change();
}
-ParticlesMaterial::~ParticlesMaterial() {
+ParticleProcessMaterial::~ParticleProcessMaterial() {
MutexLock lock(material_mutex);
if (shader_map.has(current_key)) {
diff --git a/scene/resources/particles_material.h b/scene/resources/particle_process_material.h
index 24341d964d..9430e5797d 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particle_process_material.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* particles_material.h */
+/* particle_process_material.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef PARTICLE_PROCESS_MATERIAL_H
+#define PARTICLE_PROCESS_MATERIAL_H
+
#include "core/templates/rid.h"
#include "scene/resources/material.h"
-#ifndef PARTICLES_MATERIAL_H
-#define PARTICLES_MATERIAL_H
-
/*
TODO:
-Path following
@@ -41,8 +41,8 @@
-Proper trails
*/
-class ParticlesMaterial : public Material {
- GDCLASS(ParticlesMaterial, Material);
+class ParticleProcessMaterial : public Material {
+ GDCLASS(ParticleProcessMaterial, Material);
public:
enum Parameter {
@@ -58,6 +58,9 @@ public:
PARAM_HUE_VARIATION,
PARAM_ANIM_SPEED,
PARAM_ANIM_OFFSET,
+ PARAM_TURB_INFLUENCE_OVER_LIFE,
+ PARAM_TURB_VEL_INFLUENCE,
+ PARAM_TURB_INIT_DISPLACEMENT,
PARAM_MAX
};
@@ -90,6 +93,14 @@ public:
SUB_EMITTER_MAX
};
+ // When extending, make sure not to overflow the size of the MaterialKey below.
+ enum CollisionMode {
+ COLLISION_DISABLED,
+ COLLISION_RIGID,
+ COLLISION_HIDE_ON_CONTACT,
+ COLLISION_MAX
+ };
+
private:
union MaterialKey {
// The bit size of the struct must be kept below or equal to 32 bits.
@@ -103,14 +114,15 @@ private:
uint32_t has_emission_color : 1;
uint32_t sub_emitter : 2;
uint32_t attractor_enabled : 1;
- uint32_t collision_enabled : 1;
+ uint32_t collision_mode : 2;
uint32_t collision_scale : 1;
+ uint32_t turbulence_enabled : 1;
};
- uint32_t key = 0;
+ uint64_t key = 0;
static uint32_t hash(const MaterialKey &p_key) {
- return hash_djb2_one_32(p_key.key);
+ return hash_murmur3_one_32(p_key.key);
}
bool operator==(const MaterialKey &p_key) const {
@@ -149,15 +161,16 @@ private:
mk.emission_shape = emission_shape;
mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
mk.sub_emitter = sub_emitter_mode;
- mk.collision_enabled = collision_enabled;
+ mk.collision_mode = collision_mode;
mk.attractor_enabled = attractor_interaction_enabled;
mk.collision_scale = collision_scale;
+ mk.turbulence_enabled = turbulence_enabled;
return mk;
}
static Mutex material_mutex;
- static SelfList<ParticlesMaterial>::List *dirty_materials;
+ static SelfList<ParticleProcessMaterial>::List *dirty_materials;
struct ShaderNames {
StringName direction;
@@ -216,6 +229,17 @@ private:
StringName emission_ring_radius;
StringName emission_ring_inner_radius;
+ StringName turbulence_enabled;
+ StringName turbulence_noise_strength;
+ StringName turbulence_noise_scale;
+ StringName turbulence_noise_speed;
+ StringName turbulence_noise_speed_random;
+ StringName turbulence_influence_over_life;
+ StringName turbulence_influence_min;
+ StringName turbulence_influence_max;
+ StringName turbulence_initial_displacement_min;
+ StringName turbulence_initial_displacement_max;
+
StringName gravity;
StringName lifetime_randomness;
@@ -230,7 +254,7 @@ private:
static ShaderNames *shader_names;
- SelfList<ParticlesMaterial> element;
+ SelfList<ParticleProcessMaterial> element;
void _update_shader();
_FORCE_INLINE_ void _queue_shader_change();
@@ -243,6 +267,7 @@ private:
float params_min[PARAM_MAX];
float params_max[PARAM_MAX];
+ float params[PARAM_MAX];
Ref<Texture2D> tex_parameters[PARAM_MAX];
Color color;
@@ -265,6 +290,13 @@ private:
bool anim_loop = false;
+ bool turbulence_enabled;
+ Vector3 turbulence_noise_speed;
+ Ref<Texture2D> turbulence_color_ramp;
+ float turbulence_noise_strength = 0.0f;
+ float turbulence_noise_scale = 0.0f;
+ float turbulence_noise_speed_random = 0.0f;
+
Vector3 gravity;
double lifetime_randomness = 0.0;
@@ -276,14 +308,14 @@ private:
//do not save emission points here
bool attractor_interaction_enabled = false;
- bool collision_enabled = false;
+ CollisionMode collision_mode;
bool collision_scale = false;
float collision_friction = 0.0f;
float collision_bounce = 0.0f;
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_direction(Vector3 p_direction);
@@ -340,6 +372,18 @@ public:
real_t get_emission_ring_inner_radius() const;
int get_emission_point_count() const;
+ void set_turbulence_enabled(bool p_turbulence_enabled);
+ void set_turbulence_noise_strength(float p_turbulence_noise_strength);
+ void set_turbulence_noise_scale(float p_turbulence_noise_scale);
+ void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random);
+ void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed);
+
+ bool get_turbulence_enabled() const;
+ float get_turbulence_noise_strength() const;
+ float get_turbulence_noise_scale() const;
+ float get_turbulence_noise_speed_random() const;
+ Vector3 get_turbulence_noise_speed() const;
+
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
@@ -349,8 +393,8 @@ public:
void set_attractor_interaction_enabled(bool p_enable);
bool is_attractor_interaction_enabled() const;
- void set_collision_enabled(bool p_enabled);
- bool is_collision_enabled() const;
+ void set_collision_mode(CollisionMode p_collision_mode);
+ CollisionMode get_collision_mode() const;
void set_collision_use_scale(bool p_scale);
bool is_collision_using_scale() const;
@@ -381,13 +425,14 @@ public:
virtual Shader::Mode get_shader_mode() const override;
- ParticlesMaterial();
- ~ParticlesMaterial();
+ ParticleProcessMaterial();
+ ~ParticleProcessMaterial();
};
-VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
-VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags)
-VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
-VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::Parameter)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::ParticleFlags)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::EmissionShape)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::SubEmitterMode)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::CollisionMode)
-#endif // PARTICLES_MATERIAL_H
+#endif // PARTICLE_PROCESS_MATERIAL_H
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 155a8522cf..5e18671c11 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -34,8 +34,8 @@
bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const {
int crosses = 0;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
@@ -105,8 +105,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
bool valid = true;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
if (e.points[0] == i || e.points[1] == i || e.points[0] == j || e.points[1] == j) {
continue;
}
@@ -140,8 +140,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float closest_dist = 1e20f;
Vector2 closest_point;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 seg[2] = {
points[e.points[0]].pos,
points[e.points[1]].pos
@@ -151,7 +151,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float d = from.distance_squared_to(closest);
if (d < closest_dist) {
- ignore_from_edge = E->get();
+ ignore_from_edge = E;
closest_dist = d;
closest_point = closest;
}
@@ -164,8 +164,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float closest_dist = 1e20f;
Vector2 closest_point;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 seg[2] = {
points[e.points[0]].pos,
points[e.points[1]].pos
@@ -175,7 +175,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float d = to.distance_squared_to(closest);
if (d < closest_dist) {
- ignore_to_edge = E->get();
+ ignore_to_edge = E;
closest_dist = d;
closest_point = closest;
}
@@ -188,8 +188,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
{
bool can_see_eachother = true;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
if (e.points[0] == ignore_from_edge.points[0] && e.points[1] == ignore_from_edge.points[1]) {
continue;
}
@@ -240,8 +240,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
valid_b = false;
}
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
if (e.points[0] == i || e.points[1] == i) {
continue;
@@ -289,14 +289,14 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
}
//solve graph
- RBSet<int> open_list;
+ HashSet<int> open_list;
points.write[aidx].distance = 0;
points.write[aidx].prev = aidx;
- for (RBSet<int>::Element *E = points[aidx].connections.front(); E; E = E->next()) {
- open_list.insert(E->get());
- points.write[E->get()].distance = from.distance_to(points[E->get()].pos);
- points.write[E->get()].prev = aidx;
+ for (const int &E : points[aidx].connections) {
+ open_list.insert(E);
+ points.write[E].distance = from.distance_to(points[E].pos);
+ points.write[E].prev = aidx;
}
bool found_route = false;
@@ -312,14 +312,14 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float least_cost = 1e30;
//this could be faster (cache previous results)
- for (RBSet<int>::Element *E = open_list.front(); E; E = E->next()) {
- const Point &p = points[E->get()];
+ for (const int &E : open_list) {
+ const Point &p = points[E];
float cost = p.distance;
cost += p.pos.distance_to(to);
cost += p.penalty;
if (cost < least_cost) {
- least_cost_point = E->get();
+ least_cost_point = E;
least_cost = cost;
}
}
@@ -327,8 +327,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
const Point &np = points[least_cost_point];
//open the neighbours for search
- for (RBSet<int>::Element *E = np.connections.front(); E; E = E->next()) {
- Point &p = points.write[E->get()];
+ for (const int &E : np.connections) {
+ Point &p = points.write[E];
float distance = np.pos.distance_to(p.pos) + np.distance;
if (p.prev != -1) {
@@ -343,9 +343,9 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
p.prev = least_cost_point;
p.distance = distance;
- open_list.insert(E->get());
+ open_list.insert(E);
- if (E->get() == bidx) {
+ if (E == bidx) {
//oh my reached end! stop algorithm
found_route = true;
break;
@@ -459,8 +459,8 @@ Dictionary PolygonPathFinder::_get_data() const {
{
int *cw = c.ptrw();
int idx = 0;
- for (RBSet<int>::Element *E = points[i].connections.front(); E; E = E->next()) {
- cw[idx++] = E->get();
+ for (const int &E : points[i].connections) {
+ cw[idx++] = E;
}
}
connections[i] = c;
@@ -469,9 +469,9 @@ Dictionary PolygonPathFinder::_get_data() const {
{
int *iw = ind.ptrw();
int idx = 0;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- iw[idx++] = E->get().points[0];
- iw[idx++] = E->get().points[1];
+ for (const Edge &E : edges) {
+ iw[idx++] = E.points[0];
+ iw[idx++] = E.points[1];
}
}
@@ -492,8 +492,8 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
float closest_dist = 1e20f;
Vector2 closest_point;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 seg[2] = {
points[e.points[0]].pos,
points[e.points[1]].pos
@@ -516,9 +516,9 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2 &p_from, const Vector2 &p_to) const {
Vector<Vector2> inters;
- for (RBSet<Edge>::Element *E = edges.front(); E; E = E->next()) {
- Vector2 a = points[E->get().points[0]].pos;
- Vector2 b = points[E->get().points[1]].pos;
+ for (const Edge &E : edges) {
+ Vector2 a = points[E.points[0]].pos;
+ Vector2 b = points[E.points[1]].pos;
Vector2 res;
if (Geometry2D::segment_intersects_segment(a, b, p_from, p_to, &res)) {
@@ -553,7 +553,7 @@ void PolygonPathFinder::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_penalty", "idx"), &PolygonPathFinder::get_point_penalty);
ClassDB::bind_method(D_METHOD("get_bounds"), &PolygonPathFinder::get_bounds);
- ClassDB::bind_method(D_METHOD("_set_data"), &PolygonPathFinder::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &PolygonPathFinder::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &PolygonPathFinder::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h
index 71ad77eb6e..0e22b53dcb 100644
--- a/scene/resources/polygon_path_finder.h
+++ b/scene/resources/polygon_path_finder.h
@@ -38,21 +38,23 @@ class PolygonPathFinder : public Resource {
struct Point {
Vector2 pos;
- RBSet<int> connections;
+ HashSet<int> connections;
float distance = 0.0;
float penalty = 0.0;
int prev = 0;
};
- struct Edge {
- int points[2] = {};
+ union Edge {
+ struct {
+ int32_t points[2];
+ };
+ uint64_t key = 0;
- _FORCE_INLINE_ bool operator<(const Edge &p_edge) const {
- if (points[0] == p_edge.points[0]) {
- return points[1] < p_edge.points[1];
- } else {
- return points[0] < p_edge.points[0];
- }
+ _FORCE_INLINE_ bool operator==(const Edge &p_edge) const {
+ return key == p_edge.key;
+ }
+ _FORCE_INLINE_ static uint32_t hash(const Edge &p_edge) {
+ return hash_one_uint64(p_edge.key);
}
Edge(int a = 0, int b = 0) {
@@ -68,7 +70,7 @@ class PolygonPathFinder : public Resource {
Rect2 bounds;
Vector<Point> points;
- RBSet<Edge> edges;
+ HashSet<Edge, Edge> edges;
bool _is_point_inside(const Vector2 &p_point) const;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 3009bdb449..c017c90370 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -32,6 +32,7 @@
#include "core/core_string_names.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
@@ -152,8 +153,8 @@ Dictionary PrimitiveMesh::surface_get_lods(int p_surface) const {
return Dictionary(); //not really supported
}
-Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
- return Array(); //not really supported
+TypedArray<Array> PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
+ return TypedArray<Array>(); //not really supported
}
uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
@@ -219,7 +220,7 @@ void PrimitiveMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
GDVIRTUAL_BIND(_create_mesh_array);
@@ -435,16 +436,19 @@ void CapsuleMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+
+ ADD_LINKED_PROPERTY("radius", "height");
+ ADD_LINKED_PROPERTY("height", "radius");
}
void CapsuleMesh::set_radius(const float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
- radius = height * 0.5;
+ height = radius * 2.0;
}
_request_update();
}
@@ -456,7 +460,7 @@ float CapsuleMesh::get_radius() const {
void CapsuleMesh::set_height(const float p_height) {
height = p_height;
if (radius > height * 0.5) {
- height = radius * 2;
+ radius = height * 0.5;
}
_request_update();
}
@@ -696,7 +700,7 @@ void BoxMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &BoxMesh::set_subdivide_depth);
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &BoxMesh::get_subdivide_depth);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
@@ -745,10 +749,10 @@ BoxMesh::BoxMesh() {}
*/
void CylinderMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings);
+ create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom);
}
-void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings) {
+void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings, bool cap_top, bool cap_bottom) {
int i, j, prevrow, thisrow, point;
float x, y, z, u, v, radius;
@@ -806,7 +810,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
};
// add top
- if (top_radius > 0.0) {
+ if (cap_top && top_radius > 0.0) {
y = height * 0.5;
thisrow = point;
@@ -842,7 +846,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
};
// add bottom
- if (bottom_radius > 0.0) {
+ if (cap_bottom && bottom_radius > 0.0) {
y = height * -0.5;
thisrow = point;
@@ -897,11 +901,19 @@ void CylinderMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_top_radius", "get_top_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_bottom_radius", "get_bottom_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
+ ClassDB::bind_method(D_METHOD("set_cap_top", "cap_top"), &CylinderMesh::set_cap_top);
+ ClassDB::bind_method(D_METHOD("is_cap_top"), &CylinderMesh::is_cap_top);
+
+ ClassDB::bind_method(D_METHOD("set_cap_bottom", "cap_bottom"), &CylinderMesh::set_cap_bottom);
+ ClassDB::bind_method(D_METHOD("is_cap_bottom"), &CylinderMesh::is_cap_bottom);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_top_radius", "get_top_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_bottom_radius", "get_bottom_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_top"), "set_cap_top", "is_cap_top");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_bottom"), "set_cap_bottom", "is_cap_bottom");
}
void CylinderMesh::set_top_radius(const float p_radius) {
@@ -949,6 +961,24 @@ int CylinderMesh::get_rings() const {
return rings;
}
+void CylinderMesh::set_cap_top(bool p_cap_top) {
+ cap_top = p_cap_top;
+ _request_update();
+}
+
+bool CylinderMesh::is_cap_top() const {
+ return cap_top;
+}
+
+void CylinderMesh::set_cap_bottom(bool p_cap_bottom) {
+ cap_bottom = p_cap_bottom;
+ _request_update();
+}
+
+bool CylinderMesh::is_cap_bottom() const {
+ return cap_bottom;
+}
+
CylinderMesh::CylinderMesh() {}
/**
@@ -961,6 +991,13 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const {
Size2 start_pos = size * -0.5;
+ Vector3 normal = Vector3(0.0, 1.0, 0.0);
+ if (orientation == FACE_X) {
+ normal = Vector3(1.0, 0.0, 0.0);
+ } else if (orientation == FACE_Z) {
+ normal = Vector3(0.0, 0.0, 1.0);
+ }
+
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
@@ -986,8 +1023,14 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const {
u /= (subdivide_w + 1.0);
v /= (subdivide_d + 1.0);
- points.push_back(Vector3(-x, 0.0, -z) + center_offset);
- normals.push_back(Vector3(0.0, 1.0, 0.0));
+ if (orientation == FACE_X) {
+ points.push_back(Vector3(0.0, z, x) + center_offset);
+ } else if (orientation == FACE_Y) {
+ points.push_back(Vector3(-x, 0.0, -z) + center_offset);
+ } else if (orientation == FACE_Z) {
+ points.push_back(Vector3(-x, z, 0.0) + center_offset);
+ }
+ normals.push_back(normal);
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */
point++;
@@ -1024,13 +1067,22 @@ void PlaneMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width);
ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth);
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth);
+
ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset);
ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &PlaneMesh::set_orientation);
+ ClassDB::bind_method(D_METHOD("get_orientation"), &PlaneMesh::get_orientation);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X, Face Y, Face Z"), "set_orientation", "get_orientation");
+
+ BIND_ENUM_CONSTANT(FACE_X)
+ BIND_ENUM_CONSTANT(FACE_Y)
+ BIND_ENUM_CONSTANT(FACE_Z)
}
void PlaneMesh::set_size(const Size2 &p_size) {
@@ -1069,6 +1121,15 @@ Vector3 PlaneMesh::get_center_offset() const {
return center_offset;
}
+void PlaneMesh::set_orientation(const Orientation p_orientation) {
+ orientation = p_orientation;
+ _request_update();
+}
+
+PlaneMesh::Orientation PlaneMesh::get_orientation() const {
+ return orientation;
+}
+
PlaneMesh::PlaneMesh() {}
/**
@@ -1298,7 +1359,7 @@ void PrismMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
@@ -1352,98 +1413,6 @@ int PrismMesh::get_subdivide_depth() const {
PrismMesh::PrismMesh() {}
/**
- QuadMesh
-*/
-
-void QuadMesh::_create_mesh_array(Array &p_arr) const {
- Vector<Vector3> faces;
- Vector<Vector3> normals;
- Vector<float> tangents;
- Vector<Vector2> uvs;
-
- faces.resize(6);
- normals.resize(6);
- tangents.resize(6 * 4);
- uvs.resize(6);
-
- Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
-
- Vector3 quad_faces[4] = {
- Vector3(-_size.x, -_size.y, 0) + center_offset,
- Vector3(-_size.x, _size.y, 0) + center_offset,
- Vector3(_size.x, _size.y, 0) + center_offset,
- Vector3(_size.x, -_size.y, 0) + center_offset,
- };
-
- static const int indices[6] = {
- 0, 1, 2,
- 0, 2, 3
- };
-
- for (int i = 0; i < 6; i++) {
- int j = indices[i];
- faces.set(i, quad_faces[j]);
- normals.set(i, Vector3(0, 0, 1));
- tangents.set(i * 4 + 0, 1.0);
- tangents.set(i * 4 + 1, 0.0);
- tangents.set(i * 4 + 2, 0.0);
- tangents.set(i * 4 + 3, 1.0);
-
- static const Vector2 quad_uv[4] = {
- Vector2(0, 1),
- Vector2(0, 0),
- Vector2(1, 0),
- Vector2(1, 1),
- };
-
- uvs.set(i, quad_uv[j]);
- }
-
- p_arr[RS::ARRAY_VERTEX] = faces;
- p_arr[RS::ARRAY_NORMAL] = normals;
- p_arr[RS::ARRAY_TANGENT] = tangents;
- p_arr[RS::ARRAY_TEX_UV] = uvs;
-}
-
-void QuadMesh::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size);
- ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset);
- ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset");
-}
-
-uint32_t QuadMesh::surface_get_format(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, 1, 0);
-
- return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV;
-}
-
-QuadMesh::QuadMesh() {
- primitive_type = PRIMITIVE_TRIANGLES;
-}
-
-void QuadMesh::set_size(const Size2 &p_size) {
- size = p_size;
- _request_update();
-}
-
-Size2 QuadMesh::get_size() const {
- return size;
-}
-
-void QuadMesh::set_center_offset(Vector3 p_center_offset) {
- center_offset = p_center_offset;
- _request_update();
-}
-
-Vector3 QuadMesh::get_center_offset() const {
- return center_offset;
-}
-
-/**
SphereMesh
*/
@@ -1538,8 +1507,8 @@ void SphereMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere);
ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere");
@@ -1593,6 +1562,134 @@ bool SphereMesh::get_is_hemisphere() const {
SphereMesh::SphereMesh() {}
/**
+ TorusMesh
+*/
+
+void TorusMesh::_create_mesh_array(Array &p_arr) const {
+ // set our bounding box
+
+ Vector<Vector3> points;
+ Vector<Vector3> normals;
+ Vector<float> tangents;
+ Vector<Vector2> uvs;
+ Vector<int> indices;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+ tangents.push_back(m_x); \
+ tangents.push_back(m_y); \
+ tangents.push_back(m_z); \
+ tangents.push_back(m_d);
+
+ ERR_FAIL_COND_MSG(inner_radius == outer_radius, "Inner radius and outer radius cannot be the same.");
+
+ float min_radius = inner_radius;
+ float max_radius = outer_radius;
+
+ if (min_radius > max_radius) {
+ SWAP(min_radius, max_radius);
+ }
+
+ float radius = (max_radius - min_radius) * 0.5;
+
+ for (int i = 0; i <= rings; i++) {
+ int prevrow = (i - 1) * (ring_segments + 1);
+ int thisrow = i * (ring_segments + 1);
+ float inci = float(i) / rings;
+ float angi = inci * Math_TAU;
+
+ Vector2 normali = Vector2(-Math::sin(angi), -Math::cos(angi));
+
+ for (int j = 0; j <= ring_segments; j++) {
+ float incj = float(j) / ring_segments;
+ float angj = incj * Math_TAU;
+
+ Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj));
+ Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0);
+
+ points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x));
+ normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x));
+ ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0);
+ uvs.push_back(Vector2(inci, incj));
+
+ if (i > 0 && j > 0) {
+ indices.push_back(thisrow + j - 1);
+ indices.push_back(prevrow + j);
+ indices.push_back(prevrow + j - 1);
+
+ indices.push_back(thisrow + j - 1);
+ indices.push_back(thisrow + j);
+ indices.push_back(prevrow + j);
+ }
+ }
+ }
+
+ p_arr[RS::ARRAY_VERTEX] = points;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void TorusMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &TorusMesh::set_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_inner_radius"), &TorusMesh::get_inner_radius);
+
+ ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &TorusMesh::set_outer_radius);
+ ClassDB::bind_method(D_METHOD("get_outer_radius"), &TorusMesh::get_outer_radius);
+
+ ClassDB::bind_method(D_METHOD("set_rings", "rings"), &TorusMesh::set_rings);
+ ClassDB::bind_method(D_METHOD("get_rings"), &TorusMesh::get_rings);
+
+ ClassDB::bind_method(D_METHOD("set_ring_segments", "rings"), &TorusMesh::set_ring_segments);
+ ClassDB::bind_method(D_METHOD("get_ring_segments"), &TorusMesh::get_ring_segments);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "3,128,1"), "set_rings", "get_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_segments", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_segments", "get_ring_segments");
+}
+
+void TorusMesh::set_inner_radius(const float p_inner_radius) {
+ inner_radius = p_inner_radius;
+ _request_update();
+}
+
+float TorusMesh::get_inner_radius() const {
+ return inner_radius;
+}
+
+void TorusMesh::set_outer_radius(const float p_outer_radius) {
+ outer_radius = p_outer_radius;
+ _request_update();
+}
+
+float TorusMesh::get_outer_radius() const {
+ return outer_radius;
+}
+
+void TorusMesh::set_rings(const int p_rings) {
+ ERR_FAIL_COND(p_rings < 3);
+ rings = p_rings;
+ _request_update();
+}
+
+int TorusMesh::get_rings() const {
+ return rings;
+}
+
+void TorusMesh::set_ring_segments(const int p_ring_segments) {
+ ERR_FAIL_COND(p_ring_segments < 3);
+ ring_segments = p_ring_segments;
+ _request_update();
+}
+
+int TorusMesh::get_ring_segments() const {
+ return ring_segments;
+}
+
+TorusMesh::TorusMesh() {}
+
+/**
PointMesh
*/
@@ -1725,7 +1822,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
float r = radius;
if (curve.is_valid() && curve->get_point_count() > 0) {
- r *= curve->interpolate_baked(v);
+ r *= curve->sample_baked(v);
}
float x = sin(u * Math_TAU);
float z = cos(u * Math_TAU);
@@ -1766,7 +1863,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
// add top
float scale_pos = 1.0;
if (curve.is_valid() && curve->get_point_count() > 0) {
- scale_pos = curve->interpolate_baked(0);
+ scale_pos = curve->sample_baked(0);
}
if (scale_pos > CMP_EPSILON) {
@@ -1828,7 +1925,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
float scale_neg = 1.0;
if (curve.is_valid() && curve->get_point_count() > 0) {
- scale_neg = curve->interpolate_baked(1.0);
+ scale_neg = curve->sample_baked(1.0);
}
// add bottom
@@ -1917,12 +2014,12 @@ void TubeTrailMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &TubeTrailMesh::set_curve);
ClassDB::bind_method(D_METHOD("get_curve"), &TubeTrailMesh::get_curve);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_steps", PROPERTY_HINT_RANGE, "3,128,1"), "set_radial_steps", "get_radial_steps");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater,suffix:m"), "set_section_length", "get_section_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "section_rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_rings", "get_section_rings");
@@ -2041,7 +2138,7 @@ void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const {
float s = size;
if (curve.is_valid() && curve->get_point_count() > 0) {
- s *= curve->interpolate_baked(v);
+ s *= curve->sample_baked(v);
}
points.push_back(Vector3(-s * 0.5, y, 0));
@@ -2144,9 +2241,9 @@ void RibbonTrailMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shape"), &RibbonTrailMesh::get_shape);
ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Flat,Cross"), "set_shape", "get_shape");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater,suffix:m"), "set_section_length", "get_section_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "section_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_segments", "get_section_segments");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
@@ -2161,12 +2258,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;
@@ -2229,17 +2326,27 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con
}
} else if (points[j].z == TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC) {
// Cubic Bezier arc.
+ int32_t cur = j;
int32_t next1 = (j == end) ? start : (j + 1);
int32_t next2 = (next1 == end) ? start : (next1 + 1);
int32_t prev = (j == start) ? end : (j - 1);
// There must be exactly two OFF points and two ON points for each cubic arc.
+ if (points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON) {
+ cur = (cur == 0) ? end : cur - 1;
+ next1 = (next1 == 0) ? end : next1 - 1;
+ next2 = (next2 == 0) ? end : next2 - 1;
+ prev = (prev == 0) ? end : prev - 1;
+ } else {
+ j++;
+ }
ERR_FAIL_COND_MSG(points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, prev));
+ ERR_FAIL_COND_MSG(points[cur].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, cur));
ERR_FAIL_COND_MSG(points[next1].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, next1));
ERR_FAIL_COND_MSG(points[next2].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, next2));
Vector2 p0 = Vector2(points[prev].x, points[prev].y);
- Vector2 p1 = Vector2(points[j].x, points[j].y);
+ Vector2 p1 = Vector2(points[cur].x, points[cur].y);
Vector2 p2 = Vector2(points[next1].x, points[next1].y);
Vector2 p3 = Vector2(points[next2].x, points[next2].y);
@@ -2257,7 +2364,6 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con
polygon.push_back(ContourPoint(p, false));
t += step;
}
- i++;
} else {
ERR_FAIL_MSG(vformat("Unknown point tag at %d:%d", i, j));
}
@@ -2304,18 +2410,18 @@ void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) con
//Decompose and triangulate.
List<TPPLPoly> out_poly;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) {
- ERR_FAIL_MSG("Convex decomposing failed!");
+ ERR_FAIL_MSG("Convex decomposing failed. Make sure the font doesn't contain self-intersecting lines, as these are not supported in TextMesh.");
}
List<TPPLPoly> out_tris;
for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
if (tpart.Triangulate_OPT(&(I->get()), &out_tris) == 0) {
- ERR_FAIL_MSG("Triangulation failed!");
+ ERR_FAIL_MSG("Triangulation failed. Make sure the font doesn't contain self-intersecting lines, as these are not supported in TextMesh.");
}
}
for (List<TPPLPoly>::Element *I = out_tris.front(); I; I = I->next()) {
TPPLPoly &tp = I->get();
- ERR_FAIL_COND(tp.GetNumPoints() != 3); // Trianges only.
+ ERR_FAIL_COND(tp.GetNumPoints() != 3); // Triangles only.
for (int i = 0; i < 3; i++) {
gl_data.triangles.push_back(Vector2(tp.GetPoint(i).x, tp.GetPoint(i).y));
@@ -2338,7 +2444,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) {
@@ -2350,88 +2459,149 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
dirty_text = false;
dirty_font = false;
+ dirty_lines = true;
} 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;
+ dirty_lines = true;
}
- if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
- } else {
- TS->shaped_text_fit_to_width(text_rid, -1, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
+
+ if (dirty_lines) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free_rid(lines_rid[i]);
+ }
+ lines_rid.clear();
+
+ BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY;
+ switch (autowrap_mode) {
+ case TextServer::AUTOWRAP_WORD_SMART:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_WORD:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_ARBITRARY:
+ autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_OFF:
+ break;
+ }
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+
+ float max_line_w = 0.0;
+ for (int i = 0; i < line_breaks.size(); i = i + 2) {
+ RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
+ max_line_w = MAX(max_line_w, TS->shaped_text_get_width(line));
+ lines_rid.push_back(line);
+ }
+
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ for (int i = 0; i < lines_rid.size() - 1; i++) {
+ TS->shaped_text_fit_to_width(lines_rid[i], (width > 0) ? width : max_line_w, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
+ }
+ }
+ dirty_lines = false;
}
- Vector2 offset;
- const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid);
- int gl_size = TS->shaped_text_get_glyph_count(text_rid);
- float line_width = TS->shaped_text_get_width(text_rid) * pixel_size;
-
- switch (horizontal_alignment) {
- case HORIZONTAL_ALIGNMENT_LEFT:
- offset.x = 0.0;
- break;
- case HORIZONTAL_ALIGNMENT_FILL:
- case HORIZONTAL_ALIGNMENT_CENTER: {
- offset.x = -line_width / 2.0;
+ float total_h = 0.0;
+ for (int i = 0; i < lines_rid.size(); i++) {
+ total_h += (TS->shaped_text_get_size(lines_rid[i]).y + line_spacing) * pixel_size;
+ }
+
+ float vbegin = 0.0;
+ switch (vertical_alignment) {
+ case VERTICAL_ALIGNMENT_FILL:
+ case VERTICAL_ALIGNMENT_TOP: {
+ // Nothing.
} break;
- case HORIZONTAL_ALIGNMENT_RIGHT: {
- offset.x = -line_width;
+ case VERTICAL_ALIGNMENT_CENTER: {
+ vbegin = (total_h - line_spacing * pixel_size) / 2.0;
+ } break;
+ case VERTICAL_ALIGNMENT_BOTTOM: {
+ vbegin = (total_h - line_spacing * pixel_size);
} break;
}
- bool has_depth = !Math::is_zero_approx(depth);
-
- // Generate glyph data, precalculate size of the arrays and mesh bounds for UV.
- int64_t p_size = 0;
- int64_t i_size = 0;
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+ Vector<float> tangents;
+ Vector<Vector2> uvs;
+ Vector<int32_t> indices;
Vector2 min_p = Vector2(INFINITY, INFINITY);
Vector2 max_p = Vector2(-INFINITY, -INFINITY);
- Vector2 offset_pre = offset;
- for (int i = 0; i < gl_size; i++) {
- if (glyphs[i].font_rid != RID()) {
- uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
- hash = hash_djb2_one_32(glyphs[i].index, hash);
+ int32_t p_size = 0;
+ int32_t i_size = 0;
+
+ Vector2 offset = Vector2(0, vbegin + lbl_offset.y * pixel_size);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
+ int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]);
+ float line_width = TS->shaped_text_get_width(lines_rid[i]) * pixel_size;
+
+ switch (horizontal_alignment) {
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ offset.x = 0.0;
+ break;
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ offset.x = -line_width / 2.0;
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ offset.x = -line_width;
+ } break;
+ }
+ offset.x += lbl_offset.x * pixel_size;
+ offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size;
+
+ bool has_depth = !Math::is_zero_approx(depth);
- _generate_glyph_mesh_data(hash, glyphs[i]);
- GlyphMeshData &gl_data = cache[hash];
+ for (int j = 0; j < gl_size; j++) {
+ if (glyphs[j].index == 0) {
+ offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat;
+ continue;
+ }
+ if (glyphs[j].font_rid != RID()) {
+ GlyphMeshKey key = GlyphMeshKey(glyphs[j].font_rid.get_id(), glyphs[j].index);
+ _generate_glyph_mesh_data(key, glyphs[j]);
+ 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);
+ p_size += glyphs[j].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
+ i_size += glyphs[j].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
- if (has_depth) {
- for (int j = 0; j < gl_data.contours.size(); j++) {
- p_size += glyphs[i].repeat * gl_data.contours[j].size() * 4;
- i_size += glyphs[i].repeat * gl_data.contours[j].size() * 6;
+ if (has_depth) {
+ for (int k = 0; k < gl_data.contours.size(); k++) {
+ p_size += glyphs[j].repeat * gl_data.contours[k].size() * 4;
+ i_size += glyphs[j].repeat * gl_data.contours[k].size() * 6;
+ }
}
- }
- for (int j = 0; j < glyphs[i].repeat; j++) {
- min_p.x = MIN(gl_data.min_p.x + offset_pre.x, min_p.x);
- min_p.y = MIN(gl_data.min_p.y + offset_pre.y, min_p.y);
- max_p.x = MAX(gl_data.max_p.x + offset_pre.x, max_p.x);
- max_p.y = MAX(gl_data.max_p.y + offset_pre.y, max_p.y);
+ for (int r = 0; r < glyphs[j].repeat; r++) {
+ min_p.x = MIN(gl_data.min_p.x + offset.x, min_p.x);
+ min_p.y = MIN(gl_data.min_p.y - offset.y, min_p.y);
+ max_p.x = MAX(gl_data.max_p.x + offset.x, max_p.x);
+ max_p.y = MAX(gl_data.max_p.y - offset.y, max_p.y);
- offset_pre.x += glyphs[i].advance * pixel_size;
- }
- } else {
- p_size += glyphs[i].repeat * 4;
- i_size += glyphs[i].repeat * 6;
+ offset.x += glyphs[j].advance * pixel_size;
+ }
+ } else {
+ p_size += glyphs[j].repeat * 4;
+ i_size += glyphs[j].repeat * 6;
- offset_pre.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
+ offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat;
+ }
}
+ offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * pixel_size;
}
- Vector<Vector3> vertices;
- Vector<Vector3> normals;
- Vector<float> tangents;
- Vector<Vector2> uvs;
- Vector<int32_t> indices;
-
vertices.resize(p_size);
normals.resize(p_size);
uvs.resize(p_size);
@@ -2447,147 +2617,177 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
// Generate mesh.
int32_t p_idx = 0;
int32_t i_idx = 0;
- for (int i = 0; i < gl_size; i++) {
- if (glyphs[i].font_rid != RID()) {
- uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
- hash = hash_djb2_one_32(glyphs[i].index, hash);
-
- const GlyphMeshData &gl_data = cache[hash];
-
- int64_t ts = gl_data.triangles.size();
- const Vector2 *ts_ptr = gl_data.triangles.ptr();
-
- for (int j = 0; j < glyphs[i].repeat; j++) {
- for (int k = 0; k < ts; k += 3) {
- // Add front face.
- for (int l = 0; l < 3; l++) {
- Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0);
- vertices_ptr[p_idx] = point;
- normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0);
- if (has_depth) {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4)));
- } else {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0)));
- }
- tangents_ptr[p_idx * 4 + 0] = 1.0;
- tangents_ptr[p_idx * 4 + 1] = 0.0;
- tangents_ptr[p_idx * 4 + 2] = 0.0;
- tangents_ptr[p_idx * 4 + 3] = 1.0;
- indices_ptr[i_idx++] = p_idx;
- p_idx++;
- }
- if (has_depth) {
- // Add back face.
- for (int l = 2; l >= 0; l--) {
- Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
+
+ offset = Vector2(0, vbegin + lbl_offset.y * pixel_size);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
+ int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]);
+ float line_width = TS->shaped_text_get_width(lines_rid[i]) * pixel_size;
+
+ switch (horizontal_alignment) {
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ offset.x = 0.0;
+ break;
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ offset.x = -line_width / 2.0;
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ offset.x = -line_width;
+ } break;
+ }
+ offset.x += lbl_offset.x * pixel_size;
+ offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size;
+
+ bool has_depth = !Math::is_zero_approx(depth);
+
+ // Generate glyph data, precalculate size of the arrays and mesh bounds for UV.
+ for (int j = 0; j < gl_size; j++) {
+ if (glyphs[j].index == 0) {
+ offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat;
+ continue;
+ }
+ if (glyphs[j].font_rid != RID()) {
+ GlyphMeshKey key = GlyphMeshKey(glyphs[j].font_rid.get_id(), glyphs[j].index);
+ _generate_glyph_mesh_data(key, glyphs[j]);
+ const GlyphMeshData &gl_data = cache[key];
+
+ int64_t ts = gl_data.triangles.size();
+ const Vector2 *ts_ptr = gl_data.triangles.ptr();
+
+ for (int r = 0; r < glyphs[j].repeat; r++) {
+ for (int k = 0; k < ts; k += 3) {
+ // Add front face.
+ for (int l = 0; l < 3; l++) {
+ Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0);
vertices_ptr[p_idx] = point;
- normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.4), real_t(0.8)));
- tangents_ptr[p_idx * 4 + 0] = -1.0;
+ normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0);
+ if (has_depth) {
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ } else {
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ }
+ tangents_ptr[p_idx * 4 + 0] = 1.0;
tangents_ptr[p_idx * 4 + 1] = 0.0;
tangents_ptr[p_idx * 4 + 2] = 0.0;
tangents_ptr[p_idx * 4 + 3] = 1.0;
indices_ptr[i_idx++] = p_idx;
p_idx++;
}
- }
- }
- // Add sides.
- if (has_depth) {
- for (int k = 0; k < gl_data.contours.size(); k++) {
- int64_t ps = gl_data.contours[k].size();
- const ContourPoint *ps_ptr = gl_data.contours[k].ptr();
- const ContourInfo &ps_info = gl_data.contours_info[k];
- real_t length = 0.0;
- for (int l = 0; l < ps; l++) {
- int prev = (l == 0) ? (ps - 1) : (l - 1);
- int next = (l + 1 == ps) ? 0 : (l + 1);
- Vector2 d1;
- Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized();
- if (ps_ptr[l].sharp) {
- d1 = d2;
- } else {
- d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized();
+ if (has_depth) {
+ // Add back face.
+ for (int l = 2; l >= 0; l--) {
+ Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
+ vertices_ptr[p_idx] = point;
+ normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4)));
+ tangents_ptr[p_idx * 4 + 0] = -1.0;
+ tangents_ptr[p_idx * 4 + 1] = 0.0;
+ tangents_ptr[p_idx * 4 + 2] = 0.0;
+ tangents_ptr[p_idx * 4 + 3] = 1.0;
+ indices_ptr[i_idx++] = p_idx;
+ p_idx++;
}
- real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length();
-
- Vector3 quad_faces[4] = {
- Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0),
- Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0),
- Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0),
- Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0),
- };
- for (int m = 0; m < 4; m++) {
- const Vector2 &d = ((m % 2) == 0) ? d1 : d2;
- real_t u_pos = ((m % 2) == 0) ? length : length + seg_len;
- vertices_ptr[p_idx + m] = quad_faces[m];
- normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0);
- if (m < 2) {
- uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
+ }
+ }
+ // Add sides.
+ if (has_depth) {
+ for (int k = 0; k < gl_data.contours.size(); k++) {
+ int64_t ps = gl_data.contours[k].size();
+ const ContourPoint *ps_ptr = gl_data.contours[k].ptr();
+ const ContourInfo &ps_info = gl_data.contours_info[k];
+ real_t length = 0.0;
+ for (int l = 0; l < ps; l++) {
+ int prev = (l == 0) ? (ps - 1) : (l - 1);
+ int next = (l + 1 == ps) ? 0 : (l + 1);
+ Vector2 d1;
+ Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized();
+ if (ps_ptr[l].sharp) {
+ d1 = d2;
} else {
- uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized();
+ }
+ real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length();
+
+ Vector3 quad_faces[4] = {
+ Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0),
+ Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0),
+ Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0),
+ Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0),
+ };
+ for (int m = 0; m < 4; m++) {
+ const Vector2 &d = ((m % 2) == 0) ? d1 : d2;
+ real_t u_pos = ((m % 2) == 0) ? length : length + seg_len;
+ vertices_ptr[p_idx + m] = quad_faces[m];
+ normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0);
+ if (m < 2) {
+ uvs_ptr[p_idx + m] = Vector2(Math::remap(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
+ } else {
+ uvs_ptr[p_idx + m] = Vector2(Math::remap(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ }
+ tangents_ptr[(p_idx + m) * 4 + 0] = d.x;
+ tangents_ptr[(p_idx + m) * 4 + 1] = -d.y;
+ tangents_ptr[(p_idx + m) * 4 + 2] = 0.0;
+ tangents_ptr[(p_idx + m) * 4 + 3] = 1.0;
}
- tangents_ptr[(p_idx + m) * 4 + 0] = d.x;
- tangents_ptr[(p_idx + m) * 4 + 1] = -d.y;
- tangents_ptr[(p_idx + m) * 4 + 2] = 0.0;
- tangents_ptr[(p_idx + m) * 4 + 3] = 1.0;
- }
- indices_ptr[i_idx++] = p_idx;
- indices_ptr[i_idx++] = p_idx + 1;
- indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 2;
- indices_ptr[i_idx++] = p_idx + 1;
- indices_ptr[i_idx++] = p_idx + 3;
- indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 3;
+ indices_ptr[i_idx++] = p_idx + 2;
- length += seg_len;
- p_idx += 4;
+ length += seg_len;
+ p_idx += 4;
+ }
}
}
+ offset.x += glyphs[j].advance * pixel_size;
}
- offset.x += glyphs[i].advance * pixel_size;
- }
- } else {
- // Add fallback quad for missing glyphs.
- for (int j = 0; j < glyphs[i].repeat; j++) {
- Size2 sz = TS->get_hex_code_box_size(glyphs[i].font_size, glyphs[i].index) * pixel_size;
- Vector3 quad_faces[4] = {
- Vector3(offset.x, offset.y, 0.0),
- Vector3(offset.x, sz.y + offset.y, 0.0),
- Vector3(sz.x + offset.x, sz.y + offset.y, 0.0),
- Vector3(sz.x + offset.x, offset.y, 0.0),
- };
- for (int k = 0; k < 4; k++) {
- vertices_ptr[p_idx + k] = quad_faces[k];
- normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
- if (has_depth) {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4)));
- } else {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0)));
+ } else {
+ // Add fallback quad for missing glyphs.
+ for (int r = 0; r < glyphs[j].repeat; r++) {
+ Size2 sz = TS->get_hex_code_box_size(glyphs[j].font_size, glyphs[j].index) * pixel_size;
+ Vector3 quad_faces[4] = {
+ Vector3(offset.x, offset.y, 0.0),
+ Vector3(offset.x, sz.y + offset.y, 0.0),
+ Vector3(sz.x + offset.x, sz.y + offset.y, 0.0),
+ Vector3(sz.x + offset.x, offset.y, 0.0),
+ };
+ for (int k = 0; k < 4; k++) {
+ vertices_ptr[p_idx + k] = quad_faces[k];
+ normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
+ if (has_depth) {
+ uvs_ptr[p_idx + k] = Vector2(Math::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ } else {
+ uvs_ptr[p_idx + k] = Vector2(Math::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ }
+ tangents_ptr[(p_idx + k) * 4 + 0] = 1.0;
+ tangents_ptr[(p_idx + k) * 4 + 1] = 0.0;
+ tangents_ptr[(p_idx + k) * 4 + 2] = 0.0;
+ tangents_ptr[(p_idx + k) * 4 + 3] = 1.0;
}
- tangents_ptr[(p_idx + k) * 4 + 0] = 1.0;
- tangents_ptr[(p_idx + k) * 4 + 1] = 0.0;
- tangents_ptr[(p_idx + k) * 4 + 2] = 0.0;
- tangents_ptr[(p_idx + k) * 4 + 3] = 1.0;
- }
- indices_ptr[i_idx++] = p_idx;
- indices_ptr[i_idx++] = p_idx + 1;
- indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 2;
- indices_ptr[i_idx++] = p_idx + 0;
- indices_ptr[i_idx++] = p_idx + 2;
- indices_ptr[i_idx++] = p_idx + 3;
- p_idx += 4;
+ indices_ptr[i_idx++] = p_idx + 0;
+ indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx + 3;
+ p_idx += 4;
- offset.x += glyphs[i].advance * pixel_size;
+ offset.x += glyphs[j].advance * pixel_size;
+ }
}
}
+ offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * pixel_size;
}
- if (p_size == 0) {
- // If empty, add single trinagle to suppress errors.
+ if (indices.is_empty()) {
+ // If empty, add single triangle to suppress errors.
vertices.push_back(Vector3());
normals.push_back(Vector3());
uvs.push_back(Vector2());
@@ -2611,6 +2811,9 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &TextMesh::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &TextMesh::get_horizontal_alignment);
+ ClassDB::bind_method(D_METHOD("set_vertical_alignment", "alignment"), &TextMesh::set_vertical_alignment);
+ ClassDB::bind_method(D_METHOD("get_vertical_alignment"), &TextMesh::get_vertical_alignment);
+
ClassDB::bind_method(D_METHOD("set_text", "text"), &TextMesh::set_text);
ClassDB::bind_method(D_METHOD("get_text"), &TextMesh::get_text);
@@ -2620,6 +2823,12 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_size", "font_size"), &TextMesh::set_font_size);
ClassDB::bind_method(D_METHOD("get_font_size"), &TextMesh::get_font_size);
+ ClassDB::bind_method(D_METHOD("set_line_spacing", "line_spacing"), &TextMesh::set_line_spacing);
+ ClassDB::bind_method(D_METHOD("get_line_spacing"), &TextMesh::get_line_spacing);
+
+ ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &TextMesh::set_autowrap_mode);
+ ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &TextMesh::get_autowrap_mode);
+
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &TextMesh::set_depth);
ClassDB::bind_method(D_METHOD("get_depth"), &TextMesh::get_depth);
@@ -2629,16 +2838,15 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pixel_size", "pixel_size"), &TextMesh::set_pixel_size);
ClassDB::bind_method(D_METHOD("get_pixel_size"), &TextMesh::get_pixel_size);
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &TextMesh::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &TextMesh::get_offset);
+
ClassDB::bind_method(D_METHOD("set_curve_step", "curve_step"), &TextMesh::set_curve_step);
ClassDB::bind_method(D_METHOD("get_curve_step"), &TextMesh::get_curve_step);
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);
@@ -2655,23 +2863,27 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("_request_update"), &TextMesh::_request_update);
ADD_GROUP("Text", "");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_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"), "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::INT, "vertical_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom"), "set_vertical_alignment", "get_vertical_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_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
ADD_GROUP("Mesh", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "curve_step", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "set_curve_step", "get_curve_step");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.0,100.0,0.001,or_greater"), "set_depth", "get_depth");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001,suffix:m"), "set_pixel_size", "get_pixel_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "curve_step", PROPERTY_HINT_RANGE, "0.1,10,0.1,suffix:px"), "set_curve_step", "get_curve_step");
+ 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_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
- 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) {
@@ -2688,68 +2900,26 @@ 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();
}
TextMesh::~TextMesh() {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free_rid(lines_rid[i]);
+ }
+ lines_rid.clear();
+
TS->free_rid(text_rid);
}
void TextMesh::set_horizontal_alignment(HorizontalAlignment p_alignment) {
ERR_FAIL_INDEX((int)p_alignment, 4);
if (horizontal_alignment != p_alignment) {
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ dirty_lines = true;
+ }
horizontal_alignment = p_alignment;
_request_update();
}
@@ -2759,6 +2929,18 @@ HorizontalAlignment TextMesh::get_horizontal_alignment() const {
return horizontal_alignment;
}
+void TextMesh::set_vertical_alignment(VerticalAlignment p_alignment) {
+ ERR_FAIL_INDEX((int)p_alignment, 4);
+ if (vertical_alignment != p_alignment) {
+ vertical_alignment = p_alignment;
+ _request_update();
+ }
+}
+
+VerticalAlignment TextMesh::get_vertical_alignment() const {
+ return vertical_alignment;
+}
+
void TextMesh::set_text(const String &p_string) {
if (text != p_string) {
text = p_string;
@@ -2798,18 +2980,18 @@ 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;
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
}
}
}
@@ -2817,17 +2999,17 @@ Ref<Font> TextMesh::_get_font_or_default() const {
// Lastly, fall back on the items defined in the default Theme, if they exist.
{
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
}
}
}
// If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
}
void TextMesh::set_font_size(int p_size) {
@@ -2843,6 +3025,29 @@ int TextMesh::get_font_size() const {
return font_size;
}
+void TextMesh::set_line_spacing(float p_line_spacing) {
+ if (line_spacing != p_line_spacing) {
+ line_spacing = p_line_spacing;
+ _request_update();
+ }
+}
+
+float TextMesh::get_line_spacing() const {
+ return line_spacing;
+}
+
+void TextMesh::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
+ if (autowrap_mode != p_mode) {
+ autowrap_mode = p_mode;
+ dirty_lines = true;
+ _request_update();
+ }
+}
+
+TextServer::AutowrapMode TextMesh::get_autowrap_mode() const {
+ return autowrap_mode;
+}
+
void TextMesh::set_depth(real_t p_depth) {
if (depth != p_depth) {
depth = MAX(p_depth, 0.0);
@@ -2857,6 +3062,7 @@ real_t TextMesh::get_depth() const {
void TextMesh::set_width(real_t p_width) {
if (width != p_width) {
width = p_width;
+ dirty_lines = true;
_request_update();
}
}
@@ -2877,6 +3083,17 @@ real_t TextMesh::get_pixel_size() const {
return pixel_size;
}
+void TextMesh::set_offset(const Point2 &p_offset) {
+ if (lbl_offset != p_offset) {
+ lbl_offset = p_offset;
+ _request_update();
+ }
+}
+
+Point2 TextMesh::get_offset() const {
+ return lbl_offset;
+}
+
void TextMesh::set_curve_step(real_t p_step) {
if (curve_step != p_step) {
curve_step = CLAMP(p_step, 0.1, 10.0);
@@ -2902,29 +3119,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 3849c92a7b..ee61f0ac55 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -75,7 +75,7 @@ public:
virtual int surface_get_array_len(int p_idx) const override;
virtual int surface_get_array_index_len(int p_idx) const override;
virtual Array surface_get_arrays(int p_surface) const override;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const override;
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
virtual Dictionary surface_get_lods(int p_surface) const override;
virtual uint32_t surface_get_format(int p_idx) const override;
virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const override;
@@ -183,13 +183,15 @@ private:
float height = 2.0;
int radial_segments = 64;
int rings = 4;
+ bool cap_top = true;
+ bool cap_bottom = true;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
public:
- static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4);
+ static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true);
void set_top_radius(const float p_radius);
float get_top_radius() const;
@@ -206,20 +208,34 @@ public:
void set_rings(const int p_rings);
int get_rings() const;
+ void set_cap_top(bool p_cap_top);
+ bool is_cap_top() const;
+
+ void set_cap_bottom(bool p_cap_bottom);
+ bool is_cap_bottom() const;
+
CylinderMesh();
};
-/**
- Similar to quadmesh but with tessellation support
+/*
+ A flat rectangle, can be used as quad or heightmap.
*/
class PlaneMesh : public PrimitiveMesh {
GDCLASS(PlaneMesh, PrimitiveMesh);
+public:
+ enum Orientation {
+ FACE_X,
+ FACE_Y,
+ FACE_Z,
+ };
+
private:
Size2 size = Size2(2.0, 2.0);
int subdivide_w = 0;
int subdivide_d = 0;
Vector3 center_offset;
+ Orientation orientation = FACE_Y;
protected:
static void _bind_methods();
@@ -238,9 +254,27 @@ public:
void set_center_offset(const Vector3 p_offset);
Vector3 get_center_offset() const;
+ void set_orientation(const Orientation p_orientation);
+ Orientation get_orientation() const;
+
PlaneMesh();
};
+VARIANT_ENUM_CAST(PlaneMesh::Orientation)
+
+/*
+ A flat rectangle, inherits from PlaneMesh but defaults to facing the Z-plane.
+*/
+class QuadMesh : public PlaneMesh {
+ GDCLASS(QuadMesh, PlaneMesh);
+
+public:
+ QuadMesh() {
+ set_orientation(FACE_Z);
+ set_size(Size2(1, 1));
+ }
+};
+
/**
A prism shapen, handy for ramps, triangles, etc.
*/
@@ -278,33 +312,6 @@ public:
};
/**
- Our original quadmesh...
-*/
-
-class QuadMesh : public PrimitiveMesh {
- GDCLASS(QuadMesh, PrimitiveMesh);
-
-private:
- Size2 size = Size2(1.0, 1.0);
- Vector3 center_offset;
-
-protected:
- static void _bind_methods();
- virtual void _create_mesh_array(Array &p_arr) const override;
-
-public:
- virtual uint32_t surface_get_format(int p_idx) const override;
-
- QuadMesh();
-
- void set_size(const Size2 &p_size);
- Size2 get_size() const;
-
- void set_center_offset(const Vector3 p_offset);
- Vector3 get_center_offset() const;
-};
-
-/**
A sphere..
*/
class SphereMesh : public PrimitiveMesh {
@@ -343,6 +350,38 @@ public:
};
/**
+ Big donut
+*/
+class TorusMesh : public PrimitiveMesh {
+ GDCLASS(TorusMesh, PrimitiveMesh);
+
+private:
+ float inner_radius = 0.5;
+ float outer_radius = 1.0;
+ int rings = 64;
+ int ring_segments = 32;
+
+protected:
+ static void _bind_methods();
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ void set_inner_radius(const float p_inner_radius);
+ float get_inner_radius() const;
+
+ void set_outer_radius(const float p_outer_radius);
+ float get_outer_radius() const;
+
+ void set_rings(const int p_rings);
+ int get_rings() const;
+
+ void set_ring_segments(const int p_ring_segments);
+ int get_ring_segments() const;
+
+ TorusMesh();
+};
+
+/**
A single point for use in particle systems
*/
@@ -467,6 +506,7 @@ private:
sharp = p_sharp;
};
};
+
struct ContourInfo {
real_t length = 0.0;
bool ccw = true;
@@ -476,6 +516,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;
@@ -483,19 +544,25 @@ 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;
+ mutable Vector<RID> lines_rid;
+
String text;
String xl_text;
int font_size = 16;
Ref<Font> font_override;
+
+ TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
float width = 500.0;
+ float line_spacing = 0.f;
+ Point2 lbl_offset;
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
+ VerticalAlignment vertical_alignment = VERTICAL_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;
@@ -505,11 +572,12 @@ private:
real_t pixel_size = 0.01;
real_t curve_step = 0.5;
+ mutable bool dirty_lines = true;
mutable bool dirty_text = true;
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:
@@ -518,10 +586,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)
@@ -531,6 +595,9 @@ public:
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
+ void set_vertical_alignment(VerticalAlignment p_alignment);
+ VerticalAlignment get_vertical_alignment() const;
+
void set_text(const String &p_string);
String get_text() const;
@@ -541,13 +608,15 @@ public:
void set_font_size(int p_size);
int get_font_size() const;
+ void set_line_spacing(float p_size);
+ float get_line_spacing() const;
+
+ void set_autowrap_mode(TextServer::AutowrapMode p_mode);
+ TextServer::AutowrapMode get_autowrap_mode() const;
+
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;
@@ -571,7 +640,11 @@ public:
void set_pixel_size(real_t p_amount);
real_t get_pixel_size() const;
+
+ void set_offset(const Point2 &p_offset);
+ Point2 get_offset() const;
};
VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
-#endif
+
+#endif // PRIMITIVE_MESHES_H
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index 5e88c9974c..6ebf96db8e 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -41,7 +41,7 @@ void RectangleShape2D::_update_shape() {
bool RectangleShape2D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "extents") { // Compatibility with Godot 3.x.
// Convert to `size`, twice as big.
- set_size((Vector2)p_value * 2);
+ set_size((Size2)p_value * 2);
return true;
}
return false;
@@ -57,13 +57,13 @@ bool RectangleShape2D::_get(const StringName &p_name, Variant &r_property) const
}
#endif // DISABLE_DEPRECATED
-void RectangleShape2D::set_size(const Vector2 &p_size) {
+void RectangleShape2D::set_size(const Size2 &p_size) {
ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0, "RectangleShape2D size cannot be negative.");
size = p_size;
_update_shape();
}
-Vector2 RectangleShape2D::get_size() const {
+Size2 RectangleShape2D::get_size() const {
return size;
}
@@ -101,11 +101,11 @@ void RectangleShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &RectangleShape2D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &RectangleShape2D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
}
RectangleShape2D::RectangleShape2D() :
Shape2D(PhysicsServer2D::get_singleton()->rectangle_shape_create()) {
- size = Vector2(20, 20);
+ size = Size2(20, 20);
_update_shape();
}
diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h
index fa85aef428..9cc7b999be 100644
--- a/scene/resources/rectangle_shape_2d.h
+++ b/scene/resources/rectangle_shape_2d.h
@@ -36,7 +36,7 @@
class RectangleShape2D : public Shape2D {
GDCLASS(RectangleShape2D, Shape2D);
- Vector2 size;
+ Size2 size;
void _update_shape();
protected:
@@ -47,8 +47,8 @@ protected:
#endif // DISABLE_DEPRECATED
public:
- void set_size(const Vector2 &p_size);
- Vector2 get_size() const;
+ void set_size(const Size2 &p_size);
+ Size2 get_size() const;
virtual void draw(const RID &p_to_rid, const Color &p_color) override;
virtual Rect2 get_rect() const override;
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 193bd0ac05..0d798d2e27 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -40,6 +40,8 @@
// Version 3: new string ID for ext/subresources, breaks forward compat.
#define FORMAT_VERSION 3
+#define BINARY_FORMAT_VERSION 4
+
#include "core/io/dir_access.h"
#include "core/version.h"
@@ -63,18 +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)) {
- Ref<DummyResource> dr;
- dr.instantiate();
- dr->set_scene_unique_id(unique_id);
- p_data->resource_map[unique_id] = dr;
- uint32_t im_size = p_data->resource_index_map.size();
- p_data->resource_index_map.insert(dr, im_size);
- }
+ 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) {
@@ -93,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) {
@@ -214,6 +220,15 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated
}
+ HashSet<StringName> path_properties;
+
+ if (next_tag.fields.has("node_paths")) {
+ Vector<String> paths = next_tag.fields["node_paths"];
+ for (int i = 0; i < paths.size(); i++) {
+ path_properties.insert(paths[i]);
+ }
+ }
+
if (next_tag.fields.has("instance")) {
instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
@@ -278,9 +293,10 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
}
if (!assign.is_empty()) {
- int nameidx = packed_scene->get_state()->add_name(assign);
+ StringName assign_name = assign;
+ int nameidx = packed_scene->get_state()->add_name(assign_name);
int valueidx = packed_scene->get_state()->add_value(value);
- packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx);
+ packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx, path_properties.has(assign_name));
//it's assignment
} else if (!next_tag.name.is_empty()) {
break;
@@ -435,7 +451,7 @@ Error ResourceLoaderText::load() {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
}
if (remaps.has(path)) {
@@ -528,9 +544,9 @@ Error ResourceLoaderText::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//reuse existing
- Resource *r = ResourceCache::get(path);
- if (r && r->get_class() == type) {
- res = Ref<Resource>(r);
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache.is_valid() && cache->get_class() == type) {
+ res = cache;
res->reset_state();
do_assign = true;
}
@@ -539,10 +555,10 @@ Error ResourceLoaderText::load() {
MissingResource *missing_resource = nullptr;
if (res.is_null()) { //not reuse
- if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist
//cached, do not assign
- Resource *r = ResourceCache::get(path);
- res = Ref<Resource>(r);
+ res = cache;
} else {
//create
@@ -652,12 +668,10 @@ Error ResourceLoaderText::load() {
return error;
}
- if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) {
- Resource *r = ResourceCache::get(local_path);
- if (r->get_class() == res_type) {
- r->reset_state();
- resource = Ref<Resource>(r);
- }
+ Ref<Resource> cache = ResourceCache::get_ref(local_path);
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) {
+ cache->reset_state();
+ resource = cache;
}
MissingResource *missing_resource = nullptr;
@@ -847,7 +861,7 @@ void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_d
if (!using_uid && !path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
}
if (p_add_types) {
@@ -924,7 +938,7 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
}
bool relative = false;
if (!path.begins_with("res://")) {
- path = base_path.plus_file(path).simplify_path();
+ path = base_path.path_join(path).simplify_path();
relative = true;
}
@@ -1060,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;
}
@@ -1078,7 +1092,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
wf->store_32(0); //64 bits file, false for now
wf->store_32(VERSION_MAJOR);
wf->store_32(VERSION_MINOR);
- static const int save_format_version = 3; //use format version 3 for saving
+ static const int save_format_version = BINARY_FORMAT_VERSION;
wf->store_32(save_format_version);
bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type);
@@ -1176,7 +1190,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
String type;
- int id = -1;
+ String id;
bool main_res;
if (next_tag.name == "sub_resource") {
@@ -1197,15 +1211,26 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
type = next_tag.fields["type"];
id = next_tag.fields["id"];
main_res = false;
+
+ if (!dummy_read.resource_map.has(id)) {
+ Ref<DummyResource> dr;
+ dr.instantiate();
+ dr->set_scene_unique_id(id);
+ dummy_read.resource_map[id] = dr;
+ uint32_t im_size = dummy_read.resource_index_map.size();
+ dummy_read.resource_index_map.insert(dr, im_size);
+ }
+
} else {
type = res_type;
- id = 0; //used for last anyway
+ String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid);
+ id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0");
main_res = true;
}
local_offsets.push_back(wf2->get_position());
- bs_save_unicode_string(wf, "local://" + itos(id));
+ bs_save_unicode_string(wf, "local://" + id);
local_pointers_pos.push_back(wf->get_position());
wf->store_64(0); //temp local offset
@@ -1254,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!";
@@ -1274,7 +1299,8 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
List<PropertyInfo> props;
packed_scene->get_property_list(&props);
- bs_save_unicode_string(wf, "local://0");
+ String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0");
+ bs_save_unicode_string(wf, "local://" + id);
local_pointers_pos.push_back(wf->get_position());
wf->store_64(0); //temp local offset
@@ -1328,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;
@@ -1455,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") {
@@ -1543,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);
}
/*****************************************************************************************************/
@@ -1564,17 +1730,17 @@ String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Res
String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) {
if (external_resources.has(res)) {
- return "ExtResource( \"" + external_resources[res] + "\" )";
+ return "ExtResource(\"" + external_resources[res] + "\")";
} else {
if (internal_resources.has(res)) {
- return "SubResource( \"" + internal_resources[res] + "\" )";
+ return "SubResource(\"" + internal_resources[res] + "\")";
} else if (!res->is_built_in()) {
if (res->get_path() == local_path) { //circular reference attempt
return "null";
}
//external resource
String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path();
- return "Resource( \"" + path + "\" )";
+ return "Resource(\"" + path + "\")";
} else {
ERR_FAIL_V_MSG("null", "Resource was not pre cached for the resource section, bug?");
//internal resource
@@ -1737,7 +1903,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
#ifdef TOOLS_ENABLED
// Keep order from cached ids.
- RBSet<String> cached_ids_found;
+ HashSet<String> cached_ids_found;
for (KeyValue<Ref<Resource>, String> &E : external_resources) {
String cached_id = E.key->get_id_for_path(local_path);
if (cached_id.is_empty() || cached_ids_found.has(cached_id)) {
@@ -1809,7 +1975,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
f->store_line(String()); // Separate.
}
- RBSet<String> used_unique_ids;
+ HashSet<String> used_unique_ids;
for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) {
Ref<Resource> res = E->get();
@@ -1891,7 +2057,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
}
if (PE->get().type == Variant::OBJECT && missing_resource_properties.has(PE->get().name)) {
- // Was this missing resource overriden? If so do not save the old value.
+ // Was this missing resource overridden? If so do not save the old value.
Ref<Resource> ures = value;
if (ures.is_null()) {
value = missing_resource_properties[PE->get().name];
@@ -1931,6 +2097,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
Ref<PackedScene> instance = state->get_node_instance(i);
String instance_placeholder = state->get_node_instance_placeholder(i);
Vector<StringName> groups = state->get_node_groups(i);
+ Vector<String> deferred_node_paths = state->get_node_deferred_nodepath_properties(i);
String header = "[node";
header += " name=\"" + String(name).c_escape() + "\"";
@@ -1947,6 +2114,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
header += " index=\"" + itos(index) + "\"";
}
+ if (deferred_node_paths.size()) {
+ header += " node_paths=" + Variant(deferred_node_paths).get_construct_string();
+ }
+
if (groups.size()) {
// Write all groups on the same line as they're part of a section header.
// This improves readability while not impacting VCS friendliness too much,
@@ -2040,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 adab503599..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);
@@ -165,7 +169,7 @@ class ResourceFormatSaverTextInstance {
RBMap<NonPersistentKey, Ref<Resource>> non_persistent_map;
- RBSet<Ref<Resource>> resource_set;
+ HashSet<Ref<Resource>> resource_set;
List<Ref<Resource>> saved_resources;
HashMap<Ref<Resource>, String> external_resources;
HashMap<Ref<Resource>, String> internal_resources;
@@ -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 2acc0f1922..0000000000
--- a/scene/resources/scene_replication_config.cpp
+++ /dev/null
@@ -1,187 +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;
- sync_props.push_back(prop.name);
- return true;
- } else if (what == "spawn") {
- prop.spawn = p_value;
- spawn_props.push_back(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);
-}
-
-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("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/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index cea8ca1b29..d53c777492 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -88,8 +88,8 @@ void SegmentShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_b", "b"), &SegmentShape2D::set_b);
ClassDB::bind_method(D_METHOD("get_b"), &SegmentShape2D::get_b);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "a"), "set_a", "get_a");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "b"), "set_b", "get_b");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "a", PROPERTY_HINT_NONE, "suffix:px"), "set_a", "get_a");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "b", PROPERTY_HINT_NONE, "suffix:px"), "set_b", "get_b");
}
SegmentShape2D::SegmentShape2D() :
diff --git a/scene/resources/separation_ray_shape_2d.cpp b/scene/resources/separation_ray_shape_2d.cpp
index df7b0d969a..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)),
@@ -89,7 +89,7 @@ void SeparationRayShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_slope", "active"), &SeparationRayShape2D::set_slide_on_slope);
ClassDB::bind_method(D_METHOD("get_slide_on_slope"), &SeparationRayShape2D::get_slide_on_slope);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_slope"), "set_slide_on_slope", "get_slide_on_slope");
}
diff --git a/scene/resources/separation_ray_shape_3d.cpp b/scene/resources/separation_ray_shape_3d.cpp
index 736cb60c1c..7306d5b985 100644
--- a/scene/resources/separation_ray_shape_3d.cpp
+++ b/scene/resources/separation_ray_shape_3d.cpp
@@ -80,7 +80,7 @@ void SeparationRayShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_slope", "active"), &SeparationRayShape3D::set_slide_on_slope);
ClassDB::bind_method(D_METHOD("get_slide_on_slope"), &SeparationRayShape3D::get_slide_on_slope);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_slope"), "set_slide_on_slope", "get_slide_on_slope");
}
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..4d566178a5 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, 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,24 +100,28 @@ 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_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
List<PropertyInfo> local;
- RenderingServer::get_singleton()->shader_get_param_list(shader, &local);
+ RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local);
params_cache.clear();
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) {
@@ -97,35 +138,35 @@ RID Shader::get_rid() const {
return shader;
}
-void Shader::set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index) {
+void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index) {
if (p_texture.is_valid()) {
- if (!default_textures.has(p_param)) {
- default_textures[p_param] = HashMap<int, Ref<Texture2D>>();
+ if (!default_textures.has(p_name)) {
+ default_textures[p_name] = HashMap<int, Ref<Texture2D>>();
}
- default_textures[p_param][p_index] = p_texture;
- RS::get_singleton()->shader_set_default_texture_param(shader, p_param, p_texture->get_rid(), p_index);
+ default_textures[p_name][p_index] = p_texture;
+ RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, p_texture->get_rid(), p_index);
} else {
- if (default_textures.has(p_param) && default_textures[p_param].has(p_index)) {
- default_textures[p_param].erase(p_index);
+ if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) {
+ default_textures[p_name].erase(p_index);
- if (default_textures[p_param].is_empty()) {
- default_textures.erase(p_param);
+ if (default_textures[p_name].is_empty()) {
+ default_textures.erase(p_name);
}
}
- RS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID(), p_index);
+ RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, RID(), p_index);
}
emit_changed();
}
-Ref<Texture2D> Shader::get_default_texture_param(const StringName &p_param, int p_index) const {
- if (default_textures.has(p_param) && default_textures[p_param].has(p_index)) {
- return default_textures[p_param][p_index];
+Ref<Texture2D> Shader::get_default_texture_parameter(const StringName &p_name, int p_index) const {
+ if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) {
+ return default_textures[p_name][p_index];
}
return Ref<Texture2D>();
}
-void Shader::get_default_texture_param_list(List<StringName> *r_textures) const {
+void Shader::get_default_texture_parameter_list(List<StringName> *r_textures) const {
for (const KeyValue<StringName, HashMap<int, Ref<Texture2D>>> &E : default_textures) {
r_textures->push_back(E.key);
}
@@ -135,8 +176,8 @@ bool Shader::is_text_shader() const {
return true;
}
-bool Shader::has_param(const StringName &p_param) const {
- return params_cache.has("shader_param/" + p_param);
+bool Shader::has_parameter(const StringName &p_name) const {
+ return params_cache.has("shader_parameter/" + p_name);
}
void Shader::_update_shader() const {
@@ -148,10 +189,10 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_code", "code"), &Shader::set_code);
ClassDB::bind_method(D_METHOD("get_code"), &Shader::get_code);
- ClassDB::bind_method(D_METHOD("set_default_texture_param", "param", "texture", "index"), &Shader::set_default_texture_param, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_default_texture_param", "param", "index"), &Shader::get_default_texture_param, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("set_default_texture_parameter", "name", "texture", "index"), &Shader::set_default_texture_parameter, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_default_texture_parameter", "name", "index"), &Shader::get_default_texture_parameter, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param);
+ ClassDB::bind_method(D_METHOD("has_parameter", "name"), &Shader::has_parameter);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code");
@@ -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..57be142a95 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,27 +73,58 @@ 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;
- bool has_param(const StringName &p_param) const;
+ void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
+ bool has_parameter(const StringName &p_name) const;
- void set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index = 0);
- Ref<Texture2D> get_default_texture_param(const StringName &p_param, int p_index = 0) const;
- void get_default_texture_param_list(List<StringName> *r_textures) const;
+ void set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index = 0);
+ Ref<Texture2D> get_default_texture_parameter(const StringName &p_name, int p_index = 0) const;
+ void get_default_texture_parameter_list(List<StringName> *r_textures) const;
virtual bool is_text_shader() const;
- _FORCE_INLINE_ StringName remap_param(const StringName &p_param) const {
+ // Finds the shader parameter name for the given property name, which should start with "shader_parameter/".
+ _FORCE_INLINE_ StringName remap_parameter(const StringName &p_property) const {
if (params_cache_dirty) {
- get_param_list(nullptr);
+ get_shader_uniform_list(nullptr);
}
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_param);
- if (E) {
- return E->value;
+ String n = p_property;
+
+ // Backwards compatibility with old shader parameter names.
+ // Note: The if statements are important to make sure we are only replacing text exactly at index 0.
+ if (n.find("param/") == 0) {
+ n = n.replace_first("param/", "shader_parameter/");
+ }
+ if (n.find("shader_param/") == 0) {
+ n = n.replace_first("shader_param/", "shader_parameter/");
}
+ if (n.find("shader_uniform/") == 0) {
+ n = n.replace_first("shader_uniform/", "shader_parameter/");
+ }
+
+ {
+ // Additional backwards compatibility for projects between #62972 and #64092 (about a month of v4.0 development).
+ // These projects did not have any prefix for shader uniforms due to a bug.
+ // This code should be removed during beta or rc of 4.0.
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
+ if (E) {
+ return E->value;
+ }
+ }
+
+ if (n.begins_with("shader_parameter/")) {
+ n = n.replace_first("shader_parameter/", "");
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
+ if (E) {
+ return E->value;
+ }
+ }
+
return StringName();
}
@@ -111,7 +146,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..fe628dd323
--- /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, 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/camera_effects.h b/scene/resources/shader_include.h
index 85ae64cdf5..b0865e3a61 100644
--- a/scene/resources/camera_effects.h
+++ b/scene/resources/shader_include.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* camera_effects.h */
+/* shader_include.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,68 +28,44 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CAMERA_EFFECTS_H
-#define CAMERA_EFFECTS_H
+#ifndef SHADER_INCLUDE_H
+#define SHADER_INCLUDE_H
#include "core/io/resource.h"
-#include "core/templates/rid.h"
+#include "core/io/resource_loader.h"
+#include "core/io/resource_saver.h"
+#include "core/templates/hash_set.h"
-class CameraEffects : public Resource {
- GDCLASS(CameraEffects, Resource);
+class ShaderInclude : public Resource {
+ GDCLASS(ShaderInclude, Resource);
+ OBJ_SAVE_TYPE(ShaderInclude);
private:
- RID camera_effects;
-
- // DOF blur
- bool dof_blur_far_enabled = false;
- float dof_blur_far_distance = 10.0;
- float dof_blur_far_transition = 5.0;
-
- bool dof_blur_near_enabled = false;
- float dof_blur_near_distance = 2.0;
- float dof_blur_near_transition = 1.0;
-
- float dof_blur_amount = 0.1;
- void _update_dof_blur();
-
- // Override exposure
- bool override_exposure_enabled = false;
- float override_exposure = 1.0;
- void _update_override_exposure();
+ String code;
+ HashSet<Ref<ShaderInclude>> dependencies;
+ void _dependency_changed();
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
public:
- virtual RID get_rid() const override;
-
- // DOF blur
- void set_dof_blur_far_enabled(bool p_enabled);
- bool is_dof_blur_far_enabled() const;
- void set_dof_blur_far_distance(float p_distance);
- float get_dof_blur_far_distance() const;
- void set_dof_blur_far_transition(float p_distance);
- float get_dof_blur_far_transition() const;
-
- void set_dof_blur_near_enabled(bool p_enabled);
- bool is_dof_blur_near_enabled() const;
- void set_dof_blur_near_distance(float p_distance);
- float get_dof_blur_near_distance() const;
- void set_dof_blur_near_transition(float p_distance);
- float get_dof_blur_near_transition() const;
-
- void set_dof_blur_amount(float p_amount);
- float get_dof_blur_amount() const;
+ void set_code(const String &p_text);
+ String get_code() const;
+};
- // Override exposure
- void set_override_exposure_enabled(bool p_enabled);
- bool is_override_exposure_enabled() const;
- void set_override_exposure(float p_exposure);
- float get_override_exposure() 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;
+};
- CameraEffects();
- ~CameraEffects();
+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 // CAMERA_EFFECTS_H
+#endif // SHADER_INCLUDE_H
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 16ef45829f..fe43f345d4 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -59,39 +59,39 @@ bool Shape2D::collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_sh
return PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), nullptr, 0, r);
}
-Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) {
- ERR_FAIL_COND_V(p_shape.is_null(), Array());
+PackedVector2Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) {
+ ERR_FAIL_COND_V(p_shape.is_null(), PackedVector2Array());
const int max_contacts = 16;
Vector2 result[max_contacts * 2];
int contacts = 0;
if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, result, max_contacts, contacts)) {
- return Array();
+ return PackedVector2Array();
}
- Array results;
+ PackedVector2Array results;
results.resize(contacts * 2);
for (int i = 0; i < contacts * 2; i++) {
- results[i] = result[i];
+ results.write[i] = result[i];
}
return results;
}
-Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) {
- ERR_FAIL_COND_V(p_shape.is_null(), Array());
+PackedVector2Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) {
+ ERR_FAIL_COND_V(p_shape.is_null(), PackedVector2Array());
const int max_contacts = 16;
Vector2 result[max_contacts * 2];
int contacts = 0;
if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), result, max_contacts, contacts)) {
- return Array();
+ return PackedVector2Array();
}
- Array results;
+ PackedVector2Array results;
results.resize(contacts * 2);
for (int i = 0; i < contacts * 2; i++) {
- results[i] = result[i];
+ results.write[i] = result[i];
}
return results;
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index e9dc10eeae..a15aecee93 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -53,8 +53,8 @@ public:
bool collide_with_motion(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion);
bool collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform);
- Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion);
- Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform);
+ PackedVector2Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion);
+ PackedVector2Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform);
virtual void draw(const RID &p_to_rid, const Color &p_color) {}
virtual Rect2 get_rect() const { return Rect2(); }
diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp
index ffb2b27644..4423c1d7bb 100644
--- a/scene/resources/shape_3d.cpp
+++ b/scene/resources/shape_3d.cpp
@@ -117,7 +117,7 @@ void Shape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape3D::get_debug_mesh);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001,suffix:m"), "set_margin", "get_margin");
}
Shape3D::Shape3D() {
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.cpp b/scene/resources/skeleton_modification_2d_ccdik.cpp
index 7adaf1452c..96961a1fe4 100644
--- a/scene/resources/skeleton_modification_2d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_2d_ccdik.cpp
@@ -52,9 +52,9 @@ bool SkeletonModification2DCCDIK::_set(const StringName &p_path, const Variant &
} else if (what == "enable_constraint") {
set_ccdik_joint_enable_constraint(which, p_value);
} else if (what == "constraint_angle_min") {
- set_ccdik_joint_constraint_angle_min(which, Math::deg2rad(float(p_value)));
+ set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(float(p_value)));
} else if (what == "constraint_angle_max") {
- set_ccdik_joint_constraint_angle_max(which, Math::deg2rad(float(p_value)));
+ set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(float(p_value)));
} else if (what == "constraint_angle_invert") {
set_ccdik_joint_constraint_angle_invert(which, p_value);
} else if (what == "constraint_in_localspace") {
@@ -96,9 +96,9 @@ bool SkeletonModification2DCCDIK::_get(const StringName &p_path, Variant &r_ret)
} else if (what == "enable_constraint") {
r_ret = get_ccdik_joint_enable_constraint(which);
} else if (what == "constraint_angle_min") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_min(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which));
} else if (what == "constraint_angle_max") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_max(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which));
} else if (what == "constraint_angle_invert") {
r_ret = get_ccdik_joint_constraint_angle_invert(which);
} else if (what == "constraint_in_localspace") {
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.cpp b/scene/resources/skeleton_modification_2d_lookat.cpp
index 23e1c579dc..d3cfffb1de 100644
--- a/scene/resources/skeleton_modification_2d_lookat.cpp
+++ b/scene/resources/skeleton_modification_2d_lookat.cpp
@@ -41,15 +41,15 @@ bool SkeletonModification2DLookAt::_set(const StringName &p_path, const Variant
if (path.begins_with("enable_constraint")) {
set_enable_constraint(p_value);
} else if (path.begins_with("constraint_angle_min")) {
- set_constraint_angle_min(Math::deg2rad(float(p_value)));
+ set_constraint_angle_min(Math::deg_to_rad(float(p_value)));
} else if (path.begins_with("constraint_angle_max")) {
- set_constraint_angle_max(Math::deg2rad(float(p_value)));
+ set_constraint_angle_max(Math::deg_to_rad(float(p_value)));
} else if (path.begins_with("constraint_angle_invert")) {
set_constraint_angle_invert(p_value);
} else if (path.begins_with("constraint_in_localspace")) {
set_constraint_in_localspace(p_value);
} else if (path.begins_with("additional_rotation")) {
- set_additional_rotation(Math::deg2rad(float(p_value)));
+ set_additional_rotation(Math::deg_to_rad(float(p_value)));
}
#ifdef TOOLS_ENABLED
@@ -67,15 +67,15 @@ bool SkeletonModification2DLookAt::_get(const StringName &p_path, Variant &r_ret
if (path.begins_with("enable_constraint")) {
r_ret = get_enable_constraint();
} else if (path.begins_with("constraint_angle_min")) {
- r_ret = Math::rad2deg(get_constraint_angle_min());
+ r_ret = Math::rad_to_deg(get_constraint_angle_min());
} else if (path.begins_with("constraint_angle_max")) {
- r_ret = Math::rad2deg(get_constraint_angle_max());
+ r_ret = Math::rad_to_deg(get_constraint_angle_max());
} else if (path.begins_with("constraint_angle_invert")) {
r_ret = get_constraint_angle_invert();
} else if (path.begins_with("constraint_in_localspace")) {
r_ret = get_constraint_in_localspace();
} else if (path.begins_with("additional_rotation")) {
- r_ret = Math::rad2deg(get_additional_rotation());
+ r_ret = Math::rad_to_deg(get_additional_rotation());
}
#ifdef TOOLS_ENABLED
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.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index b08fd82381..d3c62e441f 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -464,8 +464,8 @@ void SkeletonModification2DTwoBoneIK::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx);
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0, 100000000, 0.01"), "set_target_minimum_distance", "get_target_minimum_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0, 100000000, 0.01"), "set_target_maximum_distance", "get_target_maximum_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0,100000000,0.01,suffix:m"), "set_target_minimum_distance", "get_target_minimum_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0,100000000,0.01,suffix:m"), "set_target_maximum_distance", "get_target_maximum_distance");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_bend_direction", PROPERTY_HINT_NONE, ""), "set_flip_bend_direction", "get_flip_bend_direction");
ADD_GROUP("", "");
}
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.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
index f19be47db2..3251ee4189 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_3d_ccdik.cpp
@@ -50,9 +50,9 @@ bool SkeletonModification3DCCDIK::_set(const StringName &p_path, const Variant &
} else if (what == "enable_joint_constraint") {
set_ccdik_joint_enable_constraint(which, p_value);
} else if (what == "joint_constraint_angle_min") {
- set_ccdik_joint_constraint_angle_min(which, Math::deg2rad(real_t(p_value)));
+ set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(real_t(p_value)));
} else if (what == "joint_constraint_angle_max") {
- set_ccdik_joint_constraint_angle_max(which, Math::deg2rad(real_t(p_value)));
+ set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(real_t(p_value)));
} else if (what == "joint_constraint_angles_invert") {
set_ccdik_joint_constraint_invert(which, p_value);
}
@@ -79,9 +79,9 @@ bool SkeletonModification3DCCDIK::_get(const StringName &p_path, Variant &r_ret)
} else if (what == "enable_joint_constraint") {
r_ret = get_ccdik_joint_enable_constraint(which);
} else if (what == "joint_constraint_angle_min") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_min(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which));
} else if (what == "joint_constraint_angle_max") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_max(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which));
} else if (what == "joint_constraint_angles_invert") {
r_ret = get_ccdik_joint_constraint_invert(which);
}
diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h
index 873ab8aa5a..1fe53e94b6 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.h
+++ b/scene/resources/skeleton_modification_3d_ccdik.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_CCDIK_H
+#define SKELETON_MODIFICATION_3D_CCDIK_H
+
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DCCDIK_H
-#define SKELETONMODIFICATION3DCCDIK_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.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp
index b62dda3f4f..4099208f44 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.cpp
+++ b/scene/resources/skeleton_modification_3d_fabrik.cpp
@@ -58,7 +58,7 @@ bool SkeletonModification3DFABRIK::_set(const StringName &p_path, const Variant
} else if (what == "use_target_basis") {
set_fabrik_joint_use_target_basis(which, p_value);
} else if (what == "roll") {
- set_fabrik_joint_roll(which, Math::deg2rad(real_t(p_value)));
+ set_fabrik_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
}
return true;
}
@@ -91,7 +91,7 @@ bool SkeletonModification3DFABRIK::_get(const StringName &p_path, Variant &r_ret
} else if (what == "use_target_basis") {
r_ret = get_fabrik_joint_use_target_basis(which);
} else if (what == "roll") {
- r_ret = Math::rad2deg(get_fabrik_joint_roll(which));
+ r_ret = Math::rad_to_deg(get_fabrik_joint_roll(which));
}
return true;
}
diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h
index cc4d3a5e20..e2e490d636 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.h
+++ b/scene/resources/skeleton_modification_3d_fabrik.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_FABRIK_H
+#define SKELETON_MODIFICATION_3D_FABRIK_H
+
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DFABRIK_H
-#define SKELETONMODIFICATION3DFABRIK_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.cpp b/scene/resources/skeleton_modification_3d_jiggle.cpp
index 3e36c241f7..64f26f3fda 100644
--- a/scene/resources/skeleton_modification_3d_jiggle.cpp
+++ b/scene/resources/skeleton_modification_3d_jiggle.cpp
@@ -58,7 +58,7 @@ bool SkeletonModification3DJiggle::_set(const StringName &p_path, const Variant
} else if (what == "gravity") {
set_jiggle_joint_gravity(which, p_value);
} else if (what == "roll") {
- set_jiggle_joint_roll(which, Math::deg2rad(real_t(p_value)));
+ set_jiggle_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
}
return true;
} else {
@@ -98,7 +98,7 @@ bool SkeletonModification3DJiggle::_get(const StringName &p_path, Variant &r_ret
} else if (what == "gravity") {
r_ret = get_jiggle_joint_gravity(which);
} else if (what == "roll") {
- r_ret = Math::rad2deg(get_jiggle_joint_roll(which));
+ r_ret = Math::rad_to_deg(get_jiggle_joint_roll(which));
}
return true;
} else {
diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h
index 7ec5ed4f11..bd1ee51d93 100644
--- a/scene/resources/skeleton_modification_3d_jiggle.h
+++ b/scene/resources/skeleton_modification_3d_jiggle.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H
+#define SKELETON_MODIFICATION_3D_JIGGLE_H
+
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DJIGGLE_H
-#define SKELETONMODIFICATION3DJIGGLE_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.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
index 3e8c1e3a77..69167cb308 100644
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ b/scene/resources/skeleton_modification_3d_lookat.cpp
@@ -39,9 +39,9 @@ bool SkeletonModification3DLookAt::_set(const StringName &p_path, const Variant
set_lock_rotation_plane(p_value);
} else if (p_path == "additional_rotation") {
Vector3 tmp = p_value;
- tmp.x = Math::deg2rad(tmp.x);
- tmp.y = Math::deg2rad(tmp.y);
- tmp.z = Math::deg2rad(tmp.z);
+ tmp.x = Math::deg_to_rad(tmp.x);
+ tmp.y = Math::deg_to_rad(tmp.y);
+ tmp.z = Math::deg_to_rad(tmp.z);
set_additional_rotation(tmp);
}
@@ -55,9 +55,9 @@ bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret
r_ret = get_lock_rotation_plane();
} else if (p_path == "additional_rotation") {
Vector3 tmp = get_additional_rotation();
- tmp.x = Math::rad2deg(tmp.x);
- tmp.y = Math::rad2deg(tmp.y);
- tmp.z = Math::rad2deg(tmp.z);
+ tmp.x = Math::rad_to_deg(tmp.x);
+ tmp.y = Math::rad_to_deg(tmp.y);
+ tmp.z = Math::rad_to_deg(tmp.z);
r_ret = tmp;
}
diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h
index 9f5120a0fd..cea63fc34f 100644
--- a/scene/resources/skeleton_modification_3d_lookat.h
+++ b/scene/resources/skeleton_modification_3d_lookat.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_LOOKAT_H
+#define SKELETON_MODIFICATION_3D_LOOKAT_H
+
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DLOOKAT_H
-#define SKELETONMODIFICATION3DLOOKAT_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..2071de5457 100644
--- a/scene/resources/skeleton_modification_3d_stackholder.h
+++ b/scene/resources/skeleton_modification_3d_stackholder.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_STACKHOLDER_H
+#define SKELETON_MODIFICATION_3D_STACKHOLDER_H
+
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DSTACKHOLDER_H
-#define SKELETONMODIFICATION3DSTACKHOLDER_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.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp
index acc5ff716c..366fcc30b7 100644
--- a/scene/resources/skeleton_modification_3d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_3d_twoboneik.cpp
@@ -54,13 +54,13 @@ bool SkeletonModification3DTwoBoneIK::_set(const StringName &p_path, const Varia
} else if (path == "joint_one/bone_idx") {
set_joint_one_bone_idx(p_value);
} else if (path == "joint_one/roll") {
- set_joint_one_roll(Math::deg2rad(real_t(p_value)));
+ set_joint_one_roll(Math::deg_to_rad(real_t(p_value)));
} else if (path == "joint_two/bone_name") {
set_joint_two_bone_name(p_value);
} else if (path == "joint_two/bone_idx") {
set_joint_two_bone_idx(p_value);
} else if (path == "joint_two/roll") {
- set_joint_two_roll(Math::deg2rad(real_t(p_value)));
+ set_joint_two_roll(Math::deg_to_rad(real_t(p_value)));
}
return true;
@@ -88,13 +88,13 @@ bool SkeletonModification3DTwoBoneIK::_get(const StringName &p_path, Variant &r_
} else if (path == "joint_one/bone_idx") {
r_ret = get_joint_one_bone_idx();
} else if (path == "joint_one/roll") {
- r_ret = Math::rad2deg(get_joint_one_roll());
+ r_ret = Math::rad_to_deg(get_joint_one_roll());
} else if (path == "joint_two/bone_name") {
r_ret = get_joint_two_bone_name();
} else if (path == "joint_two/bone_idx") {
r_ret = get_joint_two_bone_idx();
} else if (path == "joint_two/roll") {
- r_ret = Math::rad2deg(get_joint_two_roll());
+ r_ret = Math::rad_to_deg(get_joint_two_roll());
}
return true;
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h
index a4ddc6cee7..7bd7c8291d 100644
--- a/scene/resources/skeleton_modification_3d_twoboneik.h
+++ b/scene/resources/skeleton_modification_3d_twoboneik.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_TWOBONEIK_H
+#define SKELETON_MODIFICATION_3D_TWOBONEIK_H
+
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETONMODIFICATION3DTWOBONEIK_H
-#define SKELETONMODIFICATION3DTWOBONEIK_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.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index 38ec19828f..56234a8a14 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -138,7 +138,7 @@ void SkeletonModificationStack2D::set_editor_gizmos_dirty(bool p_dirty) {
if (!editor_gizmo_dirty && p_dirty) {
editor_gizmo_dirty = p_dirty;
if (skeleton) {
- skeleton->update();
+ skeleton->queue_redraw();
}
} else {
editor_gizmo_dirty = p_dirty;
@@ -182,11 +182,11 @@ void SkeletonModificationStack2D::delete_modification(int p_mod_idx) {
void SkeletonModificationStack2D::set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod) {
ERR_FAIL_INDEX(p_mod_idx, modifications.size());
- if (p_mod == nullptr) {
- modifications.insert(p_mod_idx, nullptr);
+ if (p_mod.is_null()) {
+ modifications.write[p_mod_idx] = Ref<SkeletonModification2D>();
} else {
+ modifications.write[p_mod_idx] = p_mod;
p_mod->_setup_modification(this);
- modifications.insert(p_mod_idx, p_mod);
}
#ifdef TOOLS_ENABLED
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..61a0350440
--- /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 &p_property) const {
+ if (is_read_only) {
+ if (p_property.name == ("group_size") || p_property.name == ("bone_size") || p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+ }
+
+ if (p_property.name == ("root_bone") || p_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);
+ }
+ p_property.hint_string = hint;
+ }
+
+ PackedStringArray split = p_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) {
+ p_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 = false;
+
+ 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, 0.816, 0.577, -1, 0, 0, -0.025, 0.025, 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, 0.816, 0.577, 1, 0, 0, 0.025, 0.025, 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..66344d954d
--- /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);
+ void _validate_property(PropertyInfo &p_property) const;
+ 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/skin.cpp b/scene/resources/skin.cpp
index 54ed71999c..1c04ba0cd4 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -130,11 +130,12 @@ bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
}
void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::INT, "bind_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("bind_count"), PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
for (int i = 0; i < get_bind_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bind/" + itos(i) + "/name"));
- p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, "bind/" + itos(i) + "/pose"));
+ const String prefix = vformat("%s/%d/", PNAME("bind"), i);
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, prefix + PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::INT, prefix + PNAME("bone"), PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prefix + PNAME("pose")));
}
}
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index 7874d77298..d21f04fab8 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -30,10 +30,11 @@
#include "sky_material.h"
+#include "core/config/project_settings.h"
#include "core/version.h"
Mutex ProceduralSkyMaterial::shader_mutex;
-RID ProceduralSkyMaterial::shader;
+RID ProceduralSkyMaterial::shader_cache[2];
void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
sky_top_color = p_sky_top;
@@ -62,13 +63,13 @@ float ProceduralSkyMaterial::get_sky_curve() const {
return sky_curve;
}
-void ProceduralSkyMaterial::set_sky_energy(float p_energy) {
- sky_energy = p_energy;
- RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy);
+void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {
+ sky_energy_multiplier = p_multiplier;
+ RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy_multiplier);
}
-float ProceduralSkyMaterial::get_sky_energy() const {
- return sky_energy;
+float ProceduralSkyMaterial::get_sky_energy_multiplier() const {
+ return sky_energy_multiplier;
}
void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {
@@ -117,18 +118,18 @@ float ProceduralSkyMaterial::get_ground_curve() const {
return ground_curve;
}
-void ProceduralSkyMaterial::set_ground_energy(float p_energy) {
- ground_energy = p_energy;
- RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy);
+void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {
+ ground_energy_multiplier = p_multiplier;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy_multiplier);
}
-float ProceduralSkyMaterial::get_ground_energy() const {
- return ground_energy;
+float ProceduralSkyMaterial::get_ground_energy_multiplier() const {
+ return ground_energy_multiplier;
}
void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {
sun_angle_max = p_angle;
- RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::deg2rad(sun_angle_max));
+ RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::deg_to_rad(sun_angle_max));
}
float ProceduralSkyMaterial::get_sun_angle_max() const {
@@ -144,13 +145,17 @@ float ProceduralSkyMaterial::get_sun_curve() const {
return sun_curve;
}
-void ProceduralSkyMaterial::set_dither_strength(float p_dither_strength) {
- dither_strength = p_dither_strength;
- RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength);
+void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
+ use_debanding = p_use_debanding;
+ _update_shader();
+ // Only set if shader already compiled
+ if (shader_set) {
+ RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
+ }
}
-float ProceduralSkyMaterial::get_dither_strength() const {
- return dither_strength;
+bool ProceduralSkyMaterial::get_use_debanding() const {
+ return use_debanding;
}
Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
@@ -160,7 +165,8 @@ Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
RID ProceduralSkyMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
- RS::get_singleton()->material_set_shader(_get_material(), shader);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
shader_set = true;
}
return _get_material();
@@ -168,7 +174,13 @@ RID ProceduralSkyMaterial::get_rid() const {
RID ProceduralSkyMaterial::get_shader_rid() const {
_update_shader();
- return shader;
+ return shader_cache[int(use_debanding)];
+}
+
+void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
+ if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void ProceduralSkyMaterial::_bind_methods() {
@@ -181,8 +193,8 @@ void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);
ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);
- ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSkyMaterial::set_sky_energy);
- ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSkyMaterial::get_sky_energy);
+ ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);
ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);
@@ -199,8 +211,8 @@ void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);
ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);
- ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSkyMaterial::set_ground_energy);
- ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSkyMaterial::get_ground_energy);
+ ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);
ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);
@@ -208,14 +220,14 @@ void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);
ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);
- ClassDB::bind_method(D_METHOD("set_dither_strength", "strength"), &ProceduralSkyMaterial::set_dither_strength);
- ClassDB::bind_method(D_METHOD("get_dither_strength"), &ProceduralSkyMaterial::get_dither_strength);
+ ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);
+ ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");
@@ -223,53 +235,48 @@ void ProceduralSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");
ADD_GROUP("Sun", "sun_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
ADD_GROUP("", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
}
void ProceduralSkyMaterial::cleanup_shader() {
- if (shader.is_valid()) {
- RS::get_singleton()->free(shader);
+ if (shader_cache[0].is_valid()) {
+ RS::get_singleton()->free(shader_cache[0]);
+ RS::get_singleton()->free(shader_cache[1]);
}
}
void ProceduralSkyMaterial::_update_shader() {
shader_mutex.lock();
- if (shader.is_null()) {
- shader = RS::get_singleton()->shader_create();
+ if (shader_cache[0].is_null()) {
+ for (int i = 0; i < 2; i++) {
+ shader_cache[i] = RS::get_singleton()->shader_create();
- // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
- RS::get_singleton()->shader_set_code(shader, R"(
+ // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
+ RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.
shader_type sky;
+%s
-uniform vec4 sky_top_color : hint_color = vec4(0.385, 0.454, 0.55, 1.0);
-uniform vec4 sky_horizon_color : hint_color = vec4(0.646, 0.656, 0.67, 1.0);
+uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
+uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float sky_curve : hint_range(0, 1) = 0.15;
-uniform float sky_energy = 1.0;
-uniform sampler2D sky_cover : hint_black_albedo;
-uniform vec4 sky_cover_modulate : hint_color = vec4(1.0, 1.0, 1.0, 1.0);
-uniform vec4 ground_bottom_color : hint_color = vec4(0.2, 0.169, 0.133, 1.0);
-uniform vec4 ground_horizon_color : hint_color = vec4(0.646, 0.656, 0.67, 1.0);
+uniform float sky_energy = 1.0; // In Lux.
+uniform sampler2D sky_cover : source_color, hint_default_black;
+uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);
+uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);
+uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float ground_curve : hint_range(0, 1) = 0.02;
uniform float ground_energy = 1.0;
uniform float sun_angle_max = 30.0;
uniform float sun_curve : hint_range(0, 1) = 0.15;
-uniform float dither_strength : hint_range(0, 10) = 1.0;
-
-// From: https://www.shadertoy.com/view/4sfGzS credit to iq
-float hash(vec3 p) {
- p = fract( p * 0.3183099 + 0.1 );
- p *= 17.0;
- return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
-}
void sky() {
float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
@@ -325,11 +332,10 @@ void sky() {
ground *= ground_energy;
COLOR = mix(ground, sky, step(0.0, EYEDIR.y));
-
- // Make optional, eliminates banding.
- COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;
}
-)");
+)",
+ i ? "render_mode use_debanding;" : ""));
+ }
}
shader_mutex.unlock();
}
@@ -338,17 +344,17 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() {
set_sky_top_color(Color(0.385, 0.454, 0.55));
set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_sky_curve(0.15);
- set_sky_energy(1.0);
+ set_sky_energy_multiplier(1.0);
set_sky_cover_modulate(Color(1, 1, 1));
set_ground_bottom_color(Color(0.2, 0.169, 0.133));
set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_ground_curve(0.02);
- set_ground_energy(1.0);
+ set_ground_energy_multiplier(1.0);
set_sun_angle_max(30.0);
set_sun_curve(0.15);
- set_dither_strength(1.0);
+ set_use_debanding(true);
}
ProceduralSkyMaterial::~ProceduralSkyMaterial() {
@@ -434,7 +440,7 @@ void PanoramaSkyMaterial::_update_shader() {
shader_type sky;
-uniform sampler2D source_panorama : %s, hint_black_albedo;
+uniform sampler2D source_panorama : %s, source_color, hint_default_black;
void sky() {
COLOR = texture(source_panorama, SKY_COORDS).rgb;
@@ -528,22 +534,26 @@ Color PhysicalSkyMaterial::get_ground_color() const {
return ground_color;
}
-void PhysicalSkyMaterial::set_exposure(float p_exposure) {
- exposure = p_exposure;
- RS::get_singleton()->material_set_param(_get_material(), "exposure", exposure);
+void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {
+ energy_multiplier = p_multiplier;
+ RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
}
-float PhysicalSkyMaterial::get_exposure() const {
- return exposure;
+float PhysicalSkyMaterial::get_energy_multiplier() const {
+ return energy_multiplier;
}
-void PhysicalSkyMaterial::set_dither_strength(float p_dither_strength) {
- dither_strength = p_dither_strength;
- RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength);
+void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
+ use_debanding = p_use_debanding;
+ _update_shader();
+ // Only set if shader already compiled
+ if (shader_set) {
+ RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
+ }
}
-float PhysicalSkyMaterial::get_dither_strength() const {
- return dither_strength;
+bool PhysicalSkyMaterial::get_use_debanding() const {
+ return use_debanding;
}
void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {
@@ -563,7 +573,8 @@ Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
RID PhysicalSkyMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
- RS::get_singleton()->material_set_shader(_get_material(), shader);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
shader_set = true;
}
return _get_material();
@@ -571,11 +582,17 @@ RID PhysicalSkyMaterial::get_rid() const {
RID PhysicalSkyMaterial::get_shader_rid() const {
_update_shader();
- return shader;
+ return shader_cache[int(use_debanding)];
+}
+
+void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "exposure_value" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
Mutex PhysicalSkyMaterial::shader_mutex;
-RID PhysicalSkyMaterial::shader;
+RID PhysicalSkyMaterial::shader_cache[2];
void PhysicalSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
@@ -602,11 +619,11 @@ void PhysicalSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);
ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);
- ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure);
- ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure);
+ ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);
- ClassDB::bind_method(D_METHOD("set_dither_strength", "strength"), &PhysicalSkyMaterial::set_dither_strength);
- ClassDB::bind_method(D_METHOD("get_dither_strength"), &PhysicalSkyMaterial::get_dither_strength);
+ ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);
+ ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);
ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);
ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);
@@ -623,47 +640,46 @@ void PhysicalSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky");
}
void PhysicalSkyMaterial::cleanup_shader() {
- if (shader.is_valid()) {
- RS::get_singleton()->free(shader);
+ if (shader_cache[0].is_valid()) {
+ RS::get_singleton()->free(shader_cache[0]);
+ RS::get_singleton()->free(shader_cache[1]);
}
}
void PhysicalSkyMaterial::_update_shader() {
shader_mutex.lock();
- if (shader.is_null()) {
- shader = RS::get_singleton()->shader_create();
+ if (shader_cache[0].is_null()) {
+ for (int i = 0; i < 2; i++) {
+ shader_cache[i] = RS::get_singleton()->shader_create();
- // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
- RS::get_singleton()->shader_set_code(shader, R"(
+ // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
+ RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.
shader_type sky;
+%s
uniform float rayleigh : hint_range(0, 64) = 2.0;
-uniform vec4 rayleigh_color : hint_color = vec4(0.3, 0.405, 0.6, 1.0);
+uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
uniform float mie : hint_range(0, 1) = 0.005;
uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;
-uniform vec4 mie_color : hint_color = vec4(0.69, 0.729, 0.812, 1.0);
+uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);
uniform float turbidity : hint_range(0, 1000) = 10.0;
uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
-uniform vec4 ground_color : hint_color = vec4(0.1, 0.07, 0.034, 1.0);
-uniform float exposure : hint_range(0, 128) = 0.1;
-uniform float dither_strength : hint_range(0, 10) = 1.0;
+uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
+uniform float exposure : hint_range(0, 128) = 1.0;
-uniform sampler2D night_sky : hint_black_albedo;
+uniform sampler2D night_sky : source_color, hint_default_black;
const vec3 UP = vec3( 0.0, 1.0, 0.0 );
-// Sun constants
-const float SUN_ENERGY = 1000.0;
-
// Optical length at zenith for molecules.
const float rayleigh_zenith_size = 8.4e3;
const float mie_zenith_size = 1.25e3;
@@ -673,17 +689,10 @@ float henyey_greenstein(float cos_theta, float g) {
return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
}
-// From: https://www.shadertoy.com/view/4sfGzS credit to iq
-float hash(vec3 p) {
- p = fract( p * 0.3183099 + 0.1 );
- p *= 17.0;
- return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
-}
-
void sky() {
if (LIGHT0_ENABLED) {
float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
- float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;
+ float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * LIGHT0_ENERGY;
float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);
// Rayleigh coefficients.
@@ -721,21 +730,21 @@ void sky() {
float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);
float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);
float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);
- vec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;
+ vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;
L0 += texture(night_sky, SKY_COORDS).xyz * extinction;
- vec3 color = (Lin + L0) * 0.04;
+ vec3 color = Lin + L0;
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
COLOR *= exposure;
- // Make optional, eliminates banding.
- COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;
} else {
// There is no sun, so display night_sky and nothing else.
- COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04;
+ COLOR = texture(night_sky, SKY_COORDS).xyz;
COLOR *= exposure;
}
}
-)");
+)",
+ i ? "render_mode use_debanding;" : ""));
+ }
}
shader_mutex.unlock();
@@ -750,8 +759,8 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
set_turbidity(10.0);
set_sun_disk_scale(1.0);
set_ground_color(Color(0.1, 0.07, 0.034));
- set_exposure(0.1);
- set_dither_strength(1.0);
+ set_energy_multiplier(1.0);
+ set_use_debanding(true);
}
PhysicalSkyMaterial::~PhysicalSkyMaterial() {
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index 8163a42519..3de1a4b26f 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/templates/rid.h"
-#include "scene/resources/material.h"
-
#ifndef SKY_MATERIAL_H
#define SKY_MATERIAL_H
+#include "core/templates/rid.h"
+#include "scene/resources/material.h"
+
class ProceduralSkyMaterial : public Material {
GDCLASS(ProceduralSkyMaterial, Material);
@@ -41,26 +41,27 @@ private:
Color sky_top_color;
Color sky_horizon_color;
float sky_curve = 0.0f;
- float sky_energy = 0.0f;
+ float sky_energy_multiplier = 0.0f;
Ref<Texture2D> sky_cover;
Color sky_cover_modulate;
Color ground_bottom_color;
Color ground_horizon_color;
float ground_curve = 0.0f;
- float ground_energy = 0.0f;
+ float ground_energy_multiplier = 0.0f;
float sun_angle_max = 0.0f;
float sun_curve = 0.0f;
- float dither_strength = 0.0f;
+ bool use_debanding = true;
static Mutex shader_mutex;
- static RID shader;
+ static RID shader_cache[2];
static void _update_shader();
mutable bool shader_set = false;
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
public:
void set_sky_top_color(const Color &p_sky_top);
@@ -72,8 +73,8 @@ public:
void set_sky_curve(float p_curve);
float get_sky_curve() const;
- void set_sky_energy(float p_energy);
- float get_sky_energy() const;
+ void set_sky_energy_multiplier(float p_multiplier);
+ float get_sky_energy_multiplier() const;
void set_sky_cover(const Ref<Texture2D> &p_sky_cover);
Ref<Texture2D> get_sky_cover() const;
@@ -90,8 +91,8 @@ public:
void set_ground_curve(float p_curve);
float get_ground_curve() const;
- void set_ground_energy(float p_energy);
- float get_ground_energy() const;
+ void set_ground_energy_multiplier(float p_energy);
+ float get_ground_energy_multiplier() const;
void set_sun_angle_max(float p_angle);
float get_sun_angle_max() const;
@@ -99,8 +100,8 @@ public:
void set_sun_curve(float p_curve);
float get_sun_curve() const;
- void set_dither_strength(float p_dither_strength);
- float get_dither_strength() const;
+ void set_use_debanding(bool p_use_debanding);
+ bool get_use_debanding() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
@@ -138,6 +139,9 @@ public:
void set_filtering_enabled(bool p_enabled);
bool is_filtering_enabled() const;
+ void set_energy_multiplier(float p_multiplier);
+ float get_energy_multiplier() const;
+
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
@@ -156,7 +160,7 @@ class PhysicalSkyMaterial : public Material {
private:
static Mutex shader_mutex;
- static RID shader;
+ static RID shader_cache[2];
float rayleigh = 0.0f;
Color rayleigh_color;
@@ -166,14 +170,15 @@ private:
float turbidity = 0.0f;
float sun_disk_scale = 0.0f;
Color ground_color;
- float exposure = 0.0f;
- float dither_strength = 0.0f;
+ float energy_multiplier = 1.0f;
+ bool use_debanding = true;
Ref<Texture2D> night_sky;
static void _update_shader();
mutable bool shader_set = false;
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
public:
void set_rayleigh_coefficient(float p_rayleigh);
@@ -200,11 +205,14 @@ public:
void set_ground_color(Color p_ground_color);
Color get_ground_color() const;
- void set_exposure(float p_exposure);
- float get_exposure() const;
+ void set_energy_multiplier(float p_multiplier);
+ float get_energy_multiplier() const;
+
+ void set_exposure_value(float p_exposure);
+ float get_exposure_value() const;
- void set_dither_strength(float p_dither_strength);
- float get_dither_strength() const;
+ void set_use_debanding(bool p_use_debanding);
+ bool get_use_debanding() const;
void set_night_sky(const Ref<Texture2D> &p_night_sky);
Ref<Texture2D> get_night_sky() const;
@@ -219,4 +227,4 @@ public:
~PhysicalSkyMaterial();
};
-#endif /* !SKY_MATERIAL_H */
+#endif // SKY_MATERIAL_H
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
index 8de0dc1650..340d0fe370 100644
--- a/scene/resources/sphere_shape_3d.cpp
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -38,8 +38,8 @@ Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -78,10 +78,10 @@ void SphereShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape3D::get_radius);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
SphereShape3D::SphereShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) {
- set_radius(1.0);
+ set_radius(0.5);
}
diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h
index 20887dd092..91d72e01ec 100644
--- a/scene/resources/sphere_shape_3d.h
+++ b/scene/resources/sphere_shape_3d.h
@@ -35,7 +35,7 @@
class SphereShape3D : public Shape3D {
GDCLASS(SphereShape3D, Shape3D);
- float radius = 1.0f;
+ float radius = 0.5f;
protected:
static void _bind_methods();
@@ -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..3533e86c3a 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("_set_animations", "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.cpp b/scene/resources/style_box.cpp
index f3cb2b9ea7..cd893d8c23 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -41,6 +41,7 @@ float StyleBox::get_style_margin(Side p_side) const {
}
return 0;
}
+
bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
bool ret;
if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) {
@@ -63,6 +64,21 @@ void StyleBox::set_default_margin(Side p_side, float p_value) {
emit_changed();
}
+void StyleBox::set_default_margin_all(float p_value) {
+ for (int i = 0; i < 4; i++) {
+ margin[i] = p_value;
+ }
+ emit_changed();
+}
+
+void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ margin[SIDE_LEFT] = p_left;
+ margin[SIDE_TOP] = p_top;
+ margin[SIDE_RIGHT] = p_right;
+ margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
float StyleBox::get_default_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
@@ -112,6 +128,7 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask);
ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin);
+ ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all);
ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin);
ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin);
@@ -122,11 +139,11 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw);
- ADD_GROUP("Content Margin", "content_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM);
+ ADD_GROUP("Content Margins", "content_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_BOTTOM);
GDVIRTUAL_BIND(_get_style_margin, "side")
GDVIRTUAL_BIND(_test_mask, "point", "rect")
@@ -165,6 +182,21 @@ void StyleBoxTexture::set_margin_size(Side p_side, float p_size) {
emit_changed();
}
+void StyleBoxTexture::set_margin_size_all(float p_size) {
+ for (int i = 0; i < 4; i++) {
+ margin[i] = p_size;
+ }
+ emit_changed();
+}
+
+void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ margin[SIDE_LEFT] = p_left;
+ margin[SIDE_TOP] = p_top;
+ margin[SIDE_RIGHT] = p_right;
+ margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
float StyleBoxTexture::get_margin_size(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
@@ -292,11 +324,11 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture);
ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size);
+ ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all);
ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxTexture::set_expand_margin_size_individual);
ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect);
@@ -315,24 +347,26 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
- ADD_GROUP("Margin", "margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM);
+ ADD_GROUP("Margins", "margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_BOTTOM);
- ADD_GROUP("Expand Margin", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM);
+ ADD_GROUP("Expand Margins", "expand_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM);
ADD_GROUP("Axis Stretch", "axis_stretch_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+ ADD_GROUP("Sub-Region", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
+
ADD_GROUP("Modulate", "modulate_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
@@ -685,7 +719,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
// Only enable antialiasing if it is actually needed. This improve performances
// and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
- const bool aa_on = (rounded_corners || !skew.is_equal_approx(Vector2())) && anti_aliased;
+ const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
const bool blend_on = blend_border && draw_border;
@@ -840,9 +874,9 @@ float StyleBoxFlat::get_style_margin(Side p_side) const {
return border_width[p_side];
}
-void StyleBoxFlat::_validate_property(PropertyInfo &property) const {
- if (!anti_aliased && property.name == "anti_aliasing_size") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void StyleBoxFlat::_validate_property(PropertyInfo &p_property) const {
+ if (!anti_aliased && p_property.name == "anti_aliasing_size") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -862,7 +896,6 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend);
ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend);
- ClassDB::bind_method(D_METHOD("set_corner_radius_individual", "radius_top_left", "radius_top_right", "radius_bottom_right", "radius_bottom_left"), &StyleBoxFlat::set_corner_radius_individual);
ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all);
ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius);
@@ -870,7 +903,6 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxFlat::set_expand_margin_size_individual);
ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
@@ -903,10 +935,10 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "skew"), "set_skew", "get_skew");
ADD_GROUP("Border Width", "border_width_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
ADD_GROUP("Border", "border_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
@@ -914,27 +946,27 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "border_blend"), "set_border_blend", "get_border_blend");
ADD_GROUP("Corner Radius", "corner_radius_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
- ADD_GROUP("Expand Margin", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
+ ADD_GROUP("Expand Margins", "expand_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_shadow_size", "get_shadow_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset"), "set_shadow_offset", "get_shadow_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
ADD_GROUP("Anti Aliasing", "anti_aliasing_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001"), "set_aa_size", "get_aa_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001,suffix:px"), "set_aa_size", "get_aa_size");
}
StyleBoxFlat::StyleBoxFlat() {}
@@ -999,9 +1031,9 @@ void StyleBoxLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_begin", "get_grow_begin");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_end", "get_grow_end");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_begin", "get_grow_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_end", "get_grow_end");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10,suffix:px"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 3b3654775f..2c72446567 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -57,7 +57,10 @@ public:
virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const;
void set_default_margin(Side p_side, float p_value);
+ void set_default_margin_all(float p_value);
+ void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_default_margin(Side p_side) const;
+
float get_margin(Side p_side) const;
virtual Size2 get_center_size() const;
@@ -112,6 +115,8 @@ public:
float get_expand_margin_size(Side p_expand_side) const;
void set_margin_size(Side p_side, float p_size);
+ void set_margin_size_all(float p_size);
+ void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_margin_size(Side p_side) const;
void set_region_rect(const Rect2 &p_region_rect);
@@ -166,7 +171,7 @@ class StyleBoxFlat : public StyleBox {
protected:
virtual float get_style_margin(Side p_side) const override;
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_bg_color(const Color &p_color);
@@ -264,4 +269,4 @@ public:
~StyleBoxLine();
};
-#endif
+#endif // STYLE_BOX_H
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 0e41eed570..9829c7e86b 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -141,7 +141,8 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h);
h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h);
h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h);
- h = hash_djb2_one_32(p_vtx.smooth_group, h);
+ h = hash_murmur3_one_32(p_vtx.smooth_group, h);
+ h = hash_fmix32(h);
return h;
}
@@ -315,19 +316,17 @@ void SurfaceTool::set_uv2(const Vector2 &p_uv2) {
last_uv2 = p_uv2;
}
-void SurfaceTool::set_custom(int p_index, const Color &p_custom) {
- ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+void SurfaceTool::set_custom(int p_channel_index, const Color &p_custom) {
+ ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT);
ERR_FAIL_COND(!begun);
- ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX);
+ ERR_FAIL_COND(last_custom_format[p_channel_index] == CUSTOM_MAX);
static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
- static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
- ERR_FAIL_COND(!first && !(format & mask[p_index]));
+ ERR_FAIL_COND(!first && !(format & mask[p_channel_index]));
if (first) {
- format |= mask[p_index];
- format |= last_custom_format[p_index] << shift[p_index];
+ format |= mask[p_channel_index];
}
- last_custom[p_index] = p_custom;
+ last_custom[p_channel_index] = p_custom;
}
void SurfaceTool::set_bones(const Vector<int> &p_bones) {
@@ -689,7 +688,7 @@ Array SurfaceTool::commit_to_arrays() {
return a;
}
-Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) {
+Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_compress_flags) {
Ref<ArrayMesh> mesh;
if (p_existing.is_valid()) {
mesh = p_existing;
@@ -707,7 +706,15 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_
Array a = commit_to_arrays();
- mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), p_flags);
+ uint32_t compress_flags = (p_compress_flags >> RS::ARRAY_COMPRESS_FLAGS_BASE) << RS::ARRAY_COMPRESS_FLAGS_BASE;
+ static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ if (last_custom_format[i] != CUSTOM_MAX) {
+ compress_flags |= last_custom_format[i] << shift[i];
+ }
+ }
+
+ mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), compress_flags);
if (material.is_valid()) {
mesh->surface_set_material(surface, material);
@@ -988,9 +995,6 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) {
if (format & custom_mask[j]) {
CustomFormat new_format = (CustomFormat)((format >> custom_shift[j]) & RS::ARRAY_FORMAT_CUSTOM_MASK);
- if (last_custom_format[j] != CUSTOM_MAX && last_custom_format[j] != new_format) {
- WARN_PRINT(vformat("Custom %d format %d mismatch when appending format %d", j, last_custom_format[j], new_format));
- }
last_custom_format[j] = new_format;
}
}
@@ -1220,22 +1224,24 @@ SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const {
return skin_weights;
}
-void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
- ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
- ERR_FAIL_COND(begun);
- last_custom_format[p_index] = p_format;
+void SurfaceTool::set_custom_format(int p_channel_index, CustomFormat p_format) {
+ ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT);
+ ERR_FAIL_COND(!begun);
+ ERR_FAIL_INDEX(p_format, CUSTOM_MAX + 1);
+ last_custom_format[p_channel_index] = p_format;
}
-Mesh::PrimitiveType SurfaceTool::get_primitive() const {
+Mesh::PrimitiveType SurfaceTool::get_primitive_type() const {
return primitive;
}
-SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
- return last_custom_format[p_index];
+SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_channel_index) const {
+ ERR_FAIL_INDEX_V(p_channel_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
+ return last_custom_format[p_channel_index];
}
void SurfaceTool::optimize_indices_for_cache() {
ERR_FAIL_COND(optimize_vertex_cache_func == nullptr);
ERR_FAIL_COND(index_array.size() == 0);
+ ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES);
ERR_FAIL_COND(index_array.size() % 3 != 0);
LocalVector old_index_array = index_array;
@@ -1243,8 +1249,8 @@ void SurfaceTool::optimize_indices_for_cache() {
optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size());
}
-float SurfaceTool::get_max_axis_length() const {
- ERR_FAIL_COND_V(vertex_array.size() == 0, 0);
+AABB SurfaceTool::get_aabb() const {
+ ERR_FAIL_COND_V(vertex_array.size() == 0, AABB());
AABB aabb;
for (uint32_t i = 0; i < vertex_array.size(); i++) {
@@ -1255,7 +1261,7 @@ float SurfaceTool::get_max_axis_length() const {
}
}
- return aabb.get_longest_axis_size();
+ return aabb;
}
Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) {
Vector<int> lod;
@@ -1288,8 +1294,8 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count);
ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count);
- ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format);
- ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format);
+ ClassDB::bind_method(D_METHOD("set_custom_format", "channel_index", "format"), &SurfaceTool::set_custom_format);
+ ClassDB::bind_method(D_METHOD("get_custom_format", "channel_index"), &SurfaceTool::get_custom_format);
ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin);
@@ -1301,7 +1307,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2);
ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones);
ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights);
- ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom);
+ ClassDB::bind_method(D_METHOD("set_custom", "channel_index", "custom_color"), &SurfaceTool::set_custom);
ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group);
ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
@@ -1315,11 +1321,11 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache);
- ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length);
+ ClassDB::bind_method(D_METHOD("get_aabb"), &SurfaceTool::get_aabb);
ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
- ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive);
+ ClassDB::bind_method(D_METHOD("get_primitive_type"), &SurfaceTool::get_primitive_type);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index bf4332ad2a..6735d6623f 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -154,10 +154,10 @@ public:
void set_skin_weight_count(SkinWeightCount p_weights);
SkinWeightCount get_skin_weight_count() const;
- void set_custom_format(int p_index, CustomFormat p_format);
- CustomFormat get_custom_format(int p_index) const;
+ void set_custom_format(int p_channel_index, CustomFormat p_format);
+ CustomFormat get_custom_format(int p_channel_index) const;
- Mesh::PrimitiveType get_primitive() const;
+ Mesh::PrimitiveType get_primitive_type() const;
void begin(Mesh::PrimitiveType p_primitive);
@@ -166,7 +166,7 @@ public:
void set_tangent(const Plane &p_tangent);
void set_uv(const Vector2 &p_uv);
void set_uv2(const Vector2 &p_uv2);
- void set_custom(int p_index, const Color &p_custom);
+ void set_custom(int p_channel_index, const Color &p_custom);
void set_bones(const Vector<int> &p_bones);
void set_weights(const Vector<float> &p_weights);
void set_smooth_group(uint32_t p_group);
@@ -183,7 +183,7 @@ public:
void generate_tangents();
void optimize_indices_for_cache();
- float get_max_axis_length() const;
+ AABB get_aabb() const;
Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
void set_material(const Ref<Material> &p_material);
@@ -199,7 +199,7 @@ public:
void create_from(const Ref<Mesh> &p_existing, int p_surface);
void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform3D &p_xform);
- Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0);
+ Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_compress_flags = 0);
SurfaceTool();
};
@@ -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 f9390ca528..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);
@@ -98,12 +98,6 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color"), &TextLine::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextLine::hit_test);
-
- BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextLine::_shape() {
@@ -112,32 +106,32 @@ void TextLine::_shape() {
TS->shaped_text_tab_align(rid, tab_stops);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_WORD_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 OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
- case OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ case TextServer::OVERRUN_TRIM_WORD:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
break;
- case OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
+ case TextServer::OVERRUN_TRIM_CHAR:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
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);
@@ -155,8 +149,6 @@ RID TextLine::get_rid() const {
void TextLine::clear() {
TS->shaped_text_clear(rid);
- spacing_top = 0;
- spacing_bottom = 0;
}
void TextLine::set_preserve_invalid(bool p_enabled) {
@@ -200,11 +192,12 @@ void TextLine::set_bidi_override(const Array &p_override) {
dirty = true;
}
-bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
- bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+bool TextLine::add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, const Variant &p_meta) {
+ ERR_FAIL_COND_V(p_font.is_null(), false);
+ bool res = TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language, p_meta);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
dirty = true;
return res;
}
@@ -248,31 +241,31 @@ 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;
}
-void TextLine::set_text_overrun_behavior(TextLine::OverrunBehavior p_behavior) {
+void TextLine::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
if (overrun_behavior != p_behavior) {
overrun_behavior = p_behavior;
dirty = true;
}
}
-TextLine::OverrunBehavior TextLine::get_text_overrun_behavior() const {
+TextServer::OverrunBehavior TextLine::get_text_overrun_behavior() const {
return overrun_behavior;
}
void TextLine::set_width(float p_width) {
width = p_width;
- if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != OVERRUN_NO_TRIMMING) {
+ if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
dirty = true;
}
}
@@ -284,20 +277,20 @@ float TextLine::get_width() const {
Size2 TextLine::get_size() const {
const_cast<TextLine *>(this)->_shape();
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
} else {
- return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
}
}
float TextLine::get_line_ascent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_ascent(rid) + spacing_top;
+ return TS->shaped_text_get_ascent(rid);
}
float TextLine::get_line_descent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_descent(rid) + spacing_bottom;
+ return TS->shaped_text_get_descent(rid);
}
float TextLine::get_line_width() const {
@@ -353,10 +346,10 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) co
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color);
@@ -400,10 +393,10 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color);
@@ -415,11 +408,14 @@ int TextLine::hit_test(float p_coords) const {
return TS->shaped_text_hit_test_position(rid, p_coords);
}
-TextLine::TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+TextLine::TextLine(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
- TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ if (p_font.is_valid()) {
+ TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
+ }
}
TextLine::TextLine() {
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index c5762db0f2..e70e82cf2b 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -39,26 +39,15 @@
class TextLine : public RefCounted {
GDCLASS(TextLine, RefCounted);
-public:
- enum OverrunBehavior {
- OVERRUN_NO_TRIMMING,
- OVERRUN_TRIM_CHAR,
- OVERRUN_TRIM_WORD,
- OVERRUN_TRIM_ELLIPSIS,
- OVERRUN_TRIM_WORD_ELLIPSIS,
- };
-
private:
RID rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
bool dirty = true;
float width = -1.0;
- uint16_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+ BitField<TextServer::JustificationFlag> flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
- OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
+ TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_TRIM_ELLIPSIS;
Vector<float> tab_stops;
@@ -86,7 +75,7 @@ public:
void set_preserve_control(bool p_enabled);
bool get_preserve_control() const;
- bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant());
+ bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
@@ -95,11 +84,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_flags(BitField<TextServer::JustificationFlag> p_flags);
+ BitField<TextServer::JustificationFlag> get_flags() const;
- void set_text_overrun_behavior(OverrunBehavior p_behavior);
- OverrunBehavior get_text_overrun_behavior() const;
+ void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
+ TextServer::OverrunBehavior get_text_overrun_behavior() const;
void set_width(float p_width);
float get_width() const;
@@ -120,11 +109,9 @@ public:
int hit_test(float p_coords) const;
- TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
+ TextLine(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextLine();
~TextLine();
};
-VARIANT_ENUM_CAST(TextLine::OverrunBehavior);
-
#endif // TEXT_LINE_H
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 61adaf43dd..7e9a2591e4 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,Trim Spaces"), "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);
@@ -129,17 +131,11 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test);
-
- BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextParagraph::_shape_lines() {
if (lines_dirty) {
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@@ -163,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;
@@ -181,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()) {
@@ -190,43 +186,43 @@ void TextParagraph::_shape_lines() {
lines_rid.push_back(line);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_WORD_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 OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
- case OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ case TextServer::OVERRUN_TRIM_WORD:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
break;
- case OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
+ case TextServer::OVERRUN_TRIM_CHAR:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
break;
- case OVERRUN_NO_TRIMMING:
+ 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, lines_rid.size()) : lines_rid.size();
- bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
+ 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 < lines_rid.size(); i++) {
- if (i < visible_lines - 1 || lines_rid.size() == 1) {
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
+ 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, jst_flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
}
@@ -238,12 +234,12 @@ void TextParagraph::_shape_lines() {
} else {
// Autowrap disabled.
- for (int i = 0; i < lines_rid.size(); i++) {
+ 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);
}
@@ -258,8 +254,10 @@ RID TextParagraph::get_rid() const {
}
RID TextParagraph::get_line_rid(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), RID());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), RID());
return lines_rid[p_line];
}
@@ -268,9 +266,9 @@ RID TextParagraph::get_dropcap_rid() const {
}
void TextParagraph::clear() {
- spacing_top = 0;
- spacing_bottom = 0;
- for (int i = 0; i < lines_rid.size(); i++) {
+ _THREAD_SAFE_METHOD_
+
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@@ -279,106 +277,133 @@ void TextParagraph::clear() {
}
void TextParagraph::set_preserve_invalid(bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_preserve_invalid(rid, p_enabled);
TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled);
lines_dirty = true;
}
bool TextParagraph::get_preserve_invalid() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_preserve_invalid(rid);
}
void TextParagraph::set_preserve_control(bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_preserve_control(rid, p_enabled);
TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled);
lines_dirty = true;
}
bool TextParagraph::get_preserve_control() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_preserve_control(rid);
}
void TextParagraph::set_direction(TextServer::Direction p_direction) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_direction(rid, p_direction);
TS->shaped_text_set_direction(dropcap_rid, p_direction);
lines_dirty = true;
}
TextServer::Direction TextParagraph::get_direction() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
return TS->shaped_text_get_direction(rid);
}
void TextParagraph::set_custom_punctuation(const String &p_punct) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_custom_punctuation(rid, p_punct);
lines_dirty = true;
}
String TextParagraph::get_custom_punctuation() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_custom_punctuation(rid);
}
void TextParagraph::set_orientation(TextServer::Orientation p_orientation) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_orientation(rid, p_orientation);
TS->shaped_text_set_orientation(dropcap_rid, p_orientation);
lines_dirty = true;
}
TextServer::Orientation TextParagraph::get_orientation() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
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) {
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
+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_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) {
- 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 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_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_
+
TS->shaped_text_set_bidi_override(rid, p_override);
lines_dirty = true;
}
bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
+ _THREAD_SAFE_METHOD_
+
bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
lines_dirty = true;
return res;
}
bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+ _THREAD_SAFE_METHOD_
+
bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
lines_dirty = true;
return res;
}
void TextParagraph::set_alignment(HorizontalAlignment p_alignment) {
+ _THREAD_SAFE_METHOD_
+
if (alignment != p_alignment) {
if (alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
alignment = p_alignment;
@@ -394,33 +419,54 @@ HorizontalAlignment TextParagraph::get_alignment() const {
}
void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
+ _THREAD_SAFE_METHOD_
+
tab_stops = p_tab_stops;
lines_dirty = true;
}
-void TextParagraph::set_flags(uint16_t p_flags) {
- if (flags != p_flags) {
- flags = p_flags;
+void TextParagraph::set_justification_flags(BitField<TextServer::JustificationFlag> p_flags) {
+ _THREAD_SAFE_METHOD_
+
+ if (jst_flags != p_flags) {
+ jst_flags = p_flags;
+ lines_dirty = true;
+ }
+}
+
+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;
}
}
-uint16_t TextParagraph::get_flags() const {
- return flags;
+BitField<TextServer::LineBreakFlag> TextParagraph::get_break_flags() const {
+ return brk_flags;
}
-void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
+void TextParagraph::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
+ _THREAD_SAFE_METHOD_
+
if (overrun_behavior != p_behavior) {
overrun_behavior = p_behavior;
lines_dirty = true;
}
}
-TextParagraph::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
+TextServer::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
return overrun_behavior;
}
void TextParagraph::set_width(float p_width) {
+ _THREAD_SAFE_METHOD_
+
if (width != p_width) {
width = p_width;
lines_dirty = true;
@@ -432,25 +478,29 @@ float TextParagraph::get_width() const {
}
Size2 TextParagraph::get_non_wrapped_size() const {
+ _THREAD_SAFE_METHOD_
+
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);
}
}
Size2 TextParagraph::get_size() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Size2 size;
- int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+ int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
for (int i = 0; i < visible_lines; i++) {
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);
}
}
@@ -458,11 +508,15 @@ Size2 TextParagraph::get_size() const {
}
int TextParagraph::get_line_count() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- return lines_rid.size();
+ return (int)lines_rid.size();
}
void TextParagraph::set_max_lines_visible(int p_lines) {
+ _THREAD_SAFE_METHOD_
+
if (p_lines != max_lines_visible) {
max_lines_visible = p_lines;
lines_dirty = true;
@@ -474,73 +528,93 @@ int TextParagraph::get_max_lines_visible() const {
}
Array TextParagraph::get_line_objects(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Array());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Array());
return TS->shaped_text_get_objects(lines_rid[p_line]);
}
Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Rect2());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Rect2());
Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
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;
}
Size2 TextParagraph::get_line_size(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Size2());
+ 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);
}
}
Vector2i TextParagraph::get_line_range(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Vector2i());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Vector2i());
return TS->shaped_text_get_range(lines_rid[p_line]);
}
float TextParagraph::get_line_ascent(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
- return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ 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]);
}
float TextParagraph::get_line_descent(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
- return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
+ 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]);
}
float TextParagraph::get_line_width(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_width(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_position(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_underline_position(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_thickness(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_underline_thickness(lines_rid[p_line]);
}
Size2 TextParagraph::get_dropcap_size() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position;
}
@@ -549,6 +623,8 @@ int TextParagraph::get_dropcap_lines() const {
}
void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs = p_pos;
float h_offset = 0.f;
@@ -571,13 +647,13 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color);
}
- int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+ int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
for (int i = 0; i < lines_visible; i++) {
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;
@@ -586,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;
@@ -641,15 +717,17 @@ 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]);
}
}
}
void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs = p_pos;
@@ -673,11 +751,11 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color);
}
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
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;
@@ -686,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;
@@ -741,15 +819,17 @@ 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]);
}
}
}
int TextParagraph::hit_test(const Point2 &p_coords) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -761,23 +841,25 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
return 0;
}
}
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
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;
}
void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
Vector2 ofs = p_pos;
float h_offset = 0.f;
if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -800,6 +882,8 @@ void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color
}
void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
Vector2 ofs = p_pos;
float h_offset = 0.f;
if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -822,37 +906,44 @@ void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int
}
void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
+ ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
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);
}
void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
+ ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
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;
}
@@ -862,7 +953,7 @@ TextParagraph::TextParagraph() {
}
TextParagraph::~TextParagraph() {
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 8a8a53943b..0fe82b4364 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -31,6 +31,7 @@
#ifndef TEXT_PARAGRAPH_H
#define TEXT_PARAGRAPH_H
+#include "core/templates/local_vector.h"
#include "scene/resources/font.h"
#include "servers/text_server.h"
@@ -38,15 +39,7 @@
class TextParagraph : public RefCounted {
GDCLASS(TextParagraph, RefCounted);
-
-public:
- enum OverrunBehavior {
- OVERRUN_NO_TRIMMING,
- OVERRUN_TRIM_CHAR,
- OVERRUN_TRIM_WORD,
- OVERRUN_TRIM_ELLIPSIS,
- OVERRUN_TRIM_WORD_ELLIPSIS,
- };
+ _THREAD_SAFE_CLASS_
private:
RID dropcap_rid;
@@ -54,17 +47,16 @@ private:
Rect2 dropcap_margins;
RID rid;
- Vector<RID> lines_rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
+ LocalVector<RID> lines_rid;
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;
- OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
+ 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;
@@ -99,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);
@@ -111,11 +103,14 @@ 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(OverrunBehavior p_behavior);
- OverrunBehavior get_text_overrun_behavior() const;
+ void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
+ TextServer::OverrunBehavior get_text_overrun_behavior() const;
void set_width(float p_width);
float get_width() const;
@@ -156,11 +151,11 @@ public:
int hit_test(const Point2 &p_coords) const;
- 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);
+ Mutex &get_mutex() const { return _thread_safe_; };
+
+ TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextParagraph();
~TextParagraph();
};
-VARIANT_ENUM_CAST(TextParagraph::OverrunBehavior);
-
#endif // TEXT_PARAGRAPH_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 5850d253e3..d53dc1a8fc 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -35,8 +35,8 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/os/os.h"
-#include "mesh.h"
#include "scene/resources/bit_map.h"
+#include "scene/resources/mesh.h"
#include "servers/camera/camera_feed.h"
int Texture2D::get_width() const {
int ret;
@@ -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,37 +149,34 @@ 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);
- } else if (p_name == "size") {
- Size2 s = p_value;
- w = s.width;
- h = s.height;
- RenderingServer::get_singleton()->texture_set_size_override(texture, w, h);
- } else {
- return false;
+ set_image(p_value);
+ return true;
}
-
- return true;
+ return false;
}
bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "image") {
r_ret = get_image();
- } else if (p_name == "size") {
- r_ret = Size2(w, h);
- } else {
- return false;
+ return true;
}
-
- return true;
+ return false;
}
void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
+}
+
+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::create_from_image(const Ref<Image> &p_image) {
+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();
@@ -297,14 +294,14 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
x = CLAMP(x, 0, aw);
y = CLAMP(y, 0, ah);
- return alpha_cache->get_bit(Point2(x, y));
+ return alpha_cache->get_bit(x, y);
}
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;
}
@@ -323,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);
}
@@ -563,7 +561,7 @@ bool PortableCompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
x = CLAMP(x, 0, aw);
y = CLAMP(y, 0, ah);
- return alpha_cache->get_bit(Point2(x, y));
+ return alpha_cache->get_bit(x, y);
}
return true;
@@ -625,7 +623,7 @@ void PortableCompressedTexture2D::_bind_methods() {
ClassDB::bind_static_method("PortableCompressedTexture2D", D_METHOD("is_keeping_all_compressed_buffers"), &PortableCompressedTexture2D::is_keeping_all_compressed_buffers);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_override"), "set_size_override", "get_size_override");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_override", PROPERTY_HINT_NONE, "suffix:px"), "set_size_override", "get_size_override");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_compressed_buffer"), "set_keep_compressed_buffer", "is_keeping_compressed_buffer");
BIND_ENUM_CONSTANT(COMPRESSION_MODE_LOSSLESS);
@@ -1019,7 +1017,7 @@ bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
x = CLAMP(x, 0, aw);
y = CLAMP(y, 0, ah);
- return alpha_cache->get_bit(Point2(x, y));
+ return alpha_cache->get_bit(x, y);
}
return true;
@@ -1040,7 +1038,7 @@ void CompressedTexture2D::reload_from_file() {
load(path);
}
-void CompressedTexture2D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture2D::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTexture2D::_bind_methods() {
@@ -1396,7 +1394,7 @@ void CompressedTexture3D::reload_from_file() {
load(path);
}
-void CompressedTexture3D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture3D::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTexture3D::_bind_methods() {
@@ -1545,8 +1543,8 @@ void AtlasTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_filter_clip"), &AtlasTexture::has_filter_clip);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_atlas", "get_atlas");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region"), "set_region", "get_region");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region", PROPERTY_HINT_NONE, "suffix:px"), "set_region", "get_region");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin", PROPERTY_HINT_NONE, "suffix:px"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
}
@@ -1787,7 +1785,7 @@ void MeshTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base_texture", "get_base_texture");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1"), "set_image_size", "get_image_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1,suffix:px"), "set_image_size", "get_image_size");
}
MeshTexture::MeshTexture() {
@@ -1806,7 +1804,7 @@ void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
@@ -1868,11 +1866,11 @@ void CurveTexture::_update() {
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
if (texture_mode == TEXTURE_MODE_RGB) {
- wd[i * 3 + 0] = curve.interpolate_baked(t);
+ wd[i * 3 + 0] = curve.sample_baked(t);
wd[i * 3 + 1] = wd[i * 3 + 0];
wd[i * 3 + 2] = wd[i * 3 + 0];
} else {
- wd[i] = curve.interpolate_baked(t);
+ wd[i] = curve.sample_baked(t);
}
}
@@ -1954,7 +1952,7 @@ void CurveXYZTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z");
@@ -2011,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();
}
@@ -2024,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();
}
@@ -2037,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();
}
@@ -2056,7 +2054,7 @@ void CurveXYZTexture::_update() {
Curve &curve_x = **_curve_x;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i * 3 + 0] = curve_x.interpolate_baked(t);
+ wd[i * 3 + 0] = curve_x.sample_baked(t);
}
} else {
@@ -2069,7 +2067,7 @@ void CurveXYZTexture::_update() {
Curve &curve_y = **_curve_y;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i * 3 + 1] = curve_y.interpolate_baked(t);
+ wd[i * 3 + 1] = curve_y.sample_baked(t);
}
} else {
@@ -2082,7 +2080,7 @@ void CurveXYZTexture::_update() {
Curve &curve_z = **_curve_z;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i * 3 + 2] = curve_z.interpolate_baked(t);
+ wd[i * 3 + 2] = curve_z.sample_baked(t);
}
} else {
@@ -2160,8 +2158,8 @@ 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::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ 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");
}
@@ -2249,7 +2247,7 @@ void GradientTexture1D::_update() {
}
void GradientTexture1D::set_width(int p_width) {
- ERR_FAIL_COND(p_width <= 0);
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2413,6 +2411,7 @@ float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
}
void GradientTexture2D::set_width(int p_width) {
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2422,6 +2421,7 @@ int GradientTexture2D::get_width() const {
}
void GradientTexture2D::set_height(int p_height) {
+ ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range.");
height = p_height;
_queue_update();
}
@@ -2515,8 +2515,8 @@ void GradientTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update);
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,2048"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
ADD_GROUP("Fill", "fill_");
@@ -2537,13 +2537,6 @@ void GradientTexture2D::_bind_methods() {
//////////////////////////////////////
-void ProxyTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base", "base"), &ProxyTexture::set_base);
- ClassDB::bind_method(D_METHOD("get_base"), &ProxyTexture::get_base);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base", "get_base");
-}
-
void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) {
ERR_FAIL_COND(p_texture == this);
@@ -2624,26 +2617,30 @@ void AnimatedTexture::_update_proxy() {
time += delta;
- float limit;
-
- if (fps == 0) {
- limit = 0;
- } else {
- limit = 1.0 / fps;
- }
+ float speed = speed_scale == 0 ? 0 : abs(1.0 / speed_scale);
int iter_max = frame_count;
while (iter_max && !pause) {
- float frame_limit = limit + frames[current_frame].delay_sec;
+ float frame_limit = frames[current_frame].duration * speed;
if (time > frame_limit) {
- current_frame++;
+ if (speed_scale > 0.0) {
+ current_frame++;
+ } else {
+ current_frame--;
+ }
if (current_frame >= frame_count) {
- if (oneshot) {
+ if (one_shot) {
current_frame = frame_count - 1;
} else {
current_frame = 0;
}
+ } else if (current_frame < 0) {
+ if (one_shot) {
+ current_frame = 0;
+ } else {
+ current_frame = frame_count - 1;
+ }
}
time -= frame_limit;
@@ -2691,13 +2688,13 @@ bool AnimatedTexture::get_pause() const {
return pause;
}
-void AnimatedTexture::set_oneshot(bool p_oneshot) {
+void AnimatedTexture::set_one_shot(bool p_one_shot) {
RWLockWrite r(rw_lock);
- oneshot = p_oneshot;
+ one_shot = p_one_shot;
}
-bool AnimatedTexture::get_oneshot() const {
- return oneshot;
+bool AnimatedTexture::get_one_shot() const {
+ return one_shot;
}
void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture) {
@@ -2717,30 +2714,30 @@ Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const {
return frames[p_frame].texture;
}
-void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) {
+void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) {
ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
RWLockRead r(rw_lock);
- frames[p_frame].delay_sec = p_delay_sec;
+ frames[p_frame].duration = p_duration;
}
-float AnimatedTexture::get_frame_delay(int p_frame) const {
+float AnimatedTexture::get_frame_duration(int p_frame) const {
ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
RWLockRead r(rw_lock);
- return frames[p_frame].delay_sec;
+ return frames[p_frame].duration;
}
-void AnimatedTexture::set_fps(float p_fps) {
- ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000);
+void AnimatedTexture::set_speed_scale(float p_scale) {
+ ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000);
- fps = p_fps;
+ speed_scale = p_scale;
}
-float AnimatedTexture::get_fps() const {
- return fps;
+float AnimatedTexture::get_speed_scale() const {
+ return speed_scale;
}
int AnimatedTexture::get_width() const {
@@ -2796,12 +2793,12 @@ bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void AnimatedTexture::_validate_property(PropertyInfo &property) const {
- String prop = property.name;
+void AnimatedTexture::_validate_property(PropertyInfo &p_property) const {
+ String prop = p_property.name;
if (prop.begins_with("frame_")) {
int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
if (frame >= frame_count) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -2816,27 +2813,27 @@ void AnimatedTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause);
ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause);
- ClassDB::bind_method(D_METHOD("set_oneshot", "oneshot"), &AnimatedTexture::set_oneshot);
- ClassDB::bind_method(D_METHOD("get_oneshot"), &AnimatedTexture::get_oneshot);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot);
- ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps);
- ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &AnimatedTexture::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedTexture::get_speed_scale);
ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
- ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay);
- ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay);
+ ClassDB::bind_method(D_METHOD("set_frame_duration", "frame", "duration"), &AnimatedTexture::set_frame_duration);
+ ClassDB::bind_method(D_METHOD("get_frame_duration", "frame"), &AnimatedTexture::get_frame_duration);
ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "oneshot"), "set_oneshot", "get_oneshot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_greater,or_lesser"), "set_speed_scale", "get_speed_scale");
for (int i = 0; i < MAX_FRAMES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/duration", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_duration", "get_frame_duration", i);
}
BIND_CONSTANT(MAX_FRAMES);
@@ -2962,7 +2959,7 @@ ImageTextureLayered::LayeredType ImageTextureLayered::get_layered_type() const {
return layered_type;
}
-Error ImageTextureLayered::_create_from_images(const Array &p_images) {
+Error ImageTextureLayered::_create_from_images(const TypedArray<Image> &p_images) {
Vector<Ref<Image>> images;
for (int i = 0; i < p_images.size(); i++) {
Ref<Image> img = p_images[i];
@@ -2973,8 +2970,8 @@ Error ImageTextureLayered::_create_from_images(const Array &p_images) {
return create_from_images(images);
}
-Array ImageTextureLayered::_get_images() const {
- Array images;
+TypedArray<Image> ImageTextureLayered::_get_images() const {
+ TypedArray<Image> images;
for (int i = 0; i < layers; i++) {
images.push_back(get_layer_data(i));
}
@@ -3026,12 +3023,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);
}
@@ -3061,7 +3058,7 @@ void ImageTextureLayered::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_images"), &ImageTextureLayered::_get_images);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_ARRAY_TYPE, "Image", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images");
}
ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) {
@@ -3221,7 +3218,7 @@ void CompressedTextureLayered::reload_from_file() {
load(path);
}
-void CompressedTextureLayered::_validate_property(PropertyInfo &property) const {
+void CompressedTextureLayered::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTextureLayered::_bind_methods() {
@@ -3425,7 +3422,7 @@ RID PlaceholderTexture2D::get_rid() const {
void PlaceholderTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
}
PlaceholderTexture2D::PlaceholderTexture2D() {
@@ -3473,7 +3470,7 @@ Vector<Ref<Image>> PlaceholderTexture3D::get_data() const {
void PlaceholderTexture3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture3D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTexture3D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
}
PlaceholderTexture3D::PlaceholderTexture3D() {
@@ -3529,7 +3526,7 @@ void PlaceholderTextureLayered::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTextureLayered::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTextureLayered::get_size);
ClassDB::bind_method(D_METHOD("set_layers", "layers"), &PlaceholderTextureLayered::set_layers);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_RANGE, "1,4096"), "set_layers", "get_layers");
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 317756e313..4e529de8ee 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;
@@ -250,7 +251,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit);
@@ -421,9 +422,9 @@ class ImageTextureLayered : public TextureLayered {
int layers = 0;
bool mipmaps = false;
- Error _create_from_images(const Array &p_images);
+ Error _create_from_images(const TypedArray<Image> &p_images);
- Array _get_images() const;
+ TypedArray<Image> _get_images() const;
protected:
static void _bind_methods();
@@ -505,7 +506,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Image::Format get_format() const override;
@@ -650,7 +651,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Image::Format get_format() const override;
@@ -768,15 +769,6 @@ public:
class GradientTexture1D : public Texture2D {
GDCLASS(GradientTexture1D, Texture2D);
-public:
- struct Point {
- float offset = 0.0;
- Color color;
- bool operator<(const Point &p_ponit) const {
- return offset < p_ponit.offset;
- }
- };
-
private:
Ref<Gradient> gradient;
bool update_pending = false;
@@ -882,8 +874,6 @@ VARIANT_ENUM_CAST(GradientTexture2D::Fill);
VARIANT_ENUM_CAST(GradientTexture2D::Repeat);
class ProxyTexture : public Texture2D {
- GDCLASS(ProxyTexture, Texture2D);
-
private:
mutable RID proxy_ph;
mutable RID proxy;
@@ -923,15 +913,15 @@ private:
struct Frame {
Ref<Texture2D> texture;
- float delay_sec = 0.0;
+ float duration = 1.0;
};
Frame frames[MAX_FRAMES];
int frame_count = 1.0;
int current_frame = 0;
bool pause = false;
- bool oneshot = false;
- float fps = 4.0;
+ bool one_shot = false;
+ float speed_scale = 1.0;
float time = 0.0;
@@ -941,7 +931,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_frames(int p_frames);
@@ -953,17 +943,17 @@ public:
void set_pause(bool p_pause);
bool get_pause() const;
- void set_oneshot(bool p_oneshot);
- bool get_oneshot() const;
+ void set_one_shot(bool p_one_shot);
+ bool get_one_shot() const;
void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_frame_texture(int p_frame) const;
- void set_frame_delay(int p_frame, float p_delay_sec);
- float get_frame_delay(int p_frame) const;
+ void set_frame_duration(int p_frame, float p_duration);
+ float get_frame_duration(int p_frame) const;
- void set_fps(float p_fps);
- float get_fps() const;
+ void set_speed_scale(float p_scale);
+ float get_speed_scale() const;
virtual int get_width() const override;
virtual int get_height() const override;
@@ -1105,4 +1095,4 @@ public:
PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
};
-#endif
+#endif // TEXTURE_H
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 1e57933000..3321392821 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -31,17 +31,7 @@
#include "theme.h"
#include "core/string/print_string.h"
-
-// Universal Theme resources used when no other theme has the item.
-Ref<Theme> Theme::default_theme;
-Ref<Theme> Theme::project_default_theme;
-
-// Universal default values, final fallback for every theme.
-float Theme::fallback_base_scale = 1.0;
-Ref<Texture2D> Theme::fallback_icon;
-Ref<StyleBox> Theme::fallback_style;
-Ref<Font> Theme::fallback_font;
-int Theme::fallback_font_size = 16;
+#include "scene/theme/theme_db.h"
// Dynamic properties.
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
@@ -129,42 +119,42 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
// Icons.
- for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : icon_map) {
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/icons/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
}
}
// Styles.
- for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : style_map) {
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/styles/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
}
}
// Fonts.
- for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : font_map) {
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/fonts/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
}
}
// Font sizes.
- for (const KeyValue<StringName, HashMap<StringName, int>> &E : font_size_map) {
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : font_size_map) {
for (const KeyValue<StringName, int> &F : E.value) {
- list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/font_sizes/" + F.key, PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
+ list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/font_sizes/" + F.key, PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"));
}
}
// Colors.
- for (const KeyValue<StringName, HashMap<StringName, Color>> &E : color_map) {
+ for (const KeyValue<StringName, ThemeColorMap> &E : color_map) {
for (const KeyValue<StringName, Color> &F : E.value) {
- list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/colors/" + F.key));
+ list.push_back(PropertyInfo(Variant::COLOR, String() + E.key + "/colors/" + F.key));
}
}
// Constants.
- for (const KeyValue<StringName, HashMap<StringName, int>> &E : constant_map) {
+ for (const KeyValue<StringName, ThemeConstantMap> &E : constant_map) {
for (const KeyValue<StringName, int> &F : E.value) {
list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/constants/" + F.key));
}
@@ -185,64 +175,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-// Universal fallback Theme resources.
-Ref<Theme> Theme::get_default() {
- return default_theme;
-}
-
-void Theme::set_default(const Ref<Theme> &p_default) {
- default_theme = p_default;
-}
-
-Ref<Theme> Theme::get_project_default() {
- return project_default_theme;
-}
-
-void Theme::set_project_default(const Ref<Theme> &p_project_default) {
- project_default_theme = p_project_default;
-}
-
-// Universal fallback values for theme item types.
-void Theme::set_fallback_base_scale(float p_base_scale) {
- fallback_base_scale = p_base_scale;
-}
-
-void Theme::set_fallback_icon(const Ref<Texture2D> &p_icon) {
- fallback_icon = p_icon;
-}
-
-void Theme::set_fallback_style(const Ref<StyleBox> &p_style) {
- fallback_style = p_style;
-}
-
-void Theme::set_fallback_font(const Ref<Font> &p_font) {
- fallback_font = p_font;
-}
-
-void Theme::set_fallback_font_size(int p_font_size) {
- fallback_font_size = p_font_size;
-}
-
-float Theme::get_fallback_base_scale() {
- return fallback_base_scale;
-}
-
-Ref<Texture2D> Theme::get_fallback_icon() {
- return fallback_icon;
-}
-
-Ref<StyleBox> Theme::get_fallback_style() {
- return fallback_style;
-}
-
-Ref<Font> Theme::get_fallback_font() {
- return fallback_font;
-}
-
-int Theme::get_fallback_font_size() {
- return fallback_font_size;
-}
-
+// Static helpers.
bool Theme::is_valid_type_name(const String &p_name) {
for (int i = 0; i < p_name.length(); i++) {
if (!is_ascii_identifier_char(p_name[i])) {
@@ -295,7 +228,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 +274,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);
@@ -351,7 +284,7 @@ Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_the
if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
return icon_map[p_theme_type][p_name];
} else {
- return fallback_icon;
+ return ThemeDB::get_singleton()->get_fallback_icon();
}
}
@@ -407,7 +340,7 @@ void Theme::add_icon_type(const StringName &p_theme_type) {
if (icon_map.has(p_theme_type)) {
return;
}
- icon_map[p_theme_type] = HashMap<StringName, Ref<Texture2D>>();
+ icon_map[p_theme_type] = ThemeIconMap();
}
void Theme::remove_icon_type(const StringName &p_theme_type) {
@@ -432,7 +365,7 @@ void Theme::remove_icon_type(const StringName &p_theme_type) {
void Theme::get_icon_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : icon_map) {
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
p_list->push_back(E.key);
}
}
@@ -451,7 +384,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);
@@ -461,7 +394,7 @@ Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_
if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
return style_map[p_theme_type][p_name];
} else {
- return fallback_style;
+ return ThemeDB::get_singleton()->get_fallback_stylebox();
}
}
@@ -517,7 +450,7 @@ void Theme::add_stylebox_type(const StringName &p_theme_type) {
if (style_map.has(p_theme_type)) {
return;
}
- style_map[p_theme_type] = HashMap<StringName, Ref<StyleBox>>();
+ style_map[p_theme_type] = ThemeStyleMap();
}
void Theme::remove_stylebox_type(const StringName &p_theme_type) {
@@ -542,7 +475,7 @@ void Theme::remove_stylebox_type(const StringName &p_theme_type) {
void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : style_map) {
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
p_list->push_back(E.key);
}
}
@@ -561,7 +494,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);
@@ -573,7 +506,7 @@ Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_ty
} else if (has_default_font()) {
return default_font;
} else {
- return fallback_font;
+ return ThemeDB::get_singleton()->get_fallback_font();
}
}
@@ -629,7 +562,7 @@ void Theme::add_font_type(const StringName &p_theme_type) {
if (font_map.has(p_theme_type)) {
return;
}
- font_map[p_theme_type] = HashMap<StringName, Ref<Font>>();
+ font_map[p_theme_type] = ThemeFontMap();
}
void Theme::remove_font_type(const StringName &p_theme_type) {
@@ -654,7 +587,7 @@ void Theme::remove_font_type(const StringName &p_theme_type) {
void Theme::get_font_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : font_map) {
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
p_list->push_back(E.key);
}
}
@@ -676,7 +609,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ
} else if (has_default_font_size()) {
return default_font_size;
} else {
- return fallback_font_size;
+ return ThemeDB::get_singleton()->get_fallback_font_size();
}
}
@@ -728,7 +661,7 @@ void Theme::add_font_size_type(const StringName &p_theme_type) {
if (font_size_map.has(p_theme_type)) {
return;
}
- font_size_map[p_theme_type] = HashMap<StringName, int>();
+ font_size_map[p_theme_type] = ThemeFontSizeMap();
}
void Theme::remove_font_size_type(const StringName &p_theme_type) {
@@ -742,7 +675,7 @@ void Theme::remove_font_size_type(const StringName &p_theme_type) {
void Theme::get_font_size_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- for (const KeyValue<StringName, HashMap<StringName, int>> &E : font_size_map) {
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : font_size_map) {
p_list->push_back(E.key);
}
}
@@ -814,7 +747,7 @@ void Theme::add_color_type(const StringName &p_theme_type) {
if (color_map.has(p_theme_type)) {
return;
}
- color_map[p_theme_type] = HashMap<StringName, Color>();
+ color_map[p_theme_type] = ThemeColorMap();
}
void Theme::remove_color_type(const StringName &p_theme_type) {
@@ -828,7 +761,7 @@ void Theme::remove_color_type(const StringName &p_theme_type) {
void Theme::get_color_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- for (const KeyValue<StringName, HashMap<StringName, Color>> &E : color_map) {
+ for (const KeyValue<StringName, ThemeColorMap> &E : color_map) {
p_list->push_back(E.key);
}
}
@@ -900,7 +833,7 @@ void Theme::add_constant_type(const StringName &p_theme_type) {
if (constant_map.has(p_theme_type)) {
return;
}
- constant_map[p_theme_type] = HashMap<StringName, int>();
+ constant_map[p_theme_type] = ThemeConstantMap();
}
void Theme::remove_constant_type(const StringName &p_theme_type) {
@@ -914,7 +847,7 @@ void Theme::remove_constant_type(const StringName &p_theme_type) {
void Theme::get_constant_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- for (const KeyValue<StringName, HashMap<StringName, int>> &E : constant_map) {
+ for (const KeyValue<StringName, ThemeConstantMap> &E : constant_map) {
p_list->push_back(E.key);
}
}
@@ -1272,12 +1205,44 @@ void Theme::remove_type(const StringName &p_theme_type) {
void Theme::get_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- get_icon_type_list(p_list);
- get_stylebox_type_list(p_list);
- get_font_type_list(p_list);
- get_font_size_type_list(p_list);
- get_color_type_list(p_list);
- get_constant_type_list(p_list);
+ // This Set guarantees uniqueness.
+ // Because each map can have the same type defined, but for this method
+ // we only want one occurrence of each type.
+ HashSet<StringName> types;
+
+ // Icons.
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
+ types.insert(E.key);
+ }
+
+ // Styles.
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
+ types.insert(E.key);
+ }
+
+ // Fonts.
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
+ types.insert(E.key);
+ }
+
+ // Font sizes.
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : font_size_map) {
+ types.insert(E.key);
+ }
+
+ // Colors.
+ for (const KeyValue<StringName, ThemeColorMap> &E : color_map) {
+ types.insert(E.key);
+ }
+
+ // Constants.
+ for (const KeyValue<StringName, ThemeConstantMap> &E : constant_map) {
+ types.insert(E.key);
+ }
+
+ for (const StringName &E : types) {
+ p_list->push_back(E);
+ }
}
void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) {
@@ -1588,7 +1553,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Colors.
{
- for (const KeyValue<StringName, HashMap<StringName, Color>> &E : p_other->color_map) {
+ for (const KeyValue<StringName, ThemeColorMap> &E : p_other->color_map) {
for (const KeyValue<StringName, Color> &F : E.value) {
set_color(F.key, E.key, F.value);
}
@@ -1597,7 +1562,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Constants.
{
- for (const KeyValue<StringName, HashMap<StringName, int>> &E : p_other->constant_map) {
+ for (const KeyValue<StringName, ThemeConstantMap> &E : p_other->constant_map) {
for (const KeyValue<StringName, int> &F : E.value) {
set_constant(F.key, E.key, F.value);
}
@@ -1606,7 +1571,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Fonts.
{
- for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : p_other->font_map) {
+ for (const KeyValue<StringName, ThemeFontMap> &E : p_other->font_map) {
for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
set_font(F.key, E.key, F.value);
}
@@ -1615,7 +1580,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Font sizes.
{
- for (const KeyValue<StringName, HashMap<StringName, int>> &E : p_other->font_size_map) {
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : p_other->font_size_map) {
for (const KeyValue<StringName, int> &F : E.value) {
set_font_size(F.key, E.key, F.value);
}
@@ -1624,7 +1589,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Icons.
{
- for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : p_other->icon_map) {
+ for (const KeyValue<StringName, ThemeIconMap> &E : p_other->icon_map) {
for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
set_icon(F.key, E.key, F.value);
}
@@ -1633,7 +1598,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Styleboxes.
{
- for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : p_other->style_map) {
+ for (const KeyValue<StringName, ThemeStyleMap> &E : p_other->style_map) {
for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
set_stylebox(F.key, E.key, F.value);
}
@@ -1653,7 +1618,7 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
void Theme::clear() {
// These items need disconnecting.
{
- for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : icon_map) {
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
if (F.value.is_valid()) {
Ref<Texture2D> icon = F.value;
@@ -1664,7 +1629,7 @@ void Theme::clear() {
}
{
- for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : style_map) {
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
if (F.value.is_valid()) {
Ref<StyleBox> style = F.value;
@@ -1675,7 +1640,7 @@ void Theme::clear() {
}
{
- for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : font_map) {
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
if (F.value.is_valid()) {
Ref<Font> font = F.value;
@@ -1786,7 +1751,7 @@ void Theme::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_default_base_scale", "get_default_base_scale");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater"), "set_default_font_size", "get_default_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"), "set_default_font_size", "get_default_font_size");
BIND_ENUM_CONSTANT(DATA_TYPE_COLOR);
BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index f8f1e95634..ed1dc7c938 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -47,6 +47,13 @@ class Theme : public Resource {
#endif
public:
+ using ThemeIconMap = HashMap<StringName, Ref<Texture2D>>;
+ using ThemeStyleMap = HashMap<StringName, Ref<StyleBox>>;
+ using ThemeFontMap = HashMap<StringName, Ref<Font>>;
+ using ThemeFontSizeMap = HashMap<StringName, int>;
+ using ThemeColorMap = HashMap<StringName, Color>;
+ using ThemeConstantMap = HashMap<StringName, int>;
+
enum DataType {
DATA_TYPE_COLOR,
DATA_TYPE_CONSTANT,
@@ -62,12 +69,12 @@ private:
void _emit_theme_changed(bool p_notify_list_changed = false);
- HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
- HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map;
- HashMap<StringName, HashMap<StringName, Ref<Font>>> font_map;
- HashMap<StringName, HashMap<StringName, int>> font_size_map;
- HashMap<StringName, HashMap<StringName, Color>> color_map;
- HashMap<StringName, HashMap<StringName, int>> constant_map;
+ HashMap<StringName, ThemeIconMap> icon_map;
+ HashMap<StringName, ThemeStyleMap> style_map;
+ HashMap<StringName, ThemeFontMap> font_map;
+ HashMap<StringName, ThemeFontSizeMap> font_size_map;
+ HashMap<StringName, ThemeColorMap> color_map;
+ HashMap<StringName, ThemeConstantMap> constant_map;
HashMap<StringName, StringName> variation_map;
HashMap<StringName, List<StringName>> variation_base_map;
@@ -95,17 +102,6 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- // Universal Theme resources used when no other theme has the item.
- static Ref<Theme> default_theme;
- static Ref<Theme> project_default_theme;
-
- // Universal default values, final fallback for every theme.
- static float fallback_base_scale;
- static Ref<Texture2D> fallback_icon;
- static Ref<StyleBox> fallback_style;
- static Ref<Font> fallback_font;
- static int fallback_font_size;
-
// Default values configurable for each individual theme.
float default_base_scale = 0.0;
Ref<Font> default_font;
@@ -119,24 +115,6 @@ protected:
virtual void reset_state() override;
public:
- static Ref<Theme> get_default();
- static void set_default(const Ref<Theme> &p_default);
-
- static Ref<Theme> get_project_default();
- static void set_project_default(const Ref<Theme> &p_project_default);
-
- static void set_fallback_base_scale(float p_base_scale);
- static void set_fallback_icon(const Ref<Texture2D> &p_icon);
- static void set_fallback_style(const Ref<StyleBox> &p_style);
- static void set_fallback_font(const Ref<Font> &p_font);
- static void set_fallback_font_size(int p_font_size);
-
- static float get_fallback_base_scale();
- static Ref<Texture2D> get_fallback_icon();
- static Ref<StyleBox> get_fallback_style();
- static Ref<Font> get_fallback_font();
- static int get_fallback_font_size();
-
static bool is_valid_type_name(const String &p_name);
static bool is_valid_item_name(const String &p_name);
@@ -249,4 +227,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 cee3f85c32..9138a82ba8 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -34,7 +34,7 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/templates/local_vector.h"
-
+#include "core/templates/rb_set.h"
#include "scene/2d/navigation_region_2d.h"
#include "scene/gui/control.h"
#include "scene/resources/convex_polygon_shape_2d.h"
@@ -118,7 +118,7 @@ void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
pattern.erase(p_coords);
if (p_update_size) {
- size = Vector2i();
+ size = Size2i();
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
size = size.max(E.key + Vector2i(1, 1));
}
@@ -157,11 +157,11 @@ TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
return a;
}
-Vector2i TileMapPattern::get_size() const {
+Size2i TileMapPattern::get_size() const {
return size;
}
-void TileMapPattern::set_size(const Vector2i &p_size) {
+void TileMapPattern::set_size(const Size2i &p_size) {
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
Vector2i coords = E.key;
if (p_size.x <= coords.x || p_size.y <= coords.y) {
@@ -178,7 +178,7 @@ bool TileMapPattern::is_empty() const {
};
void TileMapPattern::clear() {
- size = Vector2i();
+ size = Size2i();
pattern.clear();
emit_changed();
};
@@ -236,6 +236,9 @@ bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_patte
return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
}
}
+ if (terrain != p_terrains_pattern.terrain) {
+ return terrain < p_terrains_pattern.terrain;
+ }
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
return bits[i] < p_terrains_pattern.bits[i];
@@ -253,10 +256,23 @@ bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_patt
return false;
}
}
+ if (terrain != p_terrains_pattern.terrain) {
+ return false;
+ }
return true;
}
-void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
+void TileSet::TerrainsPattern::set_terrain(int p_terrain) {
+ ERR_FAIL_COND(p_terrain < -1);
+
+ terrain = p_terrain;
+}
+
+int TileSet::TerrainsPattern::get_terrain() const {
+ return terrain;
+}
+
+void TileSet::TerrainsPattern::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
ERR_FAIL_COND(p_terrain < -1);
@@ -271,25 +287,27 @@ void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit,
bits[p_peering_bit] = p_terrain;
}
-int TileSet::TerrainsPattern::get_terrain(TileSet::CellNeighbor p_peering_bit) const {
+int TileSet::TerrainsPattern::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
return bits[p_peering_bit];
}
-void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) {
- int in_array_index = 0;
+void TileSet::TerrainsPattern::from_array(Array p_terrains) {
+ set_terrain(p_terrains[0]);
+ int in_array_index = 1;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
- ERR_FAIL_COND(in_array_index >= p_terrains.size());
- set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
+ ERR_FAIL_INDEX(in_array_index, p_terrains.size());
+ set_terrain_peering_bit(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
in_array_index++;
}
}
}
-Array TileSet::TerrainsPattern::get_terrains_as_array() const {
+Array TileSet::TerrainsPattern::as_array() const {
Array output;
+ output.push_back(get_terrain());
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
output.push_back(bits[i]);
@@ -297,10 +315,11 @@ Array TileSet::TerrainsPattern::get_terrains_as_array() const {
}
return output;
}
+
TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
ERR_FAIL_COND(p_terrain_set < 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- is_valid_bit[i] = (p_tile_set->is_valid_peering_bit_terrain(p_terrain_set, TileSet::CellNeighbor(i)));
+ is_valid_bit[i] = (p_tile_set->is_valid_terrain_peering_bit(p_terrain_set, TileSet::CellNeighbor(i)));
bits[i] = -1;
}
valid = true;
@@ -410,11 +429,16 @@ void TileSet::_update_terrains_cache() {
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
+ // Main terrain.
+ if (terrains_pattern.get_terrain() >= 0) {
+ per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
+ }
+
// Terrain bits.
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_terrain(terrain_set, bit)) {
- int terrain = terrains_pattern.get_terrain(bit);
+ if (is_valid_terrain_peering_bit(terrain_set, bit)) {
+ int terrain = terrains_pattern.get_terrain_peering_bit(bit);
if (terrain >= 0) {
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
}
@@ -822,7 +846,7 @@ Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
}
-bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
+bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
@@ -905,13 +929,13 @@ bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode,
return false;
}
-bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
+bool TileSet::is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
return false;
}
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
- return is_valid_peering_bit_for_mode(terrain_mode, p_peering_bit);
+ return is_valid_terrain_peering_bit_for_mode(terrain_mode, p_peering_bit);
}
// Navigation
@@ -1024,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));
}
}
@@ -1046,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;
@@ -1062,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;
}
@@ -1369,12 +1393,12 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
// Count the sum of probabilities.
double sum = 0.0;
RBSet<TileMapCell> set = per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
- for (RBSet<TileMapCell>::Element *E = set.front(); E; E = E->next()) {
- if (E->get().source_id >= 0) {
- Ref<TileSetSource> source = sources[E->get().source_id];
+ for (const TileMapCell &E : set) {
+ if (E.source_id >= 0) {
+ Ref<TileSetSource> source = sources[E.source_id];
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- TileData *tile_data = atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile);
+ TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
sum += tile_data->get_probability();
} else {
sum += 1.0;
@@ -1389,13 +1413,13 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
double picked = Math::random(0.0, sum);
// Pick the tile.
- for (RBSet<TileMapCell>::Element *E = set.front(); E; E = E->next()) {
- if (E->get().source_id >= 0) {
- Ref<TileSetSource> source = sources[E->get().source_id];
+ for (const TileMapCell &E : set) {
+ if (E.source_id >= 0) {
+ Ref<TileSetSource> source = sources[E.source_id];
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- TileData *tile_data = atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile);
+ TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
count += tile_data->get_probability();
} else {
count += 1.0;
@@ -1405,7 +1429,7 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
}
if (count >= picked) {
- return E->get();
+ return E;
}
}
@@ -1494,26 +1518,48 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform
}
}
-Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ return _get_square_terrain_polygon(tile_size);
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ return _get_isometric_terrain_polygon(tile_size);
+ } else {
+ float overlap = 0.0;
+ switch (tile_shape) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ return _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
+ }
+ return Vector<Point2>();
+}
+
+Vector<Point2> TileSet::get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>());
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_square_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_square_corner_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_corner_terrain_peering_bit_polygon(tile_size, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_square_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_side_terrain_peering_bit_polygon(tile_size, p_bit);
}
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_isometric_corner_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_corner_terrain_peering_bit_polygon(tile_size, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_isometric_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_side_terrain_peering_bit_polygon(tile_size, p_bit);
}
} else {
float overlap = 0.0;
@@ -1528,11 +1574,11 @@ Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::Cell
break;
}
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_half_offset_corner_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_half_offset_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
}
}
}
@@ -1544,30 +1590,68 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
if (terrain_bits_meshes_dirty) {
// Recompute the meshes.
- terrain_bits_meshes.clear();
+ terrain_peering_bits_meshes.clear();
for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) {
TerrainMode terrain_mode = TerrainMode(terrain_mode_index);
+
+ // Center terrain
+ Vector<Vector2> polygon;
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ polygon = _get_square_terrain_polygon(tile_size);
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ polygon = _get_isometric_terrain_polygon(tile_size);
+ } else {
+ float overlap = 0.0;
+ switch (tile_shape) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ polygon = _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
+ }
+ {
+ Ref<ArrayMesh> mesh;
+ mesh.instantiate();
+ Vector<Vector2> uvs;
+ uvs.resize(polygon.size());
+ Vector<Color> colors;
+ colors.resize(polygon.size());
+ colors.fill(Color(1.0, 1.0, 1.0, 1.0));
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = polygon;
+ a[Mesh::ARRAY_TEX_UV] = uvs;
+ a[Mesh::ARRAY_COLOR] = colors;
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+ terrain_meshes[terrain_mode] = mesh;
+ }
+ // Peering bits
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_for_mode(terrain_mode, bit)) {
- Vector<Vector2> polygon;
+ if (is_valid_terrain_peering_bit_for_mode(terrain_mode, bit)) {
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_square_corner_or_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_square_corner_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_corner_terrain_peering_bit_polygon(tile_size, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_square_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_side_terrain_peering_bit_polygon(tile_size, bit);
}
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_isometric_corner_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_corner_terrain_peering_bit_polygon(tile_size, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_isometric_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_side_terrain_peering_bit_polygon(tile_size, bit);
}
} else {
float overlap = 0.0;
@@ -1582,29 +1666,30 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
break;
}
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_half_offset_corner_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_half_offset_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
}
}
-
- Ref<ArrayMesh> mesh;
- mesh.instantiate();
- Vector<Vector2> uvs;
- uvs.resize(polygon.size());
- Vector<Color> colors;
- colors.resize(polygon.size());
- colors.fill(Color(1.0, 1.0, 1.0, 1.0));
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = polygon;
- a[Mesh::ARRAY_TEX_UV] = uvs;
- a[Mesh::ARRAY_COLOR] = colors;
- a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
- terrain_bits_meshes[terrain_mode][bit] = mesh;
+ {
+ Ref<ArrayMesh> mesh;
+ mesh.instantiate();
+ Vector<Vector2> uvs;
+ uvs.resize(polygon.size());
+ Vector<Color> colors;
+ colors.resize(polygon.size());
+ colors.fill(Color(1.0, 1.0, 1.0, 1.0));
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = polygon;
+ a[Mesh::ARRAY_TEX_UV] = uvs;
+ a[Mesh::ARRAY_COLOR] = colors;
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+ terrain_peering_bits_meshes[terrain_mode][bit] = mesh;
+ }
}
}
}
@@ -1618,14 +1703,21 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set);
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ int terrain_id = p_tile_data->get_terrain();
+ if (terrain_id >= 0) {
+ Color color = get_terrain_color(terrain_set, terrain_id);
+ color.a = TERRAIN_ALPHA;
+ p_canvas_item->draw_mesh(terrain_meshes[terrain_mode], Ref<Texture2D>(), Transform2D(), color);
+ }
+
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_terrain(terrain_set, bit)) {
- int terrain_id = p_tile_data->get_peering_bit_terrain(bit);
+ if (is_valid_terrain_peering_bit(terrain_set, bit)) {
+ terrain_id = p_tile_data->get_terrain_peering_bit(bit);
if (terrain_id >= 0) {
Color color = get_terrain_color(terrain_set, terrain_id);
color.a = TERRAIN_ALPHA;
- p_canvas_item->draw_mesh(terrain_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
+ p_canvas_item->draw_mesh(terrain_peering_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
}
}
}
@@ -1670,13 +1762,16 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
bit_counts[terrain] = 0;
}
+ if (tile_data->get_terrain() >= 0) {
+ bit_counts[tile_data->get_terrain()] += 10;
+ }
for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) {
TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit);
- if (is_valid_peering_bit_terrain(terrain_set, cell_neighbor)) {
- int terrain = tile_data->get_peering_bit_terrain(cell_neighbor);
+ if (is_valid_terrain_peering_bit(terrain_set, cell_neighbor)) {
+ int terrain = tile_data->get_terrain_peering_bit(cell_neighbor);
if (terrain >= 0) {
if (terrain >= (int)bit_counts.size()) {
- WARN_PRINT(vformat("Invalid peering bit terrain: %d", terrain));
+ WARN_PRINT(vformat("Invalid terrain peering bit: %d", terrain));
} else {
bit_counts[terrain] += 1;
}
@@ -1706,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;
}
}
@@ -1730,7 +1822,17 @@ void TileSet::_source_changed() {
emit_changed();
}
-Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_terrain_polygon(Vector2i p_size) {
+ Rect2 rect(-Vector2(p_size) / 6.0, Vector2(p_size) / 3.0);
+ return {
+ rect.position,
+ Vector2(rect.get_end().x, rect.position.y),
+ rect.get_end(),
+ Vector2(rect.position.x, rect.get_end().y)
+ };
+}
+
+Vector<Point2> TileSet::_get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Rect2 bit_rect;
bit_rect.size = Vector2(p_size) / 3;
switch (p_bit) {
@@ -1773,7 +1875,7 @@ Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i
return polygon;
}
-Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1815,7 +1917,7 @@ Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size,
return polygon;
}
-Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1849,7 +1951,17 @@ Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, Ti
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_terrain_polygon(Vector2i p_size) {
+ Vector2 unit = Vector2(p_size) / 6.0;
+ return {
+ Vector2(1, 0) * unit,
+ Vector2(0, 1) * unit,
+ Vector2(-1, 0) * unit,
+ Vector2(0, -1) * unit,
+ };
+}
+
+Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1907,7 +2019,7 @@ Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1949,7 +2061,7 @@ Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_siz
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1983,7 +2095,30 @@ Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size,
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+ Vector2 unit = Vector2(p_size) / 6.0;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ return {
+ Vector2(1, 1.0 - p_overlap * 2.0) * unit,
+ Vector2(0, 1) * unit,
+ Vector2(-1, 1.0 - p_overlap * 2.0) * unit,
+ Vector2(-1, -1.0 + p_overlap * 2.0) * unit,
+ Vector2(0, -1) * unit,
+ Vector2(1, -1.0 + p_overlap * 2.0) * unit,
+ };
+ } else {
+ return {
+ Vector2(1, 0) * unit,
+ Vector2(1.0 - p_overlap * 2.0, -1) * unit,
+ Vector2(-1.0 + p_overlap * 2.0, -1) * unit,
+ Vector2(-1, 0) * unit,
+ Vector2(-1.0 + p_overlap * 2.0, 1) * unit,
+ Vector2(1.0 - p_overlap * 2.0, 1) * unit,
+ };
+ }
+}
+
+Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
@@ -2006,12 +2141,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
polygon.push_back(point_list[17]);
@@ -2071,10 +2205,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
@@ -2144,7 +2276,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, 0),
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
@@ -2161,12 +2293,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
polygon.push_back(point_list[0]);
@@ -2202,10 +2333,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
@@ -2251,7 +2380,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
Vector2(0, 3),
@@ -2262,12 +2391,11 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
polygon.push_back(point_list[5]);
@@ -2297,10 +2425,8 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
@@ -2341,9 +2467,42 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
}
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);
@@ -2877,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()) {
@@ -3006,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()) {
@@ -3143,11 +3302,11 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void TileSet::_validate_property(PropertyInfo &property) const {
- if (property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
- property.usage ^= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
- property.usage ^= PROPERTY_USAGE_READ_ONLY;
+void TileSet::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
+ p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
+ p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
}
}
@@ -3175,7 +3334,7 @@ void TileSet::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size"), "set_tile_size", "get_tile_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, "suffix:px"), "set_tile_size", "get_tile_size");
// Rendering.
ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
@@ -3232,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);
@@ -3331,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);
@@ -3514,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) {
@@ -3801,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;
@@ -4273,9 +4446,9 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_texture_padding"), &TileSetAtlasSource::get_use_texture_padding);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NO_EDITOR), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_margins", "get_margins");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_separation", "get_separation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_texture_region_size", "get_texture_region_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_margins", "get_margins");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_separation", "get_separation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_texture_region_size", "get_texture_region_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_texture_padding", "get_use_texture_padding");
// Base tiles
@@ -4465,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();
}
@@ -4543,14 +4716,19 @@ void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) {
void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) {
ERR_FAIL_COND(!scenes.has(p_id));
if (p_packed_scene.is_valid()) {
- // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
- ERR_FAIL_COND(!p_packed_scene->get_state().is_valid());
- ERR_FAIL_COND(p_packed_scene->get_state()->get_node_count() < 1);
-
// Check if it extends CanvasItem.
- String type = p_packed_scene->get_state()->get_node_type(0);
+ Ref<SceneState> scene_state = p_packed_scene->get_state();
+ String type;
+ while (scene_state.is_valid() && type.is_empty()) {
+ // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
+ ERR_FAIL_COND(scene_state->get_node_count() < 1);
+
+ type = scene_state->get_node_type(0);
+ scene_state = scene_state->get_base_scene_state();
+ }
+ ERR_FAIL_COND_MSG(type.is_empty(), vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Could not get the type of the root node.", p_packed_scene->get_path()));
bool extends_correct_class = ClassDB::is_parent_class(type, "Control") || ClassDB::is_parent_class(type, "Node2D");
- ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D.", p_packed_scene->get_path()));
+ ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D. Found %s instead.", p_packed_scene->get_path(), type));
scenes[p_id].scene = p_packed_scene;
} else {
@@ -4679,14 +4857,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;
}
@@ -4795,6 +4973,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;
@@ -4845,13 +5027,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;
}
@@ -4929,11 +5104,11 @@ Vector2i TileData::get_texture_offset() const {
return tex_offset;
}
-void TileData::set_material(Ref<ShaderMaterial> p_material) {
+void TileData::set_material(Ref<Material> p_material) {
material = p_material;
emit_signal(SNAME("changed"));
}
-Ref<ShaderMaterial> TileData::get_material() const {
+Ref<Material> TileData::get_material() const {
return material;
}
@@ -5114,36 +5289,51 @@ int TileData::get_terrain_set() const {
return terrain_set;
}
-void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
+void TileData::set_terrain(int p_terrain) {
+ ERR_FAIL_COND(terrain_set < 0);
+ ERR_FAIL_COND(p_terrain < -1);
+ if (tile_set) {
+ ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
+ }
+ terrain = p_terrain;
+ emit_signal(SNAME("changed"));
+}
+
+int TileData::get_terrain() const {
+ return terrain;
+}
+
+void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain_index < -1);
if (tile_set) {
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
- ERR_FAIL_COND(!is_valid_peering_bit_terrain(p_peering_bit));
+ ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
}
terrain_peering_bits[p_peering_bit] = p_terrain_index;
emit_signal(SNAME("changed"));
}
-int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
- ERR_FAIL_COND_V(!is_valid_peering_bit_terrain(p_peering_bit), -1);
+int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
+ ERR_FAIL_COND_V(!is_valid_terrain_peering_bit(p_peering_bit), -1);
return terrain_peering_bits[p_peering_bit];
}
-bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
+bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(!tile_set, false);
- return tile_set->is_valid_peering_bit_terrain(terrain_set, p_peering_bit);
+ return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
}
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
ERR_FAIL_COND_V(!tile_set, TileSet::TerrainsPattern());
TileSet::TerrainsPattern output(tile_set, terrain_set);
+ output.set_terrain(terrain);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- if (tile_set->is_valid_peering_bit_terrain(terrain_set, TileSet::CellNeighbor(i))) {
- output.set_terrain(TileSet::CellNeighbor(i), get_peering_bit_terrain(TileSet::CellNeighbor(i)));
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, TileSet::CellNeighbor(i))) {
+ output.set_terrain_peering_bit(TileSet::CellNeighbor(i), get_terrain_peering_bit(TileSet::CellNeighbor(i)));
}
}
return output;
@@ -5293,7 +5483,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
- set_peering_bit_terrain(bit, p_value);
+ set_terrain_peering_bit(bit, p_value);
return true;
}
}
@@ -5455,9 +5645,9 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (is_valid_peering_bit_terrain(bit)) {
+ if (is_valid_terrain_peering_bit(bit)) {
property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
- if (get_peering_bit_terrain(bit) == -1) {
+ if (get_terrain_peering_bit(bit) == -1) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
p_list->push_back(property_info);
@@ -5481,7 +5671,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;
}
@@ -5531,8 +5721,10 @@ void TileData::_bind_methods() {
// Terrain
ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
- ClassDB::bind_method(D_METHOD("set_peering_bit_terrain", "peering_bit", "terrain"), &TileData::set_peering_bit_terrain);
- ClassDB::bind_method(D_METHOD("get_peering_bit_terrain", "peering_bit"), &TileData::get_peering_bit_terrain);
+ ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &TileData::set_terrain);
+ ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
+ ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
+ ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
// Navigation
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
@@ -5552,14 +5744,15 @@ void TileData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "get_flip_h");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "get_flip_v");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset"), "set_texture_offset", "get_texture_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material");
ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index");
ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin");
ADD_GROUP("Terrains", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain"), "set_terrain", "get_terrain");
ADD_GROUP("Miscellaneous", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 633e1f4bed..e156679711 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -34,6 +34,7 @@
#include "core/io/resource.h"
#include "core/object/object.h"
#include "core/templates/local_vector.h"
+#include "core/templates/rb_set.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/navigation_region_2d.h"
#include "scene/main/canvas_item.h"
@@ -116,7 +117,7 @@ union TileMapCell {
class TileMapPattern : public Resource {
GDCLASS(TileMapPattern, Resource);
- Vector2i size;
+ Size2i size;
HashMap<Vector2i, TileMapCell> pattern;
void _set_tile_data(const Vector<int> &p_data);
@@ -139,8 +140,8 @@ public:
TypedArray<Vector2i> get_used_cells() const;
- Vector2i get_size() const;
- void set_size(const Vector2i &p_size);
+ Size2i get_size() const;
+ void set_size(const Size2i &p_size);
bool is_empty() const;
void clear();
@@ -163,7 +164,7 @@ private:
String name;
Ref<Texture2D> texture;
Vector2 tex_offset;
- Ref<ShaderMaterial> material;
+ Ref<Material> material;
Rect2 region;
int tile_mode = 0;
Color modulate = Color(1, 1, 1);
@@ -264,6 +265,7 @@ public:
class TerrainsPattern {
bool valid = false;
+ int terrain = -1;
int bits[TileSet::CELL_NEIGHBOR_MAX];
bool is_valid_bit[TileSet::CELL_NEIGHBOR_MAX];
@@ -276,11 +278,14 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
- void set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain);
- int get_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ void set_terrain(int p_terrain);
+ int get_terrain() const;
- void set_terrains_from_array(Array p_terrains);
- Array get_terrains_as_array() const;
+ void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain);
+ int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
+
+ void from_array(Array p_terrains);
+ Array as_array() const;
TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set);
TerrainsPattern() {}
@@ -290,7 +295,7 @@ protected:
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 _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
private:
// --- TileSet data ---
@@ -332,7 +337,8 @@ private:
};
Vector<TerrainSet> terrain_sets;
- HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_bits_meshes;
+ HashMap<TerrainMode, Ref<ArrayMesh>> terrain_meshes;
+ HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_peering_bits_meshes;
bool terrain_bits_meshes_dirty = true;
LocalVector<RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>>> per_terrain_pattern_tiles; // Cached data.
@@ -370,17 +376,20 @@ private:
RBMap<Array, Array> alternative_level_proxies;
// Helpers
- Vector<Point2> _get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_terrain_polygon(Vector2i p_size);
+ Vector<Point2> _get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_terrain_polygon(Vector2i p_size);
+ Vector<Point2> _get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- Vector<Point2> _get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- Vector<Point2> _get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ Vector<Point2> _get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ Vector<Point2> _get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
protected:
static void _bind_methods();
@@ -453,8 +462,8 @@ public:
String get_terrain_name(int p_terrain_set, int p_terrain_index) const;
void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color);
Color get_terrain_color(int p_terrain_set, int p_terrain_index) const;
- bool is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
- bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
// Navigation
int get_navigation_layers_count() const;
@@ -470,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);
@@ -515,7 +524,8 @@ public:
Vector<Vector2> get_tile_shape_polygon();
void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
- Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
+ Vector<Point2> get_terrain_polygon(int p_terrain_set);
+ Vector<Point2> get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data);
Vector<Vector<Ref<Texture2D>>> generate_terrains_icons(Size2i p_size);
@@ -559,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;
@@ -773,7 +783,7 @@ private:
bool flip_v = false;
bool transpose = false;
Vector2i tex_offset = Vector2i();
- Ref<ShaderMaterial> material = Ref<ShaderMaterial>();
+ Ref<Material> material = Ref<Material>();
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
int z_index = 0;
int y_sort_origin = 0;
@@ -797,6 +807,7 @@ private:
// Terrain
int terrain_set = -1;
+ int terrain = -1;
int terrain_peering_bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
// Navigation
@@ -836,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;
@@ -853,8 +863,8 @@ public:
void set_texture_offset(Vector2i p_texture_offset);
Vector2i get_texture_offset() const;
- void set_material(Ref<ShaderMaterial> p_material);
- Ref<ShaderMaterial> get_material() const;
+ void set_material(Ref<Material> p_material);
+ Ref<Material> get_material() const;
void set_modulate(Color p_modulate);
Color get_modulate() const;
void set_z_index(int p_z_index);
@@ -886,9 +896,11 @@ public:
// Terrain
void set_terrain_set(int p_terrain_id);
int get_terrain_set() const;
- void set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
- int get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
- bool is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ void set_terrain(int p_terrain_id);
+ int get_terrain() const;
+ void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
+ int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
TileSet::TerrainsPattern get_terrains_pattern() const; // Not exposed.
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 3e154d539b..e14081c681 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -50,16 +50,16 @@ public:
virtual void set_loop(bool p_enable) = 0;
virtual bool has_loop() const = 0;
- virtual float get_length() const = 0;
+ virtual double get_length() const = 0;
- virtual float get_playback_position() const = 0;
- virtual void seek(float p_time) = 0;
+ virtual double get_playback_position() const = 0;
+ virtual void seek(double p_time) = 0;
virtual void set_audio_track(int p_idx) = 0;
virtual Ref<Texture2D> get_texture() const = 0;
- virtual void update(float p_delta) = 0;
+ virtual void update(double p_delta) = 0;
virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) = 0;
virtual int get_channels() const = 0;
@@ -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 8e7824665f..262dbe28ed 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"
@@ -712,86 +713,6 @@ VisualShader::VaryingType VisualShader::get_varying_type(const String &p_name) {
return varyings[p_name].type;
}
-void VisualShader::set_engine_version(const Dictionary &p_engine_version) {
- ERR_FAIL_COND(!p_engine_version.has("major"));
- ERR_FAIL_COND(!p_engine_version.has("minor"));
- engine_version["major"] = p_engine_version["major"];
- engine_version["minor"] = p_engine_version["minor"];
-}
-
-Dictionary VisualShader::get_engine_version() const {
- return engine_version;
-}
-
-#ifndef DISABLE_DEPRECATED
-
-void VisualShader::update_engine_version(const Dictionary &p_new_version) {
- if (engine_version.is_empty()) { // before 4.0
- for (int i = 0; i < TYPE_MAX; i++) {
- for (KeyValue<int, Node> &E : graph[i].nodes) {
- Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(E.value.node.ptr());
- if (input.is_valid()) {
- if (input->get_input_name() == "side") {
- input->set_input_name("front_facing");
- }
- }
- Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(E.value.node.ptr());
- if (expression.is_valid()) {
- for (int j = 0; j < expression->get_input_port_count(); j++) {
- int type = expression->get_input_port_type(j);
- if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D
- type += 2;
- }
- expression->set_input_port_type(j, type);
- }
- for (int j = 0; j < expression->get_output_port_count(); j++) {
- int type = expression->get_output_port_type(j);
- if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D
- type += 2;
- }
- expression->set_output_port_type(j, type);
- }
- }
- Ref<VisualShaderNodeStep> step = Object::cast_to<VisualShaderNodeStep>(E.value.node.ptr());
- if (step.is_valid()) {
- int op_type = int(step->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- step->set_op_type(VisualShaderNodeStep::OpType(op_type));
- }
- Ref<VisualShaderNodeSmoothStep> sstep = Object::cast_to<VisualShaderNodeSmoothStep>(E.value.node.ptr());
- if (sstep.is_valid()) {
- int op_type = int(sstep->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- sstep->set_op_type(VisualShaderNodeSmoothStep::OpType(op_type));
- }
- Ref<VisualShaderNodeMix> mix = Object::cast_to<VisualShaderNodeMix>(E.value.node.ptr());
- if (mix.is_valid()) {
- int op_type = int(mix->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- mix->set_op_type(VisualShaderNodeMix::OpType(op_type));
- }
- Ref<VisualShaderNodeCompare> compare = Object::cast_to<VisualShaderNodeCompare>(E.value.node.ptr());
- if (compare.is_valid()) {
- int ctype = int(compare->get_comparison_type());
- if (int(ctype) > 0) { // + CTYPE_SCALAR_INT + CTYPE_VECTOR_2D
- ctype += 2;
- }
- compare->set_comparison_type(VisualShaderNodeCompare::ComparisonType(ctype));
- }
- }
- }
- }
- set_engine_version(p_new_version);
-}
-
-#endif /* DISABLE_DEPRECATED */
-
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_id < 2);
@@ -802,10 +723,10 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co
n.node = p_node;
n.position = p_position;
- Ref<VisualShaderNodeUniform> uniform = n.node;
- if (uniform.is_valid()) {
- String valid_name = validate_uniform_name(uniform->get_uniform_name(), uniform);
- uniform->set_uniform_name(valid_name);
+ Ref<VisualShaderNodeParameter> parameter = n.node;
+ if (parameter.is_valid()) {
+ String valid_name = validate_parameter_name(parameter->get_parameter_name(), parameter);
+ parameter->set_parameter_name(valid_name);
}
Ref<VisualShaderNodeInput> input = n.node;
@@ -910,6 +831,48 @@ void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_c
return;
}
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(p_new_class));
+ VisualShaderNode *prev_vsn = g->nodes[p_id].node.ptr();
+
+ // Update connection data.
+ for (int i = 0; i < vsn->get_output_port_count(); i++) {
+ if (i < prev_vsn->get_output_port_count()) {
+ if (prev_vsn->is_output_port_connected(i)) {
+ vsn->set_output_port_connected(i, true);
+ }
+
+ if (prev_vsn->is_output_port_expandable(i) && prev_vsn->_is_output_port_expanded(i) && vsn->is_output_port_expandable(i)) {
+ vsn->_set_output_port_expanded(i, true);
+
+ int component_count = 0;
+ switch (prev_vsn->get_output_port_type(i)) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D:
+ component_count = 2;
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D:
+ component_count = 3;
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D:
+ component_count = 4;
+ break;
+ default:
+ break;
+ }
+
+ for (int j = 0; j < component_count; j++) {
+ int sub_port = i + 1 + j;
+
+ if (prev_vsn->is_output_port_connected(sub_port)) {
+ vsn->set_output_port_connected(sub_port, true);
+ }
+ }
+
+ i += component_count;
+ }
+ } else {
+ break;
+ }
+ }
+
vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update));
g->nodes[p_id].node = Ref<VisualShaderNode>(vsn);
@@ -1004,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;
@@ -1067,11 +1036,11 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
}
}
-Array VisualShader::_get_node_connections(Type p_type) const {
+TypedArray<Dictionary> VisualShader::_get_node_connections(Type p_type) const {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Array());
const Graph *g = &graph[p_type];
- Array ret;
+ TypedArray<Dictionary> ret;
for (const Connection &E : g->connections) {
Dictionary d;
d["from_node"] = E.from_node;
@@ -1180,7 +1149,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
StringBuilder global_code_per_node;
HashMap<Type, StringBuilder> global_code_per_func;
StringBuilder code;
- RBSet<StringName> classes;
+ HashSet<StringName> classes;
global_code += String() + "shader_type canvas_item;\n";
@@ -1222,7 +1191,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
code += "\nvoid fragment() {\n";
- RBSet<int> processed;
+ HashSet<int> processed;
Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
ERR_FAIL_COND_V(err != OK, String());
@@ -1310,7 +1279,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
return name;
}
-String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const {
+String VisualShader::validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const {
String name = p_name; //validate name first
while (name.length() && !is_ascii_char(name[0])) {
name = name.substr(1, name.length() - 1);
@@ -1330,7 +1299,7 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua
}
if (name.is_empty()) {
- name = p_uniform->get_caption();
+ name = p_parameter->get_caption();
}
int attempt = 1;
@@ -1339,11 +1308,11 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua
bool exists = false;
for (int i = 0; i < TYPE_MAX; i++) {
for (const KeyValue<int, Node> &E : graph[i].nodes) {
- Ref<VisualShaderNodeUniform> node = E.value.node;
- if (node == p_uniform) { //do not test on self
+ Ref<VisualShaderNodeParameter> node = E.value.node;
+ if (node == p_parameter) { //do not test on self
continue;
}
- if (node.is_valid() && node->get_uniform_name() == name) {
+ if (node.is_valid() && node->get_parameter_name() == name) {
exists = true;
break;
}
@@ -1547,11 +1516,11 @@ void VisualShader::reset_state() {
}
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
- p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
//render modes
HashMap<String, String> blend_mode_enums;
- RBSet<String> toggles;
+ HashSet<String> toggles;
const Vector<ShaderLanguage::ModeInfo> &rmodes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode));
@@ -1576,15 +1545,15 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
for (const KeyValue<String, String> &E : blend_mode_enums) {
- p_list->push_back(PropertyInfo(Variant::INT, "modes/" + E.key, PROPERTY_HINT_ENUM, E.value));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("modes"), E.key), PROPERTY_HINT_ENUM, E.value));
}
- for (RBSet<String>::Element *E = toggles.front(); E; E = E->next()) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "flags/" + E->get()));
+ for (const String &E : toggles) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("flags"), E)));
}
for (const KeyValue<String, Varying> &E : varyings) {
- p_list->push_back(PropertyInfo(Variant::STRING, "varyings/" + E.key));
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", PNAME("varyings"), E.key)));
}
for (int i = 0; i < TYPE_MAX; i++) {
@@ -1611,7 +1580,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, RBSet<int> &processed, bool for_preview, RBSet<StringName> &r_classes) const {
+Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const {
const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
if (vsnode->is_disabled()) {
@@ -1651,8 +1620,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
bool skip_global = input.is_valid() && for_preview;
if (!skip_global) {
- Ref<VisualShaderNodeUniform> uniform = vsnode;
- if (!uniform.is_valid() || !uniform->is_global_code_generated()) {
+ Ref<VisualShaderNodeParameter> parameter = vsnode;
+ if (!parameter.is_valid() || !parameter->is_global_code_generated()) {
if (global_code) {
*global_code += vsnode->generate_global(get_mode(), type, node);
}
@@ -1711,8 +1680,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
VisualShaderNode *ptr = const_cast<VisualShaderNode *>(graph[type].nodes[from_node].node.ptr());
if (ptr->has_method("get_input_real_name")) {
inputs[i] = ptr->call("get_input_real_name");
- } else if (ptr->has_method("get_uniform_name")) {
- inputs[i] = ptr->call("get_uniform_name");
+ } else if (ptr->has_method("get_parameter_name")) {
+ inputs[i] = ptr->call("get_parameter_name");
} else {
inputs[i] = "";
}
@@ -1729,13 +1698,13 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
inputs[i] = "(" + src_var + " ? 1.0 : 0.0)";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- inputs[i] = "dot(" + src_var + ", vec2(0.5, 0.5))";
+ inputs[i] = src_var + ".x";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- inputs[i] = "dot(" + src_var + ", vec3(0.333333, 0.333333, 0.333333))";
+ inputs[i] = src_var + ".x";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- inputs[i] = "dot(" + src_var + ", vec4(0.25, 0.25, 0.25, 0.25))";
+ inputs[i] = src_var + ".x";
} break;
default:
break;
@@ -2136,7 +2105,7 @@ void VisualShader::_update_shader() const {
HashMap<Type, StringBuilder> global_code_per_func;
StringBuilder code;
Vector<VisualShader::DefaultTextureParam> default_tex_params;
- RBSet<StringName> classes;
+ HashSet<StringName> classes;
HashMap<int, int> insertion_pos;
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky", "fog" };
@@ -2181,8 +2150,8 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
String global_expressions;
- RBSet<String> used_uniform_names;
- List<VisualShaderNodeUniform *> uniforms;
+ HashSet<String> used_parameter_names;
+ List<VisualShaderNodeParameter *> parameters;
HashMap<int, List<int>> emitters;
HashMap<int, List<int>> varying_setters;
@@ -2201,13 +2170,13 @@ void VisualShader::_update_shader() const {
expr += "\n";
global_expressions += expr;
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = E.value.node;
- if (uniform_ref.is_valid()) {
- used_uniform_names.insert(uniform_ref->get_uniform_name());
+ Ref<VisualShaderNodeParameterRef> parameter_ref = E.value.node;
+ if (parameter_ref.is_valid()) {
+ used_parameter_names.insert(parameter_ref->get_parameter_name());
}
- Ref<VisualShaderNodeUniform> uniform = E.value.node;
- if (uniform.is_valid()) {
- uniforms.push_back(uniform.ptr());
+ Ref<VisualShaderNodeParameter> parameter = E.value.node;
+ if (parameter.is_valid()) {
+ parameters.push_back(parameter.ptr());
}
Ref<VisualShaderNodeVaryingSetter> varying_setter = E.value.node;
if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) {
@@ -2226,13 +2195,13 @@ void VisualShader::_update_shader() const {
}
}
- for (int i = 0; i < uniforms.size(); i++) {
- VisualShaderNodeUniform *uniform = uniforms[i];
- if (used_uniform_names.has(uniform->get_uniform_name())) {
- global_code += uniform->generate_global(get_mode(), Type(i), -1);
- const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true);
+ for (int i = 0; i < parameters.size(); i++) {
+ VisualShaderNodeParameter *parameter = parameters[i];
+ if (used_parameter_names.has(parameter->get_parameter_name())) {
+ global_code += parameter->generate_global(get_mode(), Type(i), -1);
+ const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(true);
} else {
- const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false);
+ const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(false);
}
}
@@ -2245,6 +2214,12 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_FLOAT:
global_code += "float ";
break;
+ case VaryingType::VARYING_TYPE_INT:
+ if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {
+ global_code += "flat ";
+ }
+ global_code += "int ";
+ break;
case VaryingType::VARYING_TYPE_VECTOR_2D:
global_code += "vec2 ";
break;
@@ -2254,8 +2229,11 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_VECTOR_4D:
global_code += "vec4 ";
break;
- case VaryingType::VARYING_TYPE_COLOR:
- global_code += "vec4 ";
+ case VaryingType::VARYING_TYPE_BOOLEAN:
+ if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {
+ global_code += "flat ";
+ }
+ global_code += "bool ";
break;
case VaryingType::VARYING_TYPE_TRANSFORM:
global_code += "mat4 ";
@@ -2270,7 +2248,7 @@ void VisualShader::_update_shader() const {
}
HashMap<int, String> code_map;
- RBSet<int> empty_funcs;
+ HashSet<int> empty_funcs;
for (int i = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
@@ -2282,7 +2260,7 @@ void VisualShader::_update_shader() const {
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
StringBuilder func_code;
- RBSet<int> processed;
+ HashSet<int> processed;
bool is_empty_func = false;
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) {
@@ -2308,6 +2286,9 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_FLOAT:
code2 += "0.0";
break;
+ case VaryingType::VARYING_TYPE_INT:
+ code2 += "0";
+ break;
case VaryingType::VARYING_TYPE_VECTOR_2D:
code2 += "vec2(0.0)";
break;
@@ -2317,8 +2298,8 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_VECTOR_4D:
code2 += "vec4(0.0)";
break;
- case VaryingType::VARYING_TYPE_COLOR:
- code2 += "vec4(0.0)";
+ case VaryingType::VARYING_TYPE_BOOLEAN:
+ code2 += "false";
break;
case VaryingType::VARYING_TYPE_TRANSFORM:
code2 += "mat4(1.0)";
@@ -2539,7 +2520,7 @@ void VisualShader::_update_shader() const {
const_cast<VisualShader *>(this)->set_code(final_code);
for (int i = 0; i < default_tex_params.size(); i++) {
for (int j = 0; j < default_tex_params[i].params.size(); j++) {
- const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].params[j], j);
+ const_cast<VisualShader *>(this)->set_default_texture_parameter(default_tex_params[i].name, default_tex_params[i].params[j], j);
}
}
if (previous_code != final_code) {
@@ -2586,9 +2567,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
- ClassDB::bind_method(D_METHOD("set_engine_version", "version"), &VisualShader::set_engine_version);
- ClassDB::bind_method(D_METHOD("get_engine_version"), &VisualShader::get_engine_version);
-
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
@@ -2599,7 +2577,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "engine_version", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_engine_version", "get_engine_version");
ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs.
@@ -2620,10 +2597,11 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(VARYING_MODE_MAX);
BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_INT);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_4D);
- BIND_ENUM_CONSTANT(VARYING_TYPE_COLOR);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_BOOLEAN);
BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM);
BIND_ENUM_CONSTANT(VARYING_TYPE_MAX);
@@ -2682,6 +2660,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
// Node3D, Fragment
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
@@ -2710,6 +2692,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
// Node3D, Light
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
@@ -2884,6 +2870,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "quarter_res_color", "QUARTER_RES_COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "sky_coords", "SKY_COORDS" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
@@ -3179,8 +3166,8 @@ String VisualShaderNodeInput::get_input_index_name(int p_index) const {
return "";
}
-void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
- if (property.name == "input_name") {
+void VisualShaderNodeInput::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "input_name") {
String port_list;
int idx = 0;
@@ -3198,7 +3185,7 @@ void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
if (port_list.is_empty()) {
port_list = RTR("None");
}
- property.hint_string = port_list;
+ p_property.hint_string = port_list;
}
}
@@ -3228,20 +3215,20 @@ void VisualShaderNodeInput::_bind_methods() {
VisualShaderNodeInput::VisualShaderNodeInput() {
}
-////////////// UniformRef
+////////////// ParameterRef
-List<VisualShaderNodeUniformRef::Uniform> uniforms;
+RBMap<RID, List<VisualShaderNodeParameterRef::Parameter>> parameters;
-void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
- uniforms.push_back({ p_name, p_type });
+void VisualShaderNodeParameterRef::add_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type) {
+ parameters[p_shader_rid].push_back({ p_name, p_type });
}
-void VisualShaderNodeUniformRef::clear_uniforms() {
- uniforms.clear();
+void VisualShaderNodeParameterRef::clear_parameters(RID p_shader_rid) {
+ parameters[p_shader_rid].clear();
}
-bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
- for (const VisualShaderNodeUniformRef::Uniform &E : uniforms) {
+bool VisualShaderNodeParameterRef::has_parameter(RID p_shader_rid, const String &p_name) {
+ for (const VisualShaderNodeParameterRef::Parameter &E : parameters[p_shader_rid]) {
if (E.name == p_name) {
return true;
}
@@ -3249,41 +3236,41 @@ bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
return false;
}
-String VisualShaderNodeUniformRef::get_caption() const {
- return "UniformRef";
+String VisualShaderNodeParameterRef::get_caption() const {
+ return "ParameterRef";
}
-int VisualShaderNodeUniformRef::get_input_port_count() const {
+int VisualShaderNodeParameterRef::get_input_port_count() const {
return 0;
}
-VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const {
+VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_input_port_type(int p_port) const {
return PortType::PORT_TYPE_SCALAR;
}
-String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
+String VisualShaderNodeParameterRef::get_input_port_name(int p_port) const {
return "";
}
-int VisualShaderNodeUniformRef::get_output_port_count() const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+int VisualShaderNodeParameterRef::get_output_port_count() const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
return 1;
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return 1;
- case UniformType::UNIFORM_TYPE_BOOLEAN:
+ case PARAMETER_TYPE_BOOLEAN:
return 1;
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return 1;
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return 1;
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return 1;
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return 1;
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
return 2;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return 1;
default:
break;
@@ -3291,30 +3278,30 @@ int VisualShaderNodeUniformRef::get_output_port_count() const {
return 1;
}
-VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_output_port_type(int p_port) const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
return PortType::PORT_TYPE_SCALAR;
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return PortType::PORT_TYPE_SCALAR_INT;
- case UniformType::UNIFORM_TYPE_BOOLEAN:
+ case PARAMETER_TYPE_BOOLEAN:
return PortType::PORT_TYPE_BOOLEAN;
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return PortType::PORT_TYPE_VECTOR_2D;
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return PortType::PORT_TYPE_VECTOR_3D;
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return PortType::PORT_TYPE_VECTOR_4D;
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return PortType::PORT_TYPE_TRANSFORM;
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
if (p_port == 0) {
return PortType::PORT_TYPE_VECTOR_3D;
} else if (p_port == 1) {
return PORT_TYPE_SCALAR;
}
break;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return PortType::PORT_TYPE_SAMPLER;
default:
break;
@@ -3322,30 +3309,30 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+String VisualShaderNodeParameterRef::get_output_port_name(int p_port) const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
return "";
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return "";
- case UniformType::UNIFORM_TYPE_BOOLEAN:
+ case PARAMETER_TYPE_BOOLEAN:
return "";
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return "";
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return "";
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return "";
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return "";
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
if (p_port == 0) {
return "rgb";
} else if (p_port == 1) {
return "alpha";
}
break;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return "";
break;
default:
@@ -3354,65 +3341,85 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
return "";
}
-void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
- uniform_name = p_name;
- if (uniform_name != "[None]") {
- uniform_type = get_uniform_type_by_name(uniform_name);
- } else {
- uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+void VisualShaderNodeParameterRef::set_shader_rid(const RID &p_shader_rid) {
+ shader_rid = p_shader_rid;
+}
+
+void VisualShaderNodeParameterRef::set_parameter_name(const String &p_name) {
+ parameter_name = p_name;
+ if (shader_rid.is_valid()) {
+ update_parameter_type();
}
emit_changed();
}
-String VisualShaderNodeUniformRef::get_uniform_name() const {
- return uniform_name;
+void VisualShaderNodeParameterRef::update_parameter_type() {
+ if (parameter_name != "[None]") {
+ param_type = get_parameter_type_by_name(parameter_name);
+ } else {
+ param_type = PARAMETER_TYPE_FLOAT;
+ }
}
-int VisualShaderNodeUniformRef::get_uniforms_count() const {
- return uniforms.size();
+String VisualShaderNodeParameterRef::get_parameter_name() const {
+ return parameter_name;
}
-String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].name;
+int VisualShaderNodeParameterRef::get_parameters_count() const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), 0);
+
+ return parameters[shader_rid].size();
+}
+
+String VisualShaderNodeParameterRef::get_parameter_name_by_index(int p_idx) const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
+
+ if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
+ return parameters[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;
+VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_name(const String &p_name) const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
+
+ for (int i = 0; i < parameters[shader_rid].size(); i++) {
+ if (parameters[shader_rid][i].name == p_name) {
+ return parameters[shader_rid][i].type;
}
}
- return UniformType::UNIFORM_TYPE_FLOAT;
+ return PARAMETER_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;
+VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_index(int p_idx) const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
+
+ if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
+ return parameters[shader_rid][p_idx].type;
}
- return UniformType::UNIFORM_TYPE_FLOAT;
+ return PARAMETER_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) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_port_type_by_index(int p_idx) const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
+
+ if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
+ switch (parameters[shader_rid][p_idx].type) {
+ case PARAMETER_TYPE_FLOAT:
return PORT_TYPE_SCALAR;
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return PORT_TYPE_SCALAR_INT;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return PORT_TYPE_SAMPLER;
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return PORT_TYPE_VECTOR_2D;
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return PORT_TYPE_VECTOR_3D;
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return PORT_TYPE_VECTOR_4D;
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return PORT_TYPE_TRANSFORM;
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
return PORT_TYPE_VECTOR_3D;
default:
break;
@@ -3421,54 +3428,54 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_b
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
- if (uniform_name == "[None]") {
+String VisualShaderNodeParameterRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
+ if (parameter_name == "[None]") {
return " " + p_output_vars[0] + " = 0.0;\n";
}
break;
- case UniformType::UNIFORM_TYPE_COLOR: {
- String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
- code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
+ case PARAMETER_TYPE_COLOR: {
+ String code = " " + p_output_vars[0] + " = " + get_parameter_name() + ".rgb;\n";
+ code += " " + p_output_vars[1] + " = " + get_parameter_name() + ".a;\n";
return code;
} break;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return String();
default:
break;
}
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) {
- uniform_type = (UniformType)p_uniform_type;
+void VisualShaderNodeParameterRef::_set_parameter_type(int p_type) {
+ param_type = (ParameterType)p_type;
}
-int VisualShaderNodeUniformRef::_get_uniform_type() const {
- return (int)uniform_type;
+int VisualShaderNodeParameterRef::_get_parameter_type() const {
+ return (int)param_type;
}
-void VisualShaderNodeUniformRef::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name);
- ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name);
+void VisualShaderNodeParameterRef::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameterRef::set_parameter_name);
+ ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameterRef::get_parameter_name);
- ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type);
- ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type);
+ ClassDB::bind_method(D_METHOD("_set_parameter_type", "type"), &VisualShaderNodeParameterRef::_set_parameter_type);
+ ClassDB::bind_method(D_METHOD("_get_parameter_type"), &VisualShaderNodeParameterRef::_get_parameter_type);
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name", PROPERTY_HINT_ENUM, ""), "set_parameter_name", "get_parameter_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "param_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_parameter_type", "_get_parameter_type");
}
-Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
+Vector<StringName> VisualShaderNodeParameterRef::get_editable_properties() const {
Vector<StringName> props;
- props.push_back("uniform_name");
- props.push_back("uniform_type");
+ props.push_back("parameter_name");
+ props.push_back("param_type");
return props;
}
-VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() {
+VisualShaderNodeParameterRef::VisualShaderNodeParameterRef() {
}
////////////////////////////////////////////
@@ -3485,7 +3492,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Binormal", "BINORMAL" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV2", "UV2" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color", "COLOR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Model View Matrix", "MODELVIEW_MATRIX" },
@@ -3533,12 +3541,14 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Vertex", "VERTEX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color", "COLOR" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
////////////////////////////////////////////////////////////////////////
// Canvas Item, Fragment.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color", "COLOR" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
@@ -3547,14 +3557,16 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
////////////////////////////////////////////////////////////////////////
// Canvas Item, Light.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Light", "LIGHT" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light", "LIGHT.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Light Alpha", "LIGHT.a" },
////////////////////////////////////////////////////////////////////////
// Sky, Sky.
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Fog", "FOG" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Fog", "FOG.rgb" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Fog Alpha", "FOG.a" },
////////////////////////////////////////////////////////////////////////
// Fog, Fog.
@@ -3675,17 +3687,17 @@ VisualShaderNodeOutput::VisualShaderNodeOutput() {
///////////////////////////
-void VisualShaderNodeUniform::set_uniform_name(const String &p_name) {
- uniform_name = p_name;
+void VisualShaderNodeParameter::set_parameter_name(const String &p_name) {
+ parameter_name = p_name;
emit_signal(SNAME("name_changed"));
emit_changed();
}
-String VisualShaderNodeUniform::get_uniform_name() const {
- return uniform_name;
+String VisualShaderNodeParameter::get_parameter_name() const {
+ return parameter_name;
}
-void VisualShaderNodeUniform::set_qualifier(VisualShaderNodeUniform::Qualifier p_qual) {
+void VisualShaderNodeParameter::set_qualifier(VisualShaderNodeParameter::Qualifier p_qual) {
ERR_FAIL_INDEX(int(p_qual), int(QUAL_MAX));
if (qualifier == p_qual) {
return;
@@ -3694,26 +3706,37 @@ void VisualShaderNodeUniform::set_qualifier(VisualShaderNodeUniform::Qualifier p
emit_changed();
}
-VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() const {
+VisualShaderNodeParameter::Qualifier VisualShaderNodeParameter::get_qualifier() const {
return qualifier;
}
-void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) {
+void VisualShaderNodeParameter::set_global_code_generated(bool p_enabled) {
global_code_generated = p_enabled;
}
-bool VisualShaderNodeUniform::is_global_code_generated() const {
+bool VisualShaderNodeParameter::is_global_code_generated() const {
return global_code_generated;
}
-void VisualShaderNodeUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name);
- ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name);
+#ifndef DISABLE_DEPRECATED
+// Kept for compatibility from 3.x to 4.0.
+bool VisualShaderNodeParameter::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "uniform_name") {
+ set_parameter_name(p_value);
+ return true;
+ }
+ return false;
+}
+#endif
+
+void VisualShaderNodeParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameter::set_parameter_name);
+ ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameter::get_parameter_name);
- ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeUniform::set_qualifier);
- ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeUniform::get_qualifier);
+ ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeParameter::set_qualifier);
+ ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeParameter::get_qualifier);
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name"), "set_uniform_name", "get_uniform_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name"), "set_parameter_name", "get_parameter_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "qualifier", PROPERTY_HINT_ENUM, "None,Global,Instance"), "set_qualifier", "get_qualifier");
BIND_ENUM_CONSTANT(QUAL_NONE);
@@ -3722,7 +3745,7 @@ void VisualShaderNodeUniform::_bind_methods() {
BIND_ENUM_CONSTANT(QUAL_MAX);
}
-String VisualShaderNodeUniform::_get_qual_str() const {
+String VisualShaderNodeParameter::_get_qual_str() const {
if (is_qualifier_supported(qualifier)) {
switch (qualifier) {
case QUAL_NONE:
@@ -3738,11 +3761,11 @@ String VisualShaderNodeUniform::_get_qual_str() const {
return String();
}
-String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+String VisualShaderNodeParameter::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
List<String> keyword_list;
ShaderLanguage::get_keyword_list(&keyword_list);
- if (keyword_list.find(uniform_name)) {
- return RTR("Shader keywords cannot be used as uniform names.\nChoose another name.");
+ if (keyword_list.find(parameter_name)) {
+ return RTR("Shader keywords cannot be used as parameter names.\nChoose another name.");
}
if (!is_qualifier_supported(qualifier)) {
String qualifier_str;
@@ -3758,66 +3781,66 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
default:
break;
}
- return vformat(RTR("This uniform type does not support the '%s' qualifier."), qualifier_str);
+ return vformat(RTR("This parameter 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::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(parameter_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);
+ return vformat(RTR("Global parameter '%s' does not exist.\nCreate it in the Project Settings."), parameter_name);
}
bool incompatible_type = false;
switch (gvt) {
case RS::GLOBAL_VAR_TYPE_FLOAT: {
- if (!Object::cast_to<VisualShaderNodeFloatUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeFloatParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_INT: {
- if (!Object::cast_to<VisualShaderNodeIntUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeIntParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_BOOL: {
- if (!Object::cast_to<VisualShaderNodeBooleanUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeBooleanParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_COLOR: {
- if (!Object::cast_to<VisualShaderNodeColorUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeColorParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_VEC3: {
- if (!Object::cast_to<VisualShaderNodeVec3Uniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeVec3Parameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_VEC4: {
- if (!Object::cast_to<VisualShaderNodeVec4Uniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeVec4Parameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
- if (!Object::cast_to<VisualShaderNodeTransformUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTransformParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
- if (!Object::cast_to<VisualShaderNodeTextureUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTextureParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
- if (!Object::cast_to<VisualShaderNodeTexture3DUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTexture3DParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
- if (!Object::cast_to<VisualShaderNodeTexture2DArrayUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTexture2DArrayParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
- if (!Object::cast_to<VisualShaderNodeCubemapUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeCubemapParameter>(this)) {
incompatible_type = true;
}
} break;
@@ -3825,29 +3848,29 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
break;
}
if (incompatible_type) {
- return vformat(RTR("Global uniform '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), uniform_name);
+ return vformat(RTR("Global parameter '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), parameter_name);
}
}
return String();
}
-Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const {
+Vector<StringName> VisualShaderNodeParameter::get_editable_properties() const {
Vector<StringName> props;
props.push_back("qualifier");
return props;
}
-VisualShaderNodeUniform::VisualShaderNodeUniform() {
+VisualShaderNodeParameter::VisualShaderNodeParameter() {
}
////////////// ResizeableBase
-void VisualShaderNodeResizableBase::set_size(const Vector2 &p_size) {
+void VisualShaderNodeResizableBase::set_size(const Size2 &p_size) {
size = p_size;
}
-Vector2 VisualShaderNodeResizableBase::get_size() const {
+Size2 VisualShaderNodeResizableBase::get_size() const {
return size;
}
@@ -4633,21 +4656,23 @@ void VisualShaderNodeVarying::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_varying_type"), &VisualShaderNodeVarying::get_varying_type);
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "varying_name"), "set_varying_name", "get_varying_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Vector,Transform"), "set_varying_type", "get_varying_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4,Boolean,Transform"), "set_varying_type", "get_varying_type");
}
String VisualShaderNodeVarying::get_type_str() const {
switch (varying_type) {
case VisualShader::VARYING_TYPE_FLOAT:
return "float";
+ case VisualShader::VARYING_TYPE_INT:
+ return "int";
case VisualShader::VARYING_TYPE_VECTOR_2D:
return "vec2";
case VisualShader::VARYING_TYPE_VECTOR_3D:
return "vec3";
case VisualShader::VARYING_TYPE_VECTOR_4D:
return "vec4";
- case VisualShader::VARYING_TYPE_COLOR:
- return "vec4";
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ return "bool";
case VisualShader::VARYING_TYPE_TRANSFORM:
return "mat4";
default:
@@ -4658,17 +4683,16 @@ String VisualShaderNodeVarying::get_type_str() const {
VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualShader::VaryingType p_type, int p_port) const {
switch (p_type) {
+ case VisualShader::VARYING_TYPE_INT:
+ return PORT_TYPE_SCALAR_INT;
case VisualShader::VARYING_TYPE_VECTOR_2D:
return PORT_TYPE_VECTOR_2D;
case VisualShader::VARYING_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
case VisualShader::VARYING_TYPE_VECTOR_4D:
return PORT_TYPE_VECTOR_4D;
- case VisualShader::VARYING_TYPE_COLOR:
- if (p_port == 1) {
- break; // scalar
- }
- return PORT_TYPE_VECTOR_3D;
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ return PORT_TYPE_BOOLEAN;
case VisualShader::VARYING_TYPE_TRANSFORM:
return PORT_TYPE_TRANSFORM;
default:
@@ -4712,9 +4736,6 @@ String VisualShaderNodeVaryingSetter::get_caption() const {
}
int VisualShaderNodeVaryingSetter::get_input_port_count() const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- return 2;
- }
return 1;
}
@@ -4723,13 +4744,6 @@ VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_input
}
String VisualShaderNodeVaryingSetter::get_input_port_name(int p_port) const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- if (p_port == 0) {
- return "color";
- } else {
- return "alpha";
- }
- }
return "";
}
@@ -4745,20 +4759,12 @@ String VisualShaderNodeVaryingSetter::get_output_port_name(int p_port) const {
return "";
}
-String VisualShaderNodeVaryingSetter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return vformat("varying %s %s;\n", get_type_str(), varying_name);
-}
-
String VisualShaderNodeVaryingSetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
if (varying_name == "[None]") {
return code;
}
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- code += vformat(" %s = vec4(%s, %s);\n", varying_name, p_input_vars[0], p_input_vars[1]);
- } else {
- code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]);
- }
+ code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]);
return code;
}
@@ -4784,9 +4790,6 @@ String VisualShaderNodeVaryingGetter::get_input_port_name(int p_port) const {
}
int VisualShaderNodeVaryingGetter::get_output_port_count() const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- return 2;
- }
return 1;
}
@@ -4795,13 +4798,6 @@ VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_outpu
}
String VisualShaderNodeVaryingGetter::get_output_port_name(int p_port) const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- if (p_port == 0) {
- return "color";
- } else {
- return "alpha";
- }
- }
return "";
}
@@ -4818,6 +4814,9 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
case VisualShader::VARYING_TYPE_FLOAT:
from = "0.0";
break;
+ case VisualShader::VARYING_TYPE_INT:
+ from = "0";
+ break;
case VisualShader::VARYING_TYPE_VECTOR_2D:
from = "vec2(0.0)";
break;
@@ -4827,9 +4826,8 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
case VisualShader::VARYING_TYPE_VECTOR_4D:
from = "vec4(0.0)";
break;
- case VisualShader::VARYING_TYPE_COLOR:
- from = "vec3(0.0)";
- from2 = "0.0";
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ from = "false";
break;
case VisualShader::VARYING_TYPE_TRANSFORM:
from = "mat4(1.0)";
@@ -4837,16 +4835,6 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
default:
break;
}
- } else if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- from = varying_name + ".rgb";
- from2 = varying_name + ".a";
- }
-
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- String code;
- code += vformat(" %s = %s;\n", p_output_vars[0], from);
- code += vformat(" %s = %s;\n", p_output_vars[1], from2);
- return code;
}
return vformat(" %s = %s;\n", p_output_vars[0], from);
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index aa5263943b..3aba550f03 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -36,7 +36,7 @@
#include "scene/gui/control.h"
#include "scene/resources/shader.h"
-class VisualShaderNodeUniform;
+class VisualShaderNodeParameter;
class VisualShaderNode;
class VisualShader : public Shader {
@@ -44,8 +44,6 @@ class VisualShader : public Shader {
friend class VisualShaderNodeVersionChecker;
- Dictionary engine_version;
-
public:
enum Type {
TYPE_VERTEX,
@@ -81,21 +79,21 @@ public:
enum VaryingType {
VARYING_TYPE_FLOAT,
+ VARYING_TYPE_INT,
VARYING_TYPE_VECTOR_2D,
VARYING_TYPE_VECTOR_3D,
VARYING_TYPE_VECTOR_4D,
- VARYING_TYPE_COLOR,
+ VARYING_TYPE_BOOLEAN,
VARYING_TYPE_TRANSFORM,
VARYING_TYPE_MAX,
};
struct Varying {
String name;
- VaryingMode mode;
- VaryingType type;
+ VaryingMode mode = VARYING_MODE_MAX;
+ VaryingType type = VARYING_TYPE_MAX;
- Varying() {
- }
+ Varying() {}
Varying(String p_name, VaryingMode p_mode, VaryingType p_type) :
name(p_name), mode(p_mode), type(p_type) {}
@@ -134,12 +132,12 @@ private:
Shader::Mode shader_mode = Shader::MODE_SPATIAL;
mutable String previous_code;
- Array _get_node_connections(Type p_type) const;
+ TypedArray<Dictionary> _get_node_connections(Type p_type) const;
Vector2 graph_offset;
HashMap<String, int> modes;
- RBSet<StringName> flags;
+ HashSet<StringName> flags;
HashMap<String, Varying> varyings;
List<Varying> varyings_list;
@@ -158,7 +156,7 @@ private:
}
};
- Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, RBSet<int> &processed, bool for_preview, RBSet<StringName> &r_classes) const;
+ Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const;
void _input_type_changed(Type p_type, int p_id);
bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const;
@@ -177,14 +175,6 @@ public: // internal methods
void set_shader_type(Type p_type);
Type get_shader_type() const;
-public:
- void set_engine_version(const Dictionary &p_version);
- Dictionary get_engine_version() const;
-
-#ifndef DISABLE_DEPRECATED
- void update_engine_version(const Dictionary &p_new_version);
-#endif /* DISABLE_DEPRECATED */
-
enum {
NODE_ID_INVALID = -1,
NODE_ID_OUTPUT = 0,
@@ -238,7 +228,7 @@ public:
String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const;
String validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const;
- String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const;
+ String validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const;
VisualShader();
};
@@ -438,7 +428,7 @@ public:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual int get_input_port_count() const override;
@@ -508,8 +498,8 @@ public:
VisualShaderNodeOutput();
};
-class VisualShaderNodeUniform : public VisualShaderNode {
- GDCLASS(VisualShaderNodeUniform, VisualShaderNode);
+class VisualShaderNodeParameter : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParameter, VisualShaderNode);
public:
enum Qualifier {
@@ -520,7 +510,7 @@ public:
};
private:
- String uniform_name = "";
+ String parameter_name = "";
Qualifier qualifier = QUAL_NONE;
bool global_code_generated = false;
@@ -528,9 +518,13 @@ protected:
static void _bind_methods();
String _get_qual_str() const;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif
+
public:
- void set_uniform_name(const String &p_name);
- String get_uniform_name() const;
+ void set_parameter_name(const String &p_name);
+ String get_parameter_name() const;
void set_qualifier(Qualifier p_qual);
Qualifier get_qualifier() const;
@@ -544,43 +538,44 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
- VisualShaderNodeUniform();
+ VisualShaderNodeParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier)
+VARIANT_ENUM_CAST(VisualShaderNodeParameter::Qualifier)
-class VisualShaderNodeUniformRef : public VisualShaderNode {
- GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode);
+class VisualShaderNodeParameterRef : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParameterRef, VisualShaderNode);
public:
- enum UniformType {
- UNIFORM_TYPE_FLOAT,
- UNIFORM_TYPE_INT,
- UNIFORM_TYPE_BOOLEAN,
- UNIFORM_TYPE_VECTOR2,
- UNIFORM_TYPE_VECTOR3,
- UNIFORM_TYPE_VECTOR4,
- UNIFORM_TYPE_TRANSFORM,
- UNIFORM_TYPE_COLOR,
+ enum ParameterType {
+ PARAMETER_TYPE_FLOAT,
+ PARAMETER_TYPE_INT,
+ PARAMETER_TYPE_BOOLEAN,
+ PARAMETER_TYPE_VECTOR2,
+ PARAMETER_TYPE_VECTOR3,
+ PARAMETER_TYPE_VECTOR4,
+ PARAMETER_TYPE_TRANSFORM,
+ PARAMETER_TYPE_COLOR,
UNIFORM_TYPE_SAMPLER,
};
- struct Uniform {
+ struct Parameter {
String name;
- UniformType type;
+ ParameterType type;
};
private:
- String uniform_name = "[None]";
- UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+ RID shader_rid;
+ String parameter_name = "[None]";
+ ParameterType param_type = ParameterType::PARAMETER_TYPE_FLOAT;
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_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type);
+ static void clear_parameters(RID p_shader_rid);
+ static bool has_parameter(RID p_shader_rid, const String &p_name);
public:
virtual String get_caption() const override;
@@ -593,38 +588,42 @@ 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_uniform_name(const String &p_name);
- String get_uniform_name() const;
+ void set_shader_rid(const RID &p_shader);
- void _set_uniform_type(int p_uniform_type);
- int _get_uniform_type() const;
+ void set_parameter_name(const String &p_name);
+ String get_parameter_name() const;
- int get_uniforms_count() const;
- String get_uniform_name_by_index(int p_idx) const;
- UniformType get_uniform_type_by_name(const String &p_name) const;
- UniformType get_uniform_type_by_index(int p_idx) const;
+ void update_parameter_type();
+
+ void _set_parameter_type(int p_parameter_type);
+ int _get_parameter_type() const;
+
+ int get_parameters_count() const;
+ String get_parameter_name_by_index(int p_idx) const;
+ ParameterType get_parameter_type_by_name(const String &p_name) const;
+ ParameterType get_parameter_type_by_index(int p_idx) const;
PortType get_port_type_by_index(int p_idx) const;
virtual Vector<StringName> get_editable_properties() const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
- VisualShaderNodeUniformRef();
+ VisualShaderNodeParameterRef();
};
class VisualShaderNodeResizableBase : public VisualShaderNode {
GDCLASS(VisualShaderNodeResizableBase, VisualShaderNode);
protected:
- Vector2 size = Size2(0, 0);
+ Size2 size = Size2(0, 0);
bool allow_v_resize = true;
protected:
static void _bind_methods();
public:
- void set_size(const Vector2 &p_size);
- Vector2 get_size() const;
+ void set_size(const Size2 &p_size);
+ Size2 get_size() const;
bool is_allow_v_resize() const;
void set_allow_v_resize(bool p_enabled);
@@ -833,7 +832,6 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVaryingSetter();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index dbd45793f9..de13912b75 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -700,7 +700,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade
case TYPE_DATA:
break;
case TYPE_COLOR:
- u += " : hint_albedo";
+ u += " : source_color";
break;
case TYPE_NORMAL_MAP:
u += " : hint_normal";
@@ -1015,7 +1015,7 @@ Vector<StringName> VisualShaderNodeCurveTexture::get_editable_properties() const
}
String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + ";\n";
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + " : repeat_disable;\n";
}
String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -1463,7 +1463,7 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade
case TYPE_DATA:
break;
case TYPE_COLOR:
- u += " : hint_albedo";
+ u += " : source_color";
break;
case TYPE_NORMAL_MAP:
u += " : hint_normal";
@@ -1606,6 +1606,55 @@ VisualShaderNodeCubemap::VisualShaderNodeCubemap() {
simple_decl = false;
}
+////////////// Linear Depth
+
+String VisualShaderNodeLinearSceneDepth::get_caption() const {
+ return "LinearSceneDepth";
+}
+
+int VisualShaderNodeLinearSceneDepth::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeLinearSceneDepth::PortType VisualShaderNodeLinearSceneDepth::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeLinearSceneDepth::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeLinearSceneDepth::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeLinearSceneDepth::PortType VisualShaderNodeLinearSceneDepth::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeLinearSceneDepth::get_output_port_name(int p_port) const {
+ return "linear depth";
+}
+
+bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += " float _log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n";
+ code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n";
+ code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n";
+ code += " _depth_view.xyz /= _depth_view.w;";
+ code += vformat(" %s = -_depth_view.z;", p_output_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
+}
+
////////////// Float Op
String VisualShaderNodeFloatOp::get_caption() const {
@@ -1901,13 +1950,7 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader
code += "atan(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
break;
case OP_REFLECT:
- if (op_type == OP_TYPE_VECTOR_2D) { // Not supported.
- code += "vec2(0.0);\n";
- } else if (op_type == OP_TYPE_VECTOR_4D) { // Not supported.
- code += "vec4(0.0);\n";
- } else {
- code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
+ code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
break;
case OP_STEP:
code += "step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
@@ -1967,7 +2010,7 @@ String VisualShaderNodeVectorOp::get_warning(Shader::Mode p_mode, VisualShader::
bool invalid_type = false;
if (op_type == OP_TYPE_VECTOR_2D || op_type == OP_TYPE_VECTOR_4D) {
- if (op == OP_CROSS || op == OP_REFLECT) {
+ if (op == OP_CROSS) {
invalid_type = true;
}
}
@@ -2462,7 +2505,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeFloatFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeFloatFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Fract,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_SIN);
BIND_ENUM_CONSTANT(FUNC_COS);
@@ -2481,7 +2524,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_FLOOR);
BIND_ENUM_CONSTANT(FUNC_ROUND);
BIND_ENUM_CONSTANT(FUNC_CEIL);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
BIND_ENUM_CONSTANT(FUNC_NEGATE);
BIND_ENUM_CONSTANT(FUNC_ACOSH);
@@ -2713,7 +2756,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Fract,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
@@ -2733,7 +2776,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_EXP);
BIND_ENUM_CONSTANT(FUNC_EXP2);
BIND_ENUM_CONSTANT(FUNC_FLOOR);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT);
BIND_ENUM_CONSTANT(FUNC_LOG);
BIND_ENUM_CONSTANT(FUNC_LOG2);
@@ -3096,6 +3139,107 @@ VisualShaderNodeUVFunc::VisualShaderNodeUVFunc() {
set_input_port_default_value(2, Vector2()); // offset
}
+////////////// UV PolarCoord
+
+String VisualShaderNodeUVPolarCoord::get_caption() const {
+ return "UVPolarCoord";
+}
+
+int VisualShaderNodeUVPolarCoord::get_input_port_count() const {
+ return 4;
+}
+
+VisualShaderNodeUVPolarCoord::PortType VisualShaderNodeUVPolarCoord::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_2D; // uv
+ case 1:
+ return PORT_TYPE_VECTOR_2D; // center
+ case 2:
+ return PORT_TYPE_SCALAR; // zoom
+ case 3:
+ return PORT_TYPE_SCALAR; // repeat
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUVPolarCoord::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "uv";
+ case 1:
+ return "scale";
+ case 2:
+ return "zoom strength";
+ case 3:
+ return "repeat";
+ default:
+ break;
+ }
+ return "";
+}
+
+bool VisualShaderNodeUVPolarCoord::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ if (p_port == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int VisualShaderNodeUVPolarCoord::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeUVPolarCoord::PortType VisualShaderNodeUVPolarCoord::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_2D;
+}
+
+String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const {
+ return "uv";
+}
+
+String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String uv;
+ if (p_input_vars[0].is_empty()) {
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ uv = "UV";
+ } else {
+ uv = "vec2(0.0)";
+ }
+ } else {
+ uv = vformat("%s", p_input_vars[0]);
+ }
+ String center = vformat("%s", p_input_vars[1]);
+ String zoom = vformat("%s", p_input_vars[2]);
+ String repeat = vformat("%s", p_input_vars[3]);
+
+ if (p_mode == Shader::MODE_CANVAS_ITEM) {
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
+ code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
+ } else {
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
+ code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
+ }
+
+ return code;
+}
+
+VisualShaderNodeUVPolarCoord::VisualShaderNodeUVPolarCoord() {
+ set_input_port_default_value(1, Vector2(0.5, 0.5)); // center
+ set_input_port_default_value(2, 1.0); // zoom
+ set_input_port_default_value(3, 1.0); // repeat
+}
+
////////////// Dot Product
String VisualShaderNodeDotProduct::get_caption() const {
@@ -4006,14 +4150,6 @@ int VisualShaderNodeVectorRefract::get_input_port_count() const {
return 3;
}
-VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_input_port_type(int p_port) const {
- if (p_port == 2) {
- return PORT_TYPE_SCALAR;
- }
-
- return PORT_TYPE_VECTOR_3D;
-}
-
String VisualShaderNodeVectorRefract::get_input_port_name(int p_port) const {
switch (p_port) {
case 0:
@@ -4030,10 +4166,6 @@ int VisualShaderNodeVectorRefract::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_output_port_type(int p_port) const {
- return PORT_TYPE_VECTOR_3D;
-}
-
String VisualShaderNodeVectorRefract::get_output_port_name(int p_port) const {
return "";
}
@@ -4042,6 +4174,31 @@ String VisualShaderNodeVectorRefract::generate_code(Shader::Mode p_mode, VisualS
return " " + p_output_vars[0] + " = refract(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n";
}
+void VisualShaderNodeVectorRefract::set_op_type(OpType p_op_type) {
+ ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX));
+ if (op_type == p_op_type) {
+ return;
+ }
+ switch (p_op_type) {
+ case OP_TYPE_VECTOR_2D: {
+ set_input_port_default_value(0, Vector2(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector2(), get_input_port_default_value(1));
+ } break;
+ case OP_TYPE_VECTOR_3D: {
+ set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
+ } break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ } break;
+ default:
+ break;
+ }
+ op_type = p_op_type;
+ emit_changed();
+}
+
VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() {
set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
@@ -4559,44 +4716,44 @@ VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() {
set_input_port_default_value(0, Transform3D());
}
-////////////// Float Uniform
+////////////// Float Parameter
-String VisualShaderNodeFloatUniform::get_caption() const {
- return "FloatUniform";
+String VisualShaderNodeFloatParameter::get_caption() const {
+ return "FloatParameter";
}
-int VisualShaderNodeFloatUniform::get_input_port_count() const {
+int VisualShaderNodeFloatParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeFloatUniform::PortType VisualShaderNodeFloatUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeFloatParameter::PortType VisualShaderNodeFloatParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeFloatUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeFloatParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeFloatUniform::get_output_port_count() const {
+int VisualShaderNodeFloatParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeFloatUniform::PortType VisualShaderNodeFloatUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeFloatParameter::PortType VisualShaderNodeFloatParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeFloatUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeFloatParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeFloatParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = "";
if (hint == HINT_RANGE) {
- code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")";
+ code += _get_qual_str() + "uniform float " + get_parameter_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")";
} else if (hint == HINT_RANGE_STEP) {
- code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")";
+ code += _get_qual_str() + "uniform float " + get_parameter_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")";
} else {
- code += _get_qual_str() + "uniform float " + get_uniform_name();
+ code += _get_qual_str() + "uniform float " + get_parameter_name();
}
if (default_value_enabled) {
code += " = " + rtos(default_value);
@@ -4605,19 +4762,19 @@ String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, Visual
return code;
}
-String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeFloatParameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeFloatUniform::is_show_prop_names() const {
+bool VisualShaderNodeFloatParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeFloatUniform::is_use_prop_slots() const {
+bool VisualShaderNodeFloatParameter::is_use_prop_slots() const {
return true;
}
-void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) {
+void VisualShaderNodeFloatParameter::set_hint(Hint p_hint) {
ERR_FAIL_INDEX(int(p_hint), int(HINT_MAX));
if (hint == p_hint) {
return;
@@ -4626,11 +4783,11 @@ void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) {
emit_changed();
}
-VisualShaderNodeFloatUniform::Hint VisualShaderNodeFloatUniform::get_hint() const {
+VisualShaderNodeFloatParameter::Hint VisualShaderNodeFloatParameter::get_hint() const {
return hint;
}
-void VisualShaderNodeFloatUniform::set_min(float p_value) {
+void VisualShaderNodeFloatParameter::set_min(float p_value) {
if (Math::is_equal_approx(hint_range_min, p_value)) {
return;
}
@@ -4638,11 +4795,11 @@ void VisualShaderNodeFloatUniform::set_min(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_min() const {
+float VisualShaderNodeFloatParameter::get_min() const {
return hint_range_min;
}
-void VisualShaderNodeFloatUniform::set_max(float p_value) {
+void VisualShaderNodeFloatParameter::set_max(float p_value) {
if (Math::is_equal_approx(hint_range_max, p_value)) {
return;
}
@@ -4650,11 +4807,11 @@ void VisualShaderNodeFloatUniform::set_max(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_max() const {
+float VisualShaderNodeFloatParameter::get_max() const {
return hint_range_max;
}
-void VisualShaderNodeFloatUniform::set_step(float p_value) {
+void VisualShaderNodeFloatParameter::set_step(float p_value) {
if (Math::is_equal_approx(hint_range_step, p_value)) {
return;
}
@@ -4662,11 +4819,11 @@ void VisualShaderNodeFloatUniform::set_step(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_step() const {
+float VisualShaderNodeFloatParameter::get_step() const {
return hint_range_step;
}
-void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeFloatParameter::set_default_value_enabled(bool p_enabled) {
if (default_value_enabled == p_enabled) {
return;
}
@@ -4674,11 +4831,11 @@ void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) {
emit_changed();
}
-bool VisualShaderNodeFloatUniform::is_default_value_enabled() const {
+bool VisualShaderNodeFloatParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeFloatUniform::set_default_value(float p_value) {
+void VisualShaderNodeFloatParameter::set_default_value(float p_value) {
if (Math::is_equal_approx(default_value, p_value)) {
return;
}
@@ -4686,28 +4843,28 @@ void VisualShaderNodeFloatUniform::set_default_value(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_default_value() const {
+float VisualShaderNodeFloatParameter::get_default_value() const {
return default_value;
}
-void VisualShaderNodeFloatUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatUniform::set_hint);
- ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatUniform::get_hint);
+void VisualShaderNodeFloatParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatParameter::set_hint);
+ ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatParameter::get_hint);
- ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeFloatUniform::set_min);
- ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeFloatUniform::get_min);
+ ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeFloatParameter::set_min);
+ ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeFloatParameter::get_min);
- ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeFloatUniform::set_max);
- ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeFloatUniform::get_max);
+ ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeFloatParameter::set_max);
+ ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeFloatParameter::get_max);
- ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatUniform::set_step);
- ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatUniform::get_step);
+ ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatParameter::set_step);
+ ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatParameter::get_step);
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatUniform::is_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min"), "set_min", "get_min");
@@ -4722,16 +4879,16 @@ void VisualShaderNodeFloatUniform::_bind_methods() {
BIND_ENUM_CONSTANT(HINT_MAX);
}
-bool VisualShaderNodeFloatUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeFloatParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeFloatUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeFloatParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeFloatParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("hint");
if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) {
props.push_back("min");
@@ -4747,47 +4904,47 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const
return props;
}
-VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() {
+VisualShaderNodeFloatParameter::VisualShaderNodeFloatParameter() {
}
-////////////// Integer Uniform
+////////////// Integer Parametet
-String VisualShaderNodeIntUniform::get_caption() const {
- return "IntUniform";
+String VisualShaderNodeIntParameter::get_caption() const {
+ return "IntParameter";
}
-int VisualShaderNodeIntUniform::get_input_port_count() const {
+int VisualShaderNodeIntParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeIntUniform::PortType VisualShaderNodeIntUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeIntParameter::PortType VisualShaderNodeIntParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR_INT;
}
-String VisualShaderNodeIntUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeIntParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeIntUniform::get_output_port_count() const {
+int VisualShaderNodeIntParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeIntUniform::PortType VisualShaderNodeIntUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeIntParameter::PortType VisualShaderNodeIntParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR_INT;
}
-String VisualShaderNodeIntUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeIntParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeIntParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = "";
if (hint == HINT_RANGE) {
- code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")";
+ code += _get_qual_str() + "uniform int " + get_parameter_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")";
} else if (hint == HINT_RANGE_STEP) {
- code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")";
+ code += _get_qual_str() + "uniform int " + get_parameter_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")";
} else {
- code += _get_qual_str() + "uniform int " + get_uniform_name();
+ code += _get_qual_str() + "uniform int " + get_parameter_name();
}
if (default_value_enabled) {
code += " = " + itos(default_value);
@@ -4796,19 +4953,19 @@ String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualSh
return code;
}
-String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeIntParameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeIntUniform::is_show_prop_names() const {
+bool VisualShaderNodeIntParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeIntUniform::is_use_prop_slots() const {
+bool VisualShaderNodeIntParameter::is_use_prop_slots() const {
return true;
}
-void VisualShaderNodeIntUniform::set_hint(Hint p_hint) {
+void VisualShaderNodeIntParameter::set_hint(Hint p_hint) {
ERR_FAIL_INDEX(int(p_hint), int(HINT_MAX));
if (hint == p_hint) {
return;
@@ -4817,11 +4974,11 @@ void VisualShaderNodeIntUniform::set_hint(Hint p_hint) {
emit_changed();
}
-VisualShaderNodeIntUniform::Hint VisualShaderNodeIntUniform::get_hint() const {
+VisualShaderNodeIntParameter::Hint VisualShaderNodeIntParameter::get_hint() const {
return hint;
}
-void VisualShaderNodeIntUniform::set_min(int p_value) {
+void VisualShaderNodeIntParameter::set_min(int p_value) {
if (hint_range_min == p_value) {
return;
}
@@ -4829,11 +4986,11 @@ void VisualShaderNodeIntUniform::set_min(int p_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_min() const {
+int VisualShaderNodeIntParameter::get_min() const {
return hint_range_min;
}
-void VisualShaderNodeIntUniform::set_max(int p_value) {
+void VisualShaderNodeIntParameter::set_max(int p_value) {
if (hint_range_max == p_value) {
return;
}
@@ -4841,11 +4998,11 @@ void VisualShaderNodeIntUniform::set_max(int p_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_max() const {
+int VisualShaderNodeIntParameter::get_max() const {
return hint_range_max;
}
-void VisualShaderNodeIntUniform::set_step(int p_value) {
+void VisualShaderNodeIntParameter::set_step(int p_value) {
if (hint_range_step == p_value) {
return;
}
@@ -4853,11 +5010,11 @@ void VisualShaderNodeIntUniform::set_step(int p_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_step() const {
+int VisualShaderNodeIntParameter::get_step() const {
return hint_range_step;
}
-void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_default_value_enabled) {
+void VisualShaderNodeIntParameter::set_default_value_enabled(bool p_default_value_enabled) {
if (default_value_enabled == p_default_value_enabled) {
return;
}
@@ -4865,11 +5022,11 @@ void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_default_value_
emit_changed();
}
-bool VisualShaderNodeIntUniform::is_default_value_enabled() const {
+bool VisualShaderNodeIntParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeIntUniform::set_default_value(int p_default_value) {
+void VisualShaderNodeIntParameter::set_default_value(int p_default_value) {
if (default_value == p_default_value) {
return;
}
@@ -4877,28 +5034,28 @@ void VisualShaderNodeIntUniform::set_default_value(int p_default_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_default_value() const {
+int VisualShaderNodeIntParameter::get_default_value() const {
return default_value;
}
-void VisualShaderNodeIntUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntUniform::set_hint);
- ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntUniform::get_hint);
+void VisualShaderNodeIntParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntParameter::set_hint);
+ ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntParameter::get_hint);
- ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeIntUniform::set_min);
- ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeIntUniform::get_min);
+ ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeIntParameter::set_min);
+ ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeIntParameter::get_min);
- ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeIntUniform::set_max);
- ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeIntUniform::get_max);
+ ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeIntParameter::set_max);
+ ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeIntParameter::get_max);
- ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntUniform::set_step);
- ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntUniform::get_step);
+ ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntParameter::set_step);
+ ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntParameter::get_step);
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntUniform::is_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range + Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min");
@@ -4913,16 +5070,16 @@ void VisualShaderNodeIntUniform::_bind_methods() {
BIND_ENUM_CONSTANT(HINT_MAX);
}
-bool VisualShaderNodeIntUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeIntParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeIntUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeIntParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeIntParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("hint");
if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) {
props.push_back("min");
@@ -4938,40 +5095,40 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
return props;
}
-VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() {
+VisualShaderNodeIntParameter::VisualShaderNodeIntParameter() {
}
-////////////// Boolean Uniform
+////////////// Boolean Parameter
-String VisualShaderNodeBooleanUniform::get_caption() const {
- return "BooleanUniform";
+String VisualShaderNodeBooleanParameter::get_caption() const {
+ return "BooleanParameter";
}
-int VisualShaderNodeBooleanUniform::get_input_port_count() const {
+int VisualShaderNodeBooleanParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeBooleanParameter::PortType VisualShaderNodeBooleanParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_BOOLEAN;
}
-String VisualShaderNodeBooleanUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeBooleanParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeBooleanUniform::get_output_port_count() const {
+int VisualShaderNodeBooleanParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeBooleanParameter::PortType VisualShaderNodeBooleanParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_BOOLEAN;
}
-String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeBooleanParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_default_value_enabled) {
+void VisualShaderNodeBooleanParameter::set_default_value_enabled(bool p_default_value_enabled) {
if (default_value_enabled == p_default_value_enabled) {
return;
}
@@ -4979,11 +5136,11 @@ void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_default_va
emit_changed();
}
-bool VisualShaderNodeBooleanUniform::is_default_value_enabled() const {
+bool VisualShaderNodeBooleanParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeBooleanUniform::set_default_value(bool p_default_value) {
+void VisualShaderNodeBooleanParameter::set_default_value(bool p_default_value) {
if (default_value == p_default_value) {
return;
}
@@ -4991,12 +5148,12 @@ void VisualShaderNodeBooleanUniform::set_default_value(bool p_default_value) {
emit_changed();
}
-bool VisualShaderNodeBooleanUniform::get_default_value() const {
+bool VisualShaderNodeBooleanParameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform bool " + get_uniform_name();
+String VisualShaderNodeBooleanParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform bool " + get_parameter_name();
if (default_value_enabled) {
if (default_value) {
code += " = true";
@@ -5008,39 +5165,39 @@ String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, Visu
return code;
}
-String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeBooleanParameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeBooleanUniform::is_show_prop_names() const {
+bool VisualShaderNodeBooleanParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const {
+bool VisualShaderNodeBooleanParameter::is_use_prop_slots() const {
return true;
}
-void VisualShaderNodeBooleanUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled);
+void VisualShaderNodeBooleanParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeBooleanParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeBooleanUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeBooleanParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeBooleanParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5048,47 +5205,47 @@ Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() con
return props;
}
-VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() {
+VisualShaderNodeBooleanParameter::VisualShaderNodeBooleanParameter() {
}
-////////////// Color Uniform
+////////////// Color Parameter
-String VisualShaderNodeColorUniform::get_caption() const {
- return "ColorUniform";
+String VisualShaderNodeColorParameter::get_caption() const {
+ return "ColorParameter";
}
-int VisualShaderNodeColorUniform::get_input_port_count() const {
+int VisualShaderNodeColorParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeColorParameter::PortType VisualShaderNodeColorParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeColorParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeColorUniform::get_output_port_count() const {
+int VisualShaderNodeColorParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeColorParameter::PortType VisualShaderNodeColorParameter::get_output_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR;
}
-String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeColorParameter::get_output_port_name(int p_port) const {
return "color";
}
-bool VisualShaderNodeColorUniform::is_output_port_expandable(int p_port) const {
+bool VisualShaderNodeColorParameter::is_output_port_expandable(int p_port) const {
if (p_port == 0) {
return true;
}
return false;
}
-void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeColorParameter::set_default_value_enabled(bool p_enabled) {
if (default_value_enabled == p_enabled) {
return;
}
@@ -5096,11 +5253,11 @@ void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) {
emit_changed();
}
-bool VisualShaderNodeColorUniform::is_default_value_enabled() const {
+bool VisualShaderNodeColorParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) {
+void VisualShaderNodeColorParameter::set_default_value(const Color &p_value) {
if (default_value.is_equal_approx(p_value)) {
return;
}
@@ -5108,12 +5265,12 @@ void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) {
emit_changed();
}
-Color VisualShaderNodeColorUniform::get_default_value() const {
+Color VisualShaderNodeColorParameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color";
+String VisualShaderNodeColorParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec4 " + get_parameter_name() + " : source_color";
if (default_value_enabled) {
code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a);
}
@@ -5121,35 +5278,35 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual
return code;
}
-String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeColorParameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeColorUniform::is_show_prop_names() const {
+bool VisualShaderNodeColorParameter::is_show_prop_names() const {
return true;
}
-void VisualShaderNodeColorUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled);
+void VisualShaderNodeColorParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeColorParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeColorUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeColorParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeColorParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5157,59 +5314,59 @@ Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const
return props;
}
-VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() {
+VisualShaderNodeColorParameter::VisualShaderNodeColorParameter() {
}
-////////////// Vector2 Uniform
+////////////// Vector2 Parameter
-String VisualShaderNodeVec2Uniform::get_caption() const {
- return "Vector2Uniform";
+String VisualShaderNodeVec2Parameter::get_caption() const {
+ return "Vector2Parameter";
}
-int VisualShaderNodeVec2Uniform::get_input_port_count() const {
+int VisualShaderNodeVec2Parameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_input_port_type(int p_port) const {
+VisualShaderNodeVec2Parameter::PortType VisualShaderNodeVec2Parameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_2D;
}
-String VisualShaderNodeVec2Uniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeVec2Parameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeVec2Uniform::get_output_port_count() const {
+int VisualShaderNodeVec2Parameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_output_port_type(int p_port) const {
+VisualShaderNodeVec2Parameter::PortType VisualShaderNodeVec2Parameter::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR_2D;
}
-String VisualShaderNodeVec2Uniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeVec2Parameter::get_output_port_name(int p_port) const {
return String();
}
-void VisualShaderNodeVec2Uniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeVec2Parameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeVec2Uniform::is_default_value_enabled() const {
+bool VisualShaderNodeVec2Parameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeVec2Uniform::set_default_value(const Vector2 &p_value) {
+void VisualShaderNodeVec2Parameter::set_default_value(const Vector2 &p_value) {
default_value = p_value;
emit_changed();
}
-Vector2 VisualShaderNodeVec2Uniform::get_default_value() const {
+Vector2 VisualShaderNodeVec2Parameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec2 " + get_uniform_name();
+String VisualShaderNodeVec2Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec2 " + get_parameter_name();
if (default_value_enabled) {
code += vformat(" = vec2(%.6f, %.6f)", default_value.x, default_value.y);
}
@@ -5217,39 +5374,39 @@ String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualS
return code;
}
-String VisualShaderNodeVec2Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeVec2Parameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeVec2Uniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Uniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Uniform::is_default_value_enabled);
+void VisualShaderNodeVec2Parameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Parameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Parameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Uniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Uniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Parameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Parameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeVec2Uniform::is_show_prop_names() const {
+bool VisualShaderNodeVec2Parameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeVec2Uniform::is_use_prop_slots() const {
+bool VisualShaderNodeVec2Parameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeVec2Uniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeVec2Parameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeVec2Uniform::is_convertible_to_constant() const {
+bool VisualShaderNodeVec2Parameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeVec2Parameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5257,59 +5414,59 @@ Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const
return props;
}
-VisualShaderNodeVec2Uniform::VisualShaderNodeVec2Uniform() {
+VisualShaderNodeVec2Parameter::VisualShaderNodeVec2Parameter() {
}
-////////////// Vector3 Uniform
+////////////// Vector3 Parameter
-String VisualShaderNodeVec3Uniform::get_caption() const {
- return "Vector3Uniform";
+String VisualShaderNodeVec3Parameter::get_caption() const {
+ return "Vector3Parameter";
}
-int VisualShaderNodeVec3Uniform::get_input_port_count() const {
+int VisualShaderNodeVec3Parameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const {
+VisualShaderNodeVec3Parameter::PortType VisualShaderNodeVec3Parameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_3D;
}
-String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeVec3Parameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeVec3Uniform::get_output_port_count() const {
+int VisualShaderNodeVec3Parameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const {
+VisualShaderNodeVec3Parameter::PortType VisualShaderNodeVec3Parameter::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR_3D;
}
-String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeVec3Parameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-void VisualShaderNodeVec3Uniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeVec3Parameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeVec3Uniform::is_default_value_enabled() const {
+bool VisualShaderNodeVec3Parameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeVec3Uniform::set_default_value(const Vector3 &p_value) {
+void VisualShaderNodeVec3Parameter::set_default_value(const Vector3 &p_value) {
default_value = p_value;
emit_changed();
}
-Vector3 VisualShaderNodeVec3Uniform::get_default_value() const {
+Vector3 VisualShaderNodeVec3Parameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec3 " + get_uniform_name();
+String VisualShaderNodeVec3Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec3 " + get_parameter_name();
if (default_value_enabled) {
code += vformat(" = vec3(%.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z);
}
@@ -5317,39 +5474,39 @@ String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualS
return code;
}
-String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeVec3Parameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeVec3Uniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Uniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Uniform::is_default_value_enabled);
+void VisualShaderNodeVec3Parameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Parameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Parameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Uniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Uniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Parameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Parameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeVec3Uniform::is_show_prop_names() const {
+bool VisualShaderNodeVec3Parameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const {
+bool VisualShaderNodeVec3Parameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeVec3Parameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeVec3Uniform::is_convertible_to_constant() const {
+bool VisualShaderNodeVec3Parameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeVec3Parameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5357,59 +5514,59 @@ Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const
return props;
}
-VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() {
+VisualShaderNodeVec3Parameter::VisualShaderNodeVec3Parameter() {
}
-////////////// Vector4 Uniform
+////////////// Vector4 Parameter
-String VisualShaderNodeVec4Uniform::get_caption() const {
- return "Vector4Uniform";
+String VisualShaderNodeVec4Parameter::get_caption() const {
+ return "Vector4Parameter";
}
-int VisualShaderNodeVec4Uniform::get_input_port_count() const {
+int VisualShaderNodeVec4Parameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_input_port_type(int p_port) const {
+VisualShaderNodeVec4Parameter::PortType VisualShaderNodeVec4Parameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_4D;
}
-String VisualShaderNodeVec4Uniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeVec4Parameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeVec4Uniform::get_output_port_count() const {
+int VisualShaderNodeVec4Parameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_output_port_type(int p_port) const {
+VisualShaderNodeVec4Parameter::PortType VisualShaderNodeVec4Parameter::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR_4D;
}
-String VisualShaderNodeVec4Uniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeVec4Parameter::get_output_port_name(int p_port) const {
return ""; // No output port means the editor will be used as port.
}
-void VisualShaderNodeVec4Uniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeVec4Parameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeVec4Uniform::is_default_value_enabled() const {
+bool VisualShaderNodeVec4Parameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeVec4Uniform::set_default_value(const Quaternion &p_value) {
+void VisualShaderNodeVec4Parameter::set_default_value(const Vector4 &p_value) {
default_value = p_value;
emit_changed();
}
-Quaternion VisualShaderNodeVec4Uniform::get_default_value() const {
+Vector4 VisualShaderNodeVec4Parameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec4 " + get_uniform_name();
+String VisualShaderNodeVec4Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec4 " + get_parameter_name();
if (default_value_enabled) {
code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z, default_value.w);
}
@@ -5417,39 +5574,39 @@ String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualS
return code;
}
-String VisualShaderNodeVec4Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeVec4Parameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeVec4Uniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Uniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Uniform::is_default_value_enabled);
+void VisualShaderNodeVec4Parameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Parameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Parameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Uniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Uniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Parameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Parameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "default_value"), "set_default_value", "get_default_value");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR4, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeVec4Uniform::is_show_prop_names() const {
+bool VisualShaderNodeVec4Parameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeVec4Uniform::is_use_prop_slots() const {
+bool VisualShaderNodeVec4Parameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeVec4Uniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeVec4Parameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // All qualifiers are supported.
}
-bool VisualShaderNodeVec4Uniform::is_convertible_to_constant() const {
+bool VisualShaderNodeVec4Parameter::is_convertible_to_constant() const {
return true; // Conversion is allowed.
}
-Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeVec4Parameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5457,59 +5614,59 @@ Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const
return props;
}
-VisualShaderNodeVec4Uniform::VisualShaderNodeVec4Uniform() {
+VisualShaderNodeVec4Parameter::VisualShaderNodeVec4Parameter() {
}
-////////////// Transform Uniform
+////////////// Transform Parameter
-String VisualShaderNodeTransformUniform::get_caption() const {
- return "TransformUniform";
+String VisualShaderNodeTransformParameter::get_caption() const {
+ return "TransformParameter";
}
-int VisualShaderNodeTransformUniform::get_input_port_count() const {
+int VisualShaderNodeTransformParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeTransformParameter::PortType VisualShaderNodeTransformParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_3D;
}
-String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeTransformParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeTransformUniform::get_output_port_count() const {
+int VisualShaderNodeTransformParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeTransformParameter::PortType VisualShaderNodeTransformParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
-String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTransformParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-void VisualShaderNodeTransformUniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeTransformParameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeTransformUniform::is_default_value_enabled() const {
+bool VisualShaderNodeTransformParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeTransformUniform::set_default_value(const Transform3D &p_value) {
+void VisualShaderNodeTransformParameter::set_default_value(const Transform3D &p_value) {
default_value = p_value;
emit_changed();
}
-Transform3D VisualShaderNodeTransformUniform::get_default_value() const {
+Transform3D VisualShaderNodeTransformParameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform mat4 " + get_uniform_name();
+String VisualShaderNodeTransformParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform mat4 " + get_parameter_name();
if (default_value_enabled) {
Vector3 row0 = default_value.basis.rows[0];
Vector3 row1 = default_value.basis.rows[1];
@@ -5521,42 +5678,42 @@ String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, Vi
return code;
}
-String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeTransformParameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeTransformUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformUniform::is_default_value_enabled);
+void VisualShaderNodeTransformParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeTransformUniform::is_show_prop_names() const {
+bool VisualShaderNodeTransformParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeTransformUniform::is_use_prop_slots() const {
+bool VisualShaderNodeTransformParameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeTransformParameter::is_qualifier_supported(Qualifier p_qual) const {
if (p_qual == Qualifier::QUAL_INSTANCE) {
return false;
}
return true;
}
-bool VisualShaderNodeTransformUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeTransformParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeTransformParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5564,74 +5721,39 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c
return props;
}
-VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() {
-}
-
-////////////// Texture Uniform
-
-String VisualShaderNodeTextureUniform::get_caption() const {
- return "TextureUniform";
-}
-
-int VisualShaderNodeTextureUniform::get_input_port_count() const {
- return 0;
-}
-
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const {
- return PORT_TYPE_SCALAR;
-}
-
-String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const {
- return "";
+VisualShaderNodeTransformParameter::VisualShaderNodeTransformParameter() {
}
-int VisualShaderNodeTextureUniform::get_output_port_count() const {
- return 1;
-}
+//////////////
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const {
- switch (p_port) {
- case 0:
- return PORT_TYPE_SAMPLER;
- default:
- return PORT_TYPE_SCALAR;
- }
-}
-
-String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
- switch (p_port) {
- case 0:
- return "sampler2D";
- default:
- return "";
- }
-}
-
-String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat) {
+ String code;
bool has_colon = false;
- String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name();
// type
{
String type_code;
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- type_code = "hint_black";
+ switch (p_texture_type) {
+ case VisualShaderNodeTextureParameter::TYPE_DATA:
+ if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_BLACK) {
+ type_code = "hint_default_black";
+ } else if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_TRANSPARENT) {
+ type_code = "hint_default_transparent";
}
break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- type_code = "hint_black_albedo";
- } else {
- type_code = "hint_albedo";
+ case VisualShaderNodeTextureParameter::TYPE_COLOR:
+ type_code = "source_color";
+ if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_BLACK) {
+ type_code += ", hint_default_black";
+ } else if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_TRANSPARENT) {
+ type_code += ", hint_default_transparent";
}
break;
- case TYPE_NORMAL_MAP:
+ case VisualShaderNodeTextureParameter::TYPE_NORMAL_MAP:
type_code = "hint_normal";
break;
- case TYPE_ANISOTROPY:
+ case VisualShaderNodeTextureParameter::TYPE_ANISOTROPY:
type_code = "hint_anisotropy";
break;
default:
@@ -5648,23 +5770,23 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
{
String filter_code;
- switch (texture_filter) {
- case FILTER_NEAREST:
+ switch (p_texture_filter) {
+ case VisualShaderNodeTextureParameter::FILTER_NEAREST:
filter_code = "filter_nearest";
break;
- case FILTER_LINEAR:
+ case VisualShaderNodeTextureParameter::FILTER_LINEAR:
filter_code = "filter_linear";
break;
- case FILTER_NEAREST_MIPMAP:
+ case VisualShaderNodeTextureParameter::FILTER_NEAREST_MIPMAP:
filter_code = "filter_nearest_mipmap";
break;
- case FILTER_LINEAR_MIPMAP:
+ case VisualShaderNodeTextureParameter::FILTER_LINEAR_MIPMAP:
filter_code = "filter_linear_mipmap";
break;
- case FILTER_NEAREST_MIPMAP_ANISOTROPIC:
+ case VisualShaderNodeTextureParameter::FILTER_NEAREST_MIPMAP_ANISOTROPIC:
filter_code = "filter_nearest_mipmap_anisotropic";
break;
- case FILTER_LINEAR_MIPMAP_ANISOTROPIC:
+ case VisualShaderNodeTextureParameter::FILTER_LINEAR_MIPMAP_ANISOTROPIC:
filter_code = "filter_linear_mipmap_anisotropic";
break;
default:
@@ -5686,11 +5808,11 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
{
String repeat_code;
- switch (texture_repeat) {
- case REPEAT_ENABLED:
+ switch (p_texture_repeat) {
+ case VisualShaderNodeTextureParameter::REPEAT_ENABLED:
repeat_code = "repeat_enable";
break;
- case REPEAT_DISABLED:
+ case VisualShaderNodeTextureParameter::REPEAT_DISABLED:
repeat_code = "repeat_disable";
break;
default:
@@ -5707,15 +5829,41 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
}
}
- code += ";\n";
return code;
}
-String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+////////////// Texture Parameter
+
+int VisualShaderNodeTextureParameter::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeTextureParameter::PortType VisualShaderNodeTextureParameter::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeTextureParameter::get_input_port_name(int p_port) const {
return "";
}
-void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type) {
+int VisualShaderNodeTextureParameter::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeTextureParameter::PortType VisualShaderNodeTextureParameter::get_output_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SAMPLER;
+ default:
+ return PORT_TYPE_SCALAR;
+ }
+}
+
+String VisualShaderNodeTextureParameter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "";
+}
+
+void VisualShaderNodeTextureParameter::set_texture_type(TextureType p_texture_type) {
ERR_FAIL_INDEX(int(p_texture_type), int(TYPE_MAX));
if (texture_type == p_texture_type) {
return;
@@ -5724,11 +5872,11 @@ void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type
emit_changed();
}
-VisualShaderNodeTextureUniform::TextureType VisualShaderNodeTextureUniform::get_texture_type() const {
+VisualShaderNodeTextureParameter::TextureType VisualShaderNodeTextureParameter::get_texture_type() const {
return texture_type;
}
-void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_color_default) {
+void VisualShaderNodeTextureParameter::set_color_default(ColorDefault p_color_default) {
ERR_FAIL_INDEX(int(p_color_default), int(COLOR_DEFAULT_MAX));
if (color_default == p_color_default) {
return;
@@ -5737,11 +5885,11 @@ void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_color_defa
emit_changed();
}
-VisualShaderNodeTextureUniform::ColorDefault VisualShaderNodeTextureUniform::get_color_default() const {
+VisualShaderNodeTextureParameter::ColorDefault VisualShaderNodeTextureParameter::get_color_default() const {
return color_default;
}
-void VisualShaderNodeTextureUniform::set_texture_filter(TextureFilter p_filter) {
+void VisualShaderNodeTextureParameter::set_texture_filter(TextureFilter p_filter) {
ERR_FAIL_INDEX(int(p_filter), int(FILTER_MAX));
if (texture_filter == p_filter) {
return;
@@ -5750,11 +5898,11 @@ void VisualShaderNodeTextureUniform::set_texture_filter(TextureFilter p_filter)
emit_changed();
}
-VisualShaderNodeTextureUniform::TextureFilter VisualShaderNodeTextureUniform::get_texture_filter() const {
+VisualShaderNodeTextureParameter::TextureFilter VisualShaderNodeTextureParameter::get_texture_filter() const {
return texture_filter;
}
-void VisualShaderNodeTextureUniform::set_texture_repeat(TextureRepeat p_repeat) {
+void VisualShaderNodeTextureParameter::set_texture_repeat(TextureRepeat p_repeat) {
ERR_FAIL_INDEX(int(p_repeat), int(REPEAT_MAX));
if (texture_repeat == p_repeat) {
return;
@@ -5763,12 +5911,12 @@ void VisualShaderNodeTextureUniform::set_texture_repeat(TextureRepeat p_repeat)
emit_changed();
}
-VisualShaderNodeTextureUniform::TextureRepeat VisualShaderNodeTextureUniform::get_texture_repeat() const {
+VisualShaderNodeTextureParameter::TextureRepeat VisualShaderNodeTextureParameter::get_texture_repeat() const {
return texture_repeat;
}
-Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("texture_type");
if (texture_type == TYPE_DATA || texture_type == TYPE_COLOR) {
props.push_back("color_default");
@@ -5778,11 +5926,11 @@ Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() con
return props;
}
-bool VisualShaderNodeTextureUniform::is_show_prop_names() const {
+bool VisualShaderNodeTextureParameter::is_show_prop_names() const {
return true;
}
-HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_properties_names() const {
+HashMap<StringName, String> VisualShaderNodeTextureParameter::get_editable_properties_names() const {
HashMap<StringName, String> names;
names.insert("texture_type", RTR("Type"));
names.insert("color_default", RTR("Default Color"));
@@ -5791,21 +5939,21 @@ HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_propert
return names;
}
-void VisualShaderNodeTextureUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureUniform::set_texture_type);
- ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureUniform::get_texture_type);
+void VisualShaderNodeTextureParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureParameter::set_texture_type);
+ ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureParameter::get_texture_type);
- ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureUniform::set_color_default);
- ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureUniform::get_color_default);
+ ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureParameter::set_color_default);
+ ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureParameter::get_color_default);
- ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureUniform::set_texture_filter);
- ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureUniform::get_texture_filter);
+ ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureParameter::set_texture_filter);
+ ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureParameter::get_texture_filter);
- ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureUniform::set_texture_repeat);
- ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureUniform::get_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureParameter::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureParameter::get_texture_repeat);
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black"), "set_color_default", "get_color_default");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat");
@@ -5817,6 +5965,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE);
BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK);
+ BIND_ENUM_CONSTANT(COLOR_DEFAULT_TRANSPARENT);
BIND_ENUM_CONSTANT(COLOR_DEFAULT_MAX);
BIND_ENUM_CONSTANT(FILTER_DEFAULT);
@@ -5834,7 +5983,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(REPEAT_MAX);
}
-bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeTextureParameter::is_qualifier_supported(Qualifier p_qual) const {
switch (p_qual) {
case Qualifier::QUAL_NONE:
return true;
@@ -5848,31 +5997,56 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co
return false;
}
-bool VisualShaderNodeTextureUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeTextureParameter::is_convertible_to_constant() const {
return false; // conversion is not allowed
}
-VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
+VisualShaderNodeTextureParameter::VisualShaderNodeTextureParameter() {
+}
+
+////////////// Texture2D Parameter
+
+String VisualShaderNodeTexture2DParameter::get_caption() const {
+ return "Texture2DParameter";
+}
+
+String VisualShaderNodeTexture2DParameter::get_output_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "sampler2D";
+ default:
+ return "";
+ }
+}
+
+String VisualShaderNodeTexture2DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
+ return code;
+}
+
+VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() {
}
-////////////// Texture Uniform (Triplanar)
+////////////// Texture Parameter (Triplanar)
-String VisualShaderNodeTextureUniformTriplanar::get_caption() const {
+String VisualShaderNodeTextureParameterTriplanar::get_caption() const {
return "TextureUniformTriplanar";
}
-int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const {
+int VisualShaderNodeTextureParameterTriplanar::get_input_port_count() const {
return 2;
}
-VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const {
+VisualShaderNodeTextureParameterTriplanar::PortType VisualShaderNodeTextureParameterTriplanar::get_input_port_type(int p_port) const {
if (p_port == 0 || p_port == 1) {
return PORT_TYPE_VECTOR_3D;
}
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) const {
+String VisualShaderNodeTextureParameterTriplanar::get_input_port_name(int p_port) const {
if (p_port == 0) {
return "weights";
} else if (p_port == 1) {
@@ -5881,11 +6055,11 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port)
return "";
}
-int VisualShaderNodeTextureUniformTriplanar::get_output_port_count() const {
+int VisualShaderNodeTextureParameterTriplanar::get_output_port_count() const {
return 2;
}
-VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_output_port_type(int p_port) const {
+VisualShaderNodeTextureParameterTriplanar::PortType VisualShaderNodeTextureParameterTriplanar::get_output_port_type(int p_port) const {
switch (p_port) {
case 0:
return PORT_TYPE_VECTOR_4D;
@@ -5896,7 +6070,7 @@ VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniform
}
}
-String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port) const {
+String VisualShaderNodeTextureParameterTriplanar::get_output_port_name(int p_port) const {
switch (p_port) {
case 0:
return "color";
@@ -5907,7 +6081,7 @@ String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port)
}
}
-String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
+String VisualShaderNodeTextureParameterTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
String code;
code += "// " + get_caption() + "\n";
@@ -5929,7 +6103,7 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader:
return code;
}
-String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code;
if (p_type == VisualShader::TYPE_VERTEX) {
@@ -5945,8 +6119,15 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader:
return code;
}
-String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- String id = get_uniform_name();
+String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
+ return code;
+}
+
+String VisualShaderNodeTextureParameterTriplanar::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String id = get_parameter_name();
String code;
if (p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) {
@@ -5962,7 +6143,7 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod
return code;
}
-bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+bool VisualShaderNodeTextureParameterTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const {
if (p_port == 0) {
return true;
} else if (p_port == 1) {
@@ -5971,154 +6152,67 @@ bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port,
return false;
}
-VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() {
+VisualShaderNodeTextureParameterTriplanar::VisualShaderNodeTextureParameterTriplanar() {
}
-////////////// Texture2DArray Uniform
+////////////// Texture2DArray Parameter
-String VisualShaderNodeTexture2DArrayUniform::get_caption() const {
- return "Texture2DArrayUniform";
+String VisualShaderNodeTexture2DArrayParameter::get_caption() const {
+ return "Texture2DArrayParameter";
}
-String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port) const {
return "sampler2DArray";
}
-String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name();
-
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black;\n";
- } else {
- code += ";\n";
- }
- break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black_albedo;\n";
- } else {
- code += " : hint_albedo;\n";
- }
- break;
- case TYPE_NORMAL_MAP:
- code += " : hint_normal;\n";
- break;
- case TYPE_ANISOTROPY:
- code += " : hint_anisotropy;\n";
- break;
- default:
- code += ";\n";
- break;
- }
-
+String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
-String VisualShaderNodeTexture2DArrayUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return String();
-}
-
-VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() {
+VisualShaderNodeTexture2DArrayParameter::VisualShaderNodeTexture2DArrayParameter() {
}
-////////////// Texture3D Uniform
+////////////// Texture3D Parameter
-String VisualShaderNodeTexture3DUniform::get_caption() const {
- return "Texture3DUniform";
+String VisualShaderNodeTexture3DParameter::get_caption() const {
+ return "Texture3DParameter";
}
-String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) const {
return "sampler3D";
}
-String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name();
-
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black;\n";
- } else {
- code += ";\n";
- }
- break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black_albedo;\n";
- } else {
- code += " : hint_albedo;\n";
- }
- break;
- case TYPE_NORMAL_MAP:
- code += " : hint_normal;\n";
- break;
- case TYPE_ANISOTROPY:
- code += " : hint_anisotropy;\n";
- break;
- default:
- code += ";\n";
- break;
- }
-
+String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
-String VisualShaderNodeTexture3DUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return String();
-}
-
-VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() {
+VisualShaderNodeTexture3DParameter::VisualShaderNodeTexture3DParameter() {
}
-////////////// Cubemap Uniform
+////////////// Cubemap Parameter
-String VisualShaderNodeCubemapUniform::get_caption() const {
- return "CubemapUniform";
+String VisualShaderNodeCubemapParameter::get_caption() const {
+ return "CubemapParameter";
}
-String VisualShaderNodeCubemapUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const {
return "samplerCube";
}
-String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform samplerCube " + get_uniform_name();
-
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black;\n";
- } else {
- code += ";\n";
- }
- break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black_albedo;\n";
- } else {
- code += " : hint_albedo;\n";
- }
- break;
- case TYPE_NORMAL_MAP:
- code += " : hint_normal;\n";
- break;
- case TYPE_ANISOTROPY:
- code += " : hint_anisotropy;\n";
- break;
- default:
- code += ";\n";
- break;
- }
-
+String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
-String VisualShaderNodeCubemapUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return String();
-}
-
-VisualShaderNodeCubemapUniform::VisualShaderNodeCubemapUniform() {
+VisualShaderNodeCubemapParameter::VisualShaderNodeCubemapParameter() {
}
////////////// If
@@ -6886,23 +6980,23 @@ void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) {
switch (p_op_type) {
case OP_TYPE_SCALAR: {
set_input_port_default_value(0, 0.0, get_input_port_default_value(0));
- set_input_port_default_value(1, 0.0, get_input_port_default_value(1));
+ set_input_port_default_value(1, 1.0, get_input_port_default_value(1));
set_input_port_default_value(2, 0.0, get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_2D: {
set_input_port_default_value(0, Vector2(), get_input_port_default_value(0));
- set_input_port_default_value(1, Vector2(), get_input_port_default_value(1));
+ set_input_port_default_value(1, Vector2(1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector2(), get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
- set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
+ set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_4D: {
- set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
- set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
- set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2));
+ set_input_port_default_value(0, Vector4(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector4(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(1));
+ set_input_port_default_value(2, Vector4(), get_input_port_default_value(2));
} break;
default:
break;
@@ -6936,7 +7030,7 @@ void VisualShaderNodeMultiplyAdd::_bind_methods() {
VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
set_input_port_default_value(0, 0.0);
- set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(1, 1.0);
set_input_port_default_value(2, 0.0);
}
@@ -7066,3 +7160,273 @@ void VisualShaderNodeBillboard::_bind_methods() {
VisualShaderNodeBillboard::VisualShaderNodeBillboard() {
simple_decl = false;
}
+
+////////////// DistanceFade
+
+String VisualShaderNodeDistanceFade::get_caption() const {
+ return "DistanceFade";
+}
+
+int VisualShaderNodeDistanceFade::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeDistanceFade::PortType VisualShaderNodeDistanceFade::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SCALAR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDistanceFade::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "min";
+ case 1:
+ return "max";
+ }
+
+ return "";
+}
+
+int VisualShaderNodeDistanceFade::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeDistanceFade::PortType VisualShaderNodeDistanceFade::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDistanceFade::get_output_port_name(int p_port) const {
+ return "amount";
+}
+
+bool VisualShaderNodeDistanceFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeDistanceFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
+ return code;
+}
+
+VisualShaderNodeDistanceFade::VisualShaderNodeDistanceFade() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 10.0);
+}
+
+////////////// ProximityFade
+
+String VisualShaderNodeProximityFade::get_caption() const {
+ return "ProximityFade";
+}
+
+int VisualShaderNodeProximityFade::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeProximityFade::PortType VisualShaderNodeProximityFade::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeProximityFade::get_input_port_name(int p_port) const {
+ return "distance";
+}
+
+int VisualShaderNodeProximityFade::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeProximityFade::PortType VisualShaderNodeProximityFade::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeProximityFade::get_output_port_name(int p_port) const {
+ return "fade";
+}
+
+bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String proximity_fade_distance = vformat("%s", p_input_vars[0]);
+ code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ if (!RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
+ } else {
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
+ }
+ code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
+ code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() {
+ set_input_port_default_value(0, 1.0);
+}
+
+////////////// Random Range
+
+String VisualShaderNodeRandomRange::get_caption() const {
+ return "RandomRange";
+}
+
+int VisualShaderNodeRandomRange::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeRandomRange::PortType VisualShaderNodeRandomRange::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_3D;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SCALAR;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRandomRange::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "seed";
+ case 1:
+ return "min";
+ case 2:
+ return "max";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRandomRange::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeRandomRange::PortType VisualShaderNodeRandomRange::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRandomRange::get_output_port_name(int p_port) const {
+ return "value";
+}
+
+String VisualShaderNodeRandomRange::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
+ String code;
+
+ code += "\n\n";
+ code += "// 3D Noise with friendly permission by Inigo Quilez\n";
+ code += "vec3 hash_noise_range( vec3 p ) {\n";
+ code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n";
+ code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n";
+ code += "}\n";
+ code += "\n";
+
+ return code;
+}
+
+String VisualShaderNodeRandomRange::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += vformat(" %s = mix(%s, %s, hash_noise_range(%s).x);\n", p_output_vars[0], p_input_vars[1], p_input_vars[2], p_input_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeRandomRange::VisualShaderNodeRandomRange() {
+ set_input_port_default_value(0, Vector3(1.0, 1.0, 1.0));
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+}
+
+////////////// Remap
+
+String VisualShaderNodeRemap::get_caption() const {
+ return "Remap";
+}
+
+int VisualShaderNodeRemap::get_input_port_count() const {
+ return 5;
+}
+
+VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SCALAR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SCALAR;
+ case 3:
+ return PORT_TYPE_SCALAR;
+ case 4:
+ return PORT_TYPE_SCALAR;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRemap::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "value";
+ case 1:
+ return "input min";
+ case 2:
+ return "input max";
+ case 3:
+ return "output min";
+ case 4:
+ return "output max";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRemap::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRemap::get_output_port_name(int p_port) const {
+ return "value";
+}
+
+String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += vformat(" float _input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
+ code += vformat(" float _output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
+ code += vformat(" %s = %s + _output_range * ((%s - %s) / _input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
+
+ return code;
+}
+
+VisualShaderNodeRemap::VisualShaderNodeRemap() {
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+ set_input_port_default_value(3, 0.0);
+ set_input_port_default_value(4, 1.0);
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index b159d25eba..4b883c25cc 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -622,6 +622,28 @@ VARIANT_ENUM_CAST(VisualShaderNodeCubemap::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeCubemap::Source)
///////////////////////////////////////
+
+class VisualShaderNodeLinearSceneDepth : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeLinearSceneDepth, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeLinearSceneDepth();
+};
+
+///////////////////////////////////////
/// OPS
///////////////////////////////////////
@@ -934,7 +956,7 @@ public:
FUNC_FLOOR,
FUNC_ROUND,
FUNC_CEIL,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_SATURATE,
FUNC_NEGATE,
FUNC_ACOSH,
@@ -1053,7 +1075,7 @@ public:
FUNC_EXP,
FUNC_EXP2,
FUNC_FLOOR,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_INVERSE_SQRT,
FUNC_LOG,
FUNC_LOG2,
@@ -1231,6 +1253,30 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeUVFunc::Function)
///////////////////////////////////////
+/// UV POLARCOORD
+///////////////////////////////////////
+
+class VisualShaderNodeUVPolarCoord : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUVPolarCoord, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeUVPolarCoord();
+};
+
+///////////////////////////////////////
/// DOT
///////////////////////////////////////
@@ -1564,21 +1610,20 @@ public:
/// REFRACT
///////////////////////////////////////
-class VisualShaderNodeVectorRefract : public VisualShaderNode {
- GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNode);
+class VisualShaderNodeVectorRefract : public VisualShaderNodeVectorBase {
+ GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNodeVectorBase);
public:
virtual String get_caption() const override;
virtual int get_input_port_count() const override;
- virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
virtual int get_output_port_count() const override;
- virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+ virtual void set_op_type(OpType p_op_type) override;
VisualShaderNodeVectorRefract();
};
@@ -1718,11 +1763,11 @@ public:
};
///////////////////////////////////////
-/// UNIFORMS
+/// PARAMETERS
///////////////////////////////////////
-class VisualShaderNodeFloatUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeFloatUniform, VisualShaderNodeUniform);
+class VisualShaderNodeFloatParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeFloatParameter, VisualShaderNodeParameter);
public:
enum Hint {
@@ -1783,13 +1828,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeFloatUniform();
+ VisualShaderNodeFloatParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeFloatUniform::Hint)
+VARIANT_ENUM_CAST(VisualShaderNodeFloatParameter::Hint)
-class VisualShaderNodeIntUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeIntUniform, VisualShaderNodeUniform);
+class VisualShaderNodeIntParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeIntParameter, VisualShaderNodeParameter);
public:
enum Hint {
@@ -1850,15 +1895,15 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeIntUniform();
+ VisualShaderNodeIntParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeIntUniform::Hint)
+VARIANT_ENUM_CAST(VisualShaderNodeIntParameter::Hint)
///////////////////////////////////////
-class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform);
+class VisualShaderNodeBooleanParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeBooleanParameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -1895,13 +1940,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeBooleanUniform();
+ VisualShaderNodeBooleanParameter();
};
///////////////////////////////////////
-class VisualShaderNodeColorUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform);
+class VisualShaderNodeColorParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeColorParameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -1939,13 +1984,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeColorUniform();
+ VisualShaderNodeColorParameter();
};
///////////////////////////////////////
-class VisualShaderNodeVec2Uniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeVec2Uniform, VisualShaderNodeUniform);
+class VisualShaderNodeVec2Parameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeVec2Parameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -1982,13 +2027,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeVec2Uniform();
+ VisualShaderNodeVec2Parameter();
};
///////////////////////////////////////
-class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform);
+class VisualShaderNodeVec3Parameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeVec3Parameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -2025,17 +2070,17 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeVec3Uniform();
+ VisualShaderNodeVec3Parameter();
};
///////////////////////////////////////
-class VisualShaderNodeVec4Uniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeVec4Uniform, VisualShaderNodeUniform);
+class VisualShaderNodeVec4Parameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeVec4Parameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
- Quaternion default_value;
+ Vector4 default_value;
protected:
static void _bind_methods();
@@ -2060,21 +2105,21 @@ public:
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
- void set_default_value(const Quaternion &p_value);
- Quaternion get_default_value() const;
+ void set_default_value(const Vector4 &p_value);
+ Vector4 get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeVec4Uniform();
+ VisualShaderNodeVec4Parameter();
};
///////////////////////////////////////
-class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform);
+class VisualShaderNodeTransformParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeTransformParameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -2111,13 +2156,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeTransformUniform();
+ VisualShaderNodeTransformParameter();
};
///////////////////////////////////////
-class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform);
+class VisualShaderNodeTextureParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeTextureParameter, VisualShaderNodeParameter);
public:
enum TextureType {
@@ -2131,6 +2176,7 @@ public:
enum ColorDefault {
COLOR_DEFAULT_WHITE,
COLOR_DEFAULT_BLACK,
+ COLOR_DEFAULT_TRANSPARENT,
COLOR_DEFAULT_MAX,
};
@@ -2162,17 +2208,13 @@ protected:
static void _bind_methods();
public:
- virtual String get_caption() const override;
-
virtual int get_input_port_count() const override;
virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
- virtual String get_output_port_name(int p_port) const override;
- virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual HashMap<StringName, String> get_editable_properties_names() const override;
@@ -2195,18 +2237,32 @@ public:
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
- VisualShaderNodeTextureUniform();
+ VisualShaderNodeTextureParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType)
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault)
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureFilter)
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureRepeat)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureType)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::ColorDefault)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureFilter)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureRepeat)
+
+///////////////////////////////////////
+
+class VisualShaderNodeTexture2DParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTexture2DParameter, VisualShaderNodeTextureParameter);
+
+public:
+ virtual String get_caption() const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+
+ VisualShaderNodeTexture2DParameter();
+};
///////////////////////////////////////
-class VisualShaderNodeTextureUniformTriplanar : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeTextureUniformTriplanar, VisualShaderNodeTextureUniform);
+class VisualShaderNodeTextureParameterTriplanar : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTextureParameterTriplanar, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() const override;
@@ -2223,54 +2279,52 @@ public:
virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
- VisualShaderNodeTextureUniformTriplanar();
+ VisualShaderNodeTextureParameterTriplanar();
};
///////////////////////////////////////
-class VisualShaderNodeTexture2DArrayUniform : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeTexture2DArrayUniform, VisualShaderNodeTextureUniform);
+class VisualShaderNodeTexture2DArrayParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTexture2DArrayParameter, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() const override;
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
- VisualShaderNodeTexture2DArrayUniform();
+ VisualShaderNodeTexture2DArrayParameter();
};
///////////////////////////////////////
-class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeTexture3DUniform, VisualShaderNodeTextureUniform);
+class VisualShaderNodeTexture3DParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTexture3DParameter, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() const override;
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
- VisualShaderNodeTexture3DUniform();
+ VisualShaderNodeTexture3DParameter();
};
///////////////////////////////////////
-class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeCubemapUniform, VisualShaderNodeTextureUniform);
+class VisualShaderNodeCubemapParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeCubemapParameter, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() const override;
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
- VisualShaderNodeCubemapUniform();
+ VisualShaderNodeCubemapParameter();
};
///////////////////////////////////////
@@ -2574,4 +2628,87 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeBillboard::BillboardType)
+///////////////////////////////////////
+/// DistanceFade
+///////////////////////////////////////
+
+class VisualShaderNodeDistanceFade : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeDistanceFade, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeDistanceFade();
+};
+
+class VisualShaderNodeProximityFade : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeProximityFade, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeProximityFade();
+};
+
+class VisualShaderNodeRandomRange : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRandomRange, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRandomRange();
+};
+
+class VisualShaderNodeRemap : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRemap, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRemap();
+};
+
#endif // VISUAL_SHADER_NODES_H
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_2d.cpp b/scene/resources/world_2d.cpp
index 9d8e0f7547..75deb1e60b 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -73,8 +73,8 @@ World2D::World2D() {
// Create and configure space2D to be more friendly with pixels than meters
space = PhysicsServer2D::get_singleton()->space_create();
PhysicsServer2D::get_singleton()->space_set_active(space, true);
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 980.0));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1)));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/2d/default_gravity", 980.0));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/2d/default_gravity_vector", Vector2(0, 1)));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/2d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0));
@@ -85,6 +85,7 @@ World2D::World2D() {
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 1));
NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 1));
+ NavigationServer2D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/2d/default_link_connection_radius", 4));
}
World2D::~World2D() {
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index 71ae40ec82..c04b8f6461 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -46,7 +46,7 @@ class World2D : public Resource {
RID space;
RID navigation_map;
- RBSet<Viewport *> viewports;
+ HashSet<Viewport *> viewports;
protected:
static void _bind_methods();
@@ -62,7 +62,7 @@ public:
PhysicsDirectSpaceState2D *get_direct_space_state();
- _FORCE_INLINE_ const RBSet<Viewport *> &get_viewports() { return viewports; }
+ _FORCE_INLINE_ const HashSet<Viewport *> &get_viewports() { return viewports; }
World2D();
~World2D();
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 0088236112..ae8c9a182f 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -31,9 +31,10 @@
#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/resources/camera_attributes.h"
+#include "scene/resources/environment.h"
#include "scene/scene_string_names.h"
#include "servers/navigation_server_3d.h"
@@ -99,17 +100,17 @@ Ref<Environment> World3D::get_fallback_environment() const {
return fallback_environment;
}
-void World3D::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) {
- camera_effects = p_camera_effects;
- if (camera_effects.is_valid()) {
- RS::get_singleton()->scenario_set_camera_effects(scenario, camera_effects->get_rid());
+void World3D::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
+ camera_attributes = p_camera_attributes;
+ if (camera_attributes.is_valid()) {
+ RS::get_singleton()->scenario_set_camera_attributes(scenario, camera_attributes->get_rid());
} else {
- RS::get_singleton()->scenario_set_camera_effects(scenario, RID());
+ RS::get_singleton()->scenario_set_camera_attributes(scenario, RID());
}
}
-Ref<CameraEffects> World3D::get_camera_effects() const {
- return camera_effects;
+Ref<CameraAttributes> World3D::get_camera_attributes() const {
+ return camera_attributes;
}
PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
@@ -124,12 +125,12 @@ void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment);
ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment);
ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment);
- ClassDB::bind_method(D_METHOD("set_camera_effects", "effects"), &World3D::set_camera_effects);
- ClassDB::bind_method(D_METHOD("get_camera_effects"), &World3D::get_camera_effects);
+ ClassDB::bind_method(D_METHOD("set_camera_attributes", "attributes"), &World3D::set_camera_attributes);
+ ClassDB::bind_method(D_METHOD("get_camera_attributes"), &World3D::get_camera_attributes);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space");
ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map");
ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario");
@@ -141,8 +142,8 @@ World3D::World3D() {
scenario = RenderingServer::get_singleton()->scenario_create();
PhysicsServer3D::get_singleton()->space_set_active(space, true);
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/3d/default_gravity", 9.8));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1));
@@ -150,8 +151,9 @@ World3D::World3D() {
navigation_map = NavigationServer3D::get_singleton()->map_create();
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
- NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3));
- NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3));
+ NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25));
+ NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25));
+ NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/3d/default_link_connection_radius", 1.0));
}
World3D::~World3D() {
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index 18d28e812f..411b9aab37 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -32,11 +32,11 @@
#define WORLD_3D_H
#include "core/io/resource.h"
-#include "scene/resources/camera_effects.h"
#include "scene/resources/environment.h"
#include "servers/physics_server_3d.h"
#include "servers/rendering_server.h"
+class CameraAttributes;
class Camera3D;
class VisibleOnScreenNotifier3D;
struct SpatialIndexer;
@@ -51,9 +51,9 @@ private:
Ref<Environment> environment;
Ref<Environment> fallback_environment;
- Ref<CameraEffects> camera_effects;
+ Ref<CameraAttributes> camera_attributes;
- RBSet<Camera3D *> cameras;
+ HashSet<Camera3D *> cameras;
protected:
static void _bind_methods();
@@ -74,10 +74,10 @@ public:
void set_fallback_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_fallback_environment() const;
- void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
- Ref<CameraEffects> get_camera_effects() const;
+ void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
+ Ref<CameraAttributes> get_camera_attributes() const;
- _FORCE_INLINE_ const RBSet<Camera3D *> &get_cameras() const { return cameras; }
+ _FORCE_INLINE_ const HashSet<Camera3D *> &get_cameras() const { return cameras; }
PhysicsDirectSpaceState3D *get_direct_space_state();
diff --git a/scene/resources/world_boundary_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp
index ac5be79d24..013ffb9e24 100644
--- a/scene/resources/world_boundary_shape_2d.cpp
+++ b/scene/resources/world_boundary_shape_2d.cpp
@@ -108,7 +108,7 @@ void WorldBoundaryShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_distance"), &WorldBoundaryShape2D::get_distance);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_distance", "get_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_distance", "get_distance");
}
WorldBoundaryShape2D::WorldBoundaryShape2D() :
diff --git a/scene/resources/world_boundary_shape_3d.cpp b/scene/resources/world_boundary_shape_3d.cpp
index 09d41e8291..400cbae217 100644
--- a/scene/resources/world_boundary_shape_3d.cpp
+++ b/scene/resources/world_boundary_shape_3d.cpp
@@ -80,7 +80,7 @@ void WorldBoundaryShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane);
ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane);
- ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane");
+ ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane", PROPERTY_HINT_NONE, "suffix:m"), "set_plane", "get_plane");
}
WorldBoundaryShape3D::WorldBoundaryShape3D() :
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