summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp506
-rw-r--r--scene/resources/animation.h6
-rw-r--r--scene/resources/audio_stream_wav.cpp20
-rw-r--r--scene/resources/audio_stream_wav.h8
-rw-r--r--scene/resources/bit_map.cpp4
-rw-r--r--scene/resources/capsule_shape_3d.cpp10
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp12
-rw-r--r--scene/resources/curve.cpp49
-rw-r--r--scene/resources/curve.h1
-rw-r--r--scene/resources/cylinder_shape_3d.cpp10
-rw-r--r--scene/resources/default_theme/color_picker_hue.svg1
-rw-r--r--scene/resources/default_theme/default_theme.cpp75
-rw-r--r--scene/resources/default_theme/default_theme.h2
-rw-r--r--scene/resources/default_theme/picker_shape_circle.svg1
-rw-r--r--scene/resources/default_theme/picker_shape_rectangle.svg1
-rw-r--r--scene/resources/default_theme/picker_shape_rectangle_wheel.svg58
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/fog_material.cpp2
-rw-r--r--scene/resources/font.cpp301
-rw-r--r--scene/resources/importer_mesh.cpp47
-rw-r--r--scene/resources/importer_mesh.h2
-rw-r--r--scene/resources/material.cpp104
-rw-r--r--scene/resources/material.h13
-rw-r--r--scene/resources/mesh.cpp59
-rw-r--r--scene/resources/mesh_library.cpp30
-rw-r--r--scene/resources/navigation_mesh.cpp26
-rw-r--r--scene/resources/packed_scene.cpp16
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--scene/resources/particle_process_material.cpp46
-rw-r--r--scene/resources/particle_process_material.h17
-rw-r--r--scene/resources/polygon_path_finder.cpp8
-rw-r--r--scene/resources/primitive_meshes.cpp492
-rw-r--r--scene/resources/primitive_meshes.h48
-rw-r--r--scene/resources/resource_format_text.cpp35
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/resources/shader.h37
-rw-r--r--scene/resources/shape_2d.cpp3
-rw-r--r--scene/resources/skeleton_modification_2d.cpp4
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp2
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp6
-rw-r--r--scene/resources/skeleton_profile.cpp4
-rw-r--r--scene/resources/skin.cpp20
-rw-r--r--scene/resources/sky_material.cpp86
-rw-r--r--scene/resources/sky_material.h10
-rw-r--r--scene/resources/sprite_frames.cpp6
-rw-r--r--scene/resources/style_box.cpp16
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/text_line.cpp49
-rw-r--r--scene/resources/text_paragraph.cpp86
-rw-r--r--scene/resources/texture.cpp56
-rw-r--r--scene/resources/texture.h19
-rw-r--r--scene/resources/theme.cpp34
-rw-r--r--scene/resources/tile_set.cpp18
-rw-r--r--scene/resources/tile_set.h3
-rw-r--r--scene/resources/video_stream.h8
-rw-r--r--scene/resources/visual_shader.cpp406
-rw-r--r--scene/resources/visual_shader.h9
-rw-r--r--scene/resources/visual_shader_nodes.cpp63
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp79
62 files changed, 2221 insertions, 827 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 9d5bc18c96..1eb78f0160 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -35,7 +35,7 @@
#include "scene/scene_string_names.h"
bool Animation::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
+ String prop_name = p_name;
if (p_name == SNAME("_compression")) {
ERR_FAIL_COND_V(tracks.size() > 0, false); //can only set compression if no tracks exist
@@ -63,9 +63,9 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
compression.enabled = true;
return true;
- } else if (name.begins_with("tracks/")) {
- int track = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("tracks/")) {
+ int track = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (tracks.size() == track && what == "type") {
String type = p_value;
@@ -431,7 +431,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
+ String prop_name = p_name;
if (p_name == SNAME("_compression")) {
ERR_FAIL_COND_V(!compression.enabled, false);
@@ -456,15 +456,15 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = comp;
return true;
- } else if (name == "length") {
+ } else if (prop_name == "length") {
r_ret = length;
- } else if (name == "loop_mode") {
+ } else if (prop_name == "loop_mode") {
r_ret = loop_mode;
- } else if (name == "step") {
+ } else if (prop_name == "step") {
r_ret = step;
- } else if (name.begins_with("tracks/")) {
- int track = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("tracks/")) {
+ int track = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
ERR_FAIL_INDEX_V(track, tracks.size(), false);
if (what == "type") {
switch (track_get_type(track)) {
@@ -2102,11 +2102,9 @@ bool Animation::track_is_compressed(int p_track) const {
return bst->compressed_track >= 0;
} break;
default: {
- return false; //animation does not really use transitions
+ return false; // Animation does not really use transitions.
} break;
}
-
- ERR_FAIL_V(false);
}
void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p_value) {
@@ -2317,9 +2315,7 @@ 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 {
@@ -5243,9 +5239,7 @@ bool Animation::_fetch_compressed(uint32_t p_compressed_track, double p_time, Ve
double page_base_time = compression.pages[page_index].time_offset;
const uint8_t *page_data = compression.pages[page_index].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5388,9 +5382,7 @@ void Animation::_get_compressed_key_indices_in_range(uint32_t p_compressed_track
double page_base_time = compression.pages[page_index].time_offset;
const uint8_t *page_data = compression.pages[page_index].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5460,9 +5452,7 @@ int Animation::_get_compressed_key_count(uint32_t p_compressed_track) const {
for (uint32_t i = 0; i < compression.pages.size(); i++) {
const uint8_t *page_data = compression.pages[i].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5496,9 +5486,7 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
for (uint32_t i = 0; i < compression.pages.size(); i++) {
const uint8_t *page_data = compression.pages[i].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5563,6 +5551,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 = a;
+ const Vector<int32_t> arr_b = 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 = a;
+ const Vector<int64_t> arr_b = 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 = a;
+ const Vector<float> arr_b = 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 = a;
+ const Vector<double> arr_b = 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 = a;
+ const Vector<Vector2> arr_b = 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 = a;
+ const Vector<Vector3> arr_b = 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 = a;
+ const Vector<Color> arr_b = 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 46a88df130..49c8fa4c22 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -496,6 +496,12 @@ public:
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();
};
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index a87c8272ea..ce68936370 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -33,7 +33,7 @@
#include "core/io/file_access.h"
#include "core/io/marshalls.h"
-void AudioStreamPlaybackWAV::start(float p_from_pos) {
+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++) {
@@ -67,16 +67,16 @@ int AudioStreamPlaybackWAV::get_loop_count() const {
return 0;
}
-float AudioStreamPlaybackWAV::get_playback_position() const {
+double AudioStreamPlaybackWAV::get_playback_position() const {
return float(offset >> MIX_FRAC_BITS) / base->mix_rate;
}
-void AudioStreamPlaybackWAV::seek(float p_time) {
+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) {
@@ -180,7 +180,7 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst,
final_r = p_src[pos + 1];
}
- if (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */
+ if constexpr (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */
final <<= 8;
if (is_stereo) {
final_r <<= 8;
@@ -194,7 +194,7 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst,
next = p_src[pos + 1];
}
- if (sizeof(Depth) == 1) {
+ if constexpr (sizeof(Depth) == 1) {
next <<= 8;
if (is_stereo) {
next_r <<= 8;
@@ -463,7 +463,7 @@ bool AudioStreamWAV::is_stereo() const {
return stereo;
}
-float AudioStreamWAV::get_length() const {
+double AudioStreamWAV::get_length() const {
int len = data_bytes;
switch (format) {
case AudioStreamWAV::FORMAT_8_BITS:
@@ -481,7 +481,7 @@ float AudioStreamWAV::get_length() const {
len /= 2;
}
- return float(len) / mix_rate;
+ return double(len) / mix_rate;
}
bool AudioStreamWAV::is_monophonic() const {
@@ -580,8 +580,8 @@ Error AudioStreamWAV::save_to_wav(const String &p_path) {
file->store_32(sub_chunk_2_size); //Subchunk2Size
// Add data
- Vector<uint8_t> data = get_data();
- const uint8_t *read_data = data.ptr();
+ Vector<uint8_t> stream_data = get_data();
+ const uint8_t *read_data = stream_data.ptr();
switch (format) {
case AudioStreamWAV::FORMAT_8_BITS:
for (unsigned int i = 0; i < data_bytes; i++) {
diff --git a/scene/resources/audio_stream_wav.h b/scene/resources/audio_stream_wav.h
index d800388d96..d0edc52031 100644
--- a/scene/resources/audio_stream_wav.h
+++ b/scene/resources/audio_stream_wav.h
@@ -64,14 +64,14 @@ class AudioStreamPlaybackWAV : public AudioStreamPlayback {
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;
@@ -137,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;
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 0505f6b559..1b06e09bb8 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -639,9 +639,7 @@ void BitMap::resize(const Size2i &p_new_size) {
}
Ref<Image> BitMap::convert_to_image() const {
- Ref<Image> image;
- image.instantiate();
- image->create(width, height, false, Image::FORMAT_L8);
+ Ref<Image> image = Image::create_empty(width, height, false, Image::FORMAT_L8);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index b0454004a0..f7ed8d98cb 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -33,17 +33,17 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
- float radius = get_radius();
- float height = get_height();
+ float c_radius = get_radius();
+ float c_height = get_height();
Vector<Vector3> points;
- Vector3 d(0, height * 0.5 - radius, 0);
+ Vector3 d(0, c_height * 0.5 - c_radius, 0);
for (int i = 0; i < 360; i++) {
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;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * c_radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * c_radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index e7960f1ba4..5bcefcd0e4 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -33,18 +33,18 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
- Vector<Vector3> points = get_points();
+ Vector<Vector3> poly_points = get_points();
- if (points.size() > 3) {
- Vector<Vector3> varr = Variant(points);
+ if (poly_points.size() > 3) {
+ Vector<Vector3> varr = Variant(poly_points);
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
- for (int i = 0; i < md.edges.size(); i++) {
- lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
- lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
+ for (uint32_t i = 0; i < md.edges.size(); i++) {
+ lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
+ lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
return lines;
}
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 0ea5264935..eda9af9dde 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -936,6 +936,46 @@ Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
}
}
+Transform2D Curve2D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, bool p_loop, real_t p_lookahead) const {
+ real_t path_length = get_baked_length(); // Ensure baked.
+ ERR_FAIL_COND_V_MSG(path_length == 0, Transform2D(), "Length of Curve2D is 0.");
+
+ Vector2 pos = sample_baked(p_offset, p_cubic);
+
+ real_t ahead = p_offset + p_lookahead;
+
+ if (p_loop && ahead >= path_length) {
+ // If our lookahead will loop, we need to check if the path is closed.
+ int point_count = get_point_count();
+ if (point_count > 0) {
+ Vector2 start_point = get_point_position(0);
+ Vector2 end_point = get_point_position(point_count - 1);
+ if (start_point == end_point) {
+ // Since the path is closed we want to 'smooth off'
+ // the corner at the start/end.
+ // So we wrap the lookahead back round.
+ ahead = Math::fmod(ahead, path_length);
+ }
+ }
+ }
+
+ Vector2 ahead_pos = sample_baked(ahead, p_cubic);
+
+ Vector2 tangent_to_curve;
+ if (ahead_pos == pos) {
+ // This will happen at the end of non-looping or non-closed paths.
+ // We'll try a look behind instead, in order to get a meaningful angle.
+ tangent_to_curve =
+ (pos - sample_baked(p_offset - p_lookahead, p_cubic)).normalized();
+ } else {
+ tangent_to_curve = (ahead_pos - pos).normalized();
+ }
+
+ Vector2 normal_of_curve = -tangent_to_curve.orthogonal();
+
+ return Transform2D(normal_of_curve, tangent_to_curve, pos);
+}
+
PackedVector2Array Curve2D::get_baked_points() const {
if (baked_cache_dirty) {
_bake();
@@ -1184,6 +1224,7 @@ void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length);
ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve2D::sample_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked_with_rotation", "offset", "cubic", "loop", "lookahead"), &Curve2D::sample_baked_with_rotation, DEFVAL(false), DEFVAL(true), DEFVAL(4.0));
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);
@@ -1667,6 +1708,10 @@ Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) cons
idx = (end + start) / 2;
}
+ if (idx == count - 1) {
+ return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
+ }
+
real_t offset_begin = baked_dist_cache[idx];
real_t offset_end = baked_dist_cache[idx + 1];
@@ -1675,10 +1720,6 @@ Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) cons
real_t frac = (p_offset - offset_begin) / idx_interval;
- if (idx == count - 1) {
- return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
- }
-
Vector3 forward = (rp[idx + 1] - rp[idx]).normalized();
Vector3 up = r[idx];
Vector3 up1 = r[idx + 1];
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 88b6dda096..fa1d35aab1 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -216,6 +216,7 @@ public:
real_t get_baked_length() const;
Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const;
+ Transform2D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false, bool p_loop = true, real_t p_lookahead = 4.0) 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;
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index a5951db8ea..e5f417cbcc 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -33,17 +33,17 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
- float radius = get_radius();
- float height = get_height();
+ float c_radius = get_radius();
+ float c_height = get_height();
Vector<Vector3> points;
- Vector3 d(0, height * 0.5, 0);
+ Vector3 d(0, c_height * 0.5, 0);
for (int i = 0; i < 360; i++) {
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;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * c_radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * c_radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
diff --git a/scene/resources/default_theme/color_picker_hue.svg b/scene/resources/default_theme/color_picker_hue.svg
deleted file mode 100644
index ff75d5eb9e..0000000000
--- a/scene/resources/default_theme/color_picker_hue.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 1 256" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(0 256 -256 0 0 0)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#f00"/><stop offset=".04" stop-color="#ff4000"/><stop offset=".08" stop-color="#ff8000"/><stop offset=".17" stop-color="#ff0"/><stop offset=".25" stop-color="#80ff00"/><stop offset=".33" stop-color="#0f0"/><stop offset=".42" stop-color="#00ff80"/><stop offset=".5" stop-color="#0ff"/><stop offset=".58" stop-color="#0080ff"/><stop offset=".63" stop-color="#0040ff"/><stop offset=".67" stop-color="#00f"/><stop offset=".75" stop-color="#8000ff"/><stop offset=".83" stop-color="#f0f"/><stop offset=".92" stop-color="#ff0080"/><stop offset="1" stop-color="#f00"/></linearGradient><path d="m0 0h1v256h-1z" fill="url(#a)"/></svg>
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 869d582935..894936acd7 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -43,6 +43,8 @@
#include "modules/svg/image_loader_svg.h"
#endif
+static const int default_font_size = 16;
+
static float scale = 1.0;
static const int default_margin = 4;
@@ -431,7 +433,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("font_color", "TextEdit", control_font_color);
- theme->set_color("font_selected_color", "TextEdit", control_font_pressed_color);
+ theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", control_font_disabled_color);
theme->set_color("font_placeholder_color", "TextEdit", control_font_placeholder_color);
theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1));
@@ -474,7 +476,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
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));
+ theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0, 0));
theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("font_placeholder_color", "CodeEdit", control_font_placeholder_color);
theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1));
@@ -551,6 +553,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("grabber_disabled", "HSlider", icons["slider_grabber_disabled"]);
theme->set_icon("tick", "HSlider", icons["hslider_tick"]);
+ theme->set_constant("grabber_offset", "HSlider", 0);
+
// VSlider
theme->set_stylebox("slider", "VSlider", style_slider);
@@ -562,6 +566,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("grabber_disabled", "VSlider", icons["slider_grabber_disabled"]);
theme->set_icon("tick", "VSlider", icons["vslider_tick"]);
+ theme->set_constant("grabber_offset", "VSlider", 0);
+
// SpinBox
theme->set_icon("updown", "SpinBox", icons["updown"]);
@@ -874,14 +880,72 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_width", "ColorPicker", 30 * scale);
theme->set_constant("label_width", "ColorPicker", 10 * scale);
+ theme->set_icon("folded_arrow", "ColorPicker", icons["arrow_right"]);
+ theme->set_icon("expanded_arrow", "ColorPicker", icons["arrow_down"]);
theme->set_icon("screen_picker", "ColorPicker", icons["color_picker_pipette"]);
+ theme->set_icon("shape_circle", "ColorPicker", icons["picker_shape_circle"]);
+ theme->set_icon("shape_rect", "ColorPicker", icons["picker_shape_rectangle"]);
+ theme->set_icon("shape_rect_wheel", "ColorPicker", icons["picker_shape_rectangle_wheel"]);
theme->set_icon("add_preset", "ColorPicker", icons["add"]);
- theme->set_icon("color_hue", "ColorPicker", icons["color_picker_hue"]);
theme->set_icon("sample_bg", "ColorPicker", icons["mini_checkerboard"]);
theme->set_icon("overbright_indicator", "ColorPicker", icons["color_picker_overbright"]);
theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]);
theme->set_icon("picker_cursor", "ColorPicker", icons["color_picker_cursor"]);
+ {
+ const int precision = 7;
+
+ Ref<Gradient> hue_gradient;
+ hue_gradient.instantiate();
+ PackedFloat32Array offsets;
+ offsets.resize(precision);
+ PackedColorArray colors;
+ colors.resize(precision);
+
+ for (int i = 0; i < precision; i++) {
+ float h = i / float(precision - 1);
+ offsets.write[i] = h;
+ colors.write[i] = Color::from_hsv(h, 1, 1);
+ }
+ hue_gradient->set_offsets(offsets);
+ hue_gradient->set_colors(colors);
+
+ Ref<GradientTexture2D> hue_texture;
+ hue_texture.instantiate();
+ hue_texture->set_width(800);
+ hue_texture->set_height(6);
+ hue_texture->set_gradient(hue_gradient);
+
+ theme->set_icon("color_hue", "ColorPicker", hue_texture);
+ }
+
+ {
+ const int precision = 7;
+
+ Ref<Gradient> hue_gradient;
+ hue_gradient.instantiate();
+ PackedFloat32Array offsets;
+ offsets.resize(precision);
+ PackedColorArray colors;
+ colors.resize(precision);
+
+ for (int i = 0; i < precision; i++) {
+ float h = i / float(precision - 1);
+ offsets.write[i] = h;
+ colors.write[i] = Color::from_ok_hsl(h, 1, 0.5);
+ }
+ hue_gradient->set_offsets(offsets);
+ hue_gradient->set_colors(colors);
+
+ Ref<GradientTexture2D> hue_texture;
+ hue_texture.instantiate();
+ hue_texture->set_width(800);
+ hue_texture->set_height(6);
+ hue_texture->set_gradient(hue_gradient);
+
+ theme->set_icon("color_okhsl_hue", "ColorPicker", hue_texture);
+ }
+
// ColorPickerButton
theme->set_icon("bg", "ColorPickerButton", icons["mini_checkerboard"]);
@@ -948,7 +1012,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font_size("mono_font_size", "RichTextLabel", -1);
theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1));
- theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0));
+ theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
@@ -969,6 +1033,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_constant("text_highlight_h_padding", "RichTextLabel", 3 * scale);
+ theme->set_constant("text_highlight_v_padding", "RichTextLabel", 3 * scale);
+
// Containers
theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index 003934ce90..5243bcefa7 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -33,8 +33,6 @@
#include "scene/resources/theme.h"
-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, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
diff --git a/scene/resources/default_theme/picker_shape_circle.svg b/scene/resources/default_theme/picker_shape_circle.svg
new file mode 100644
index 0000000000..8e7fb7f06e
--- /dev/null
+++ b/scene/resources/default_theme/picker_shape_circle.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h16v16h-16z"/></clipPath><g clip-path="url(#a)" fill="#eaeaea"><rect height="11" rx="5.5" transform="translate(1 2)" width="11"/><path d="m0 0h2v11h-2z" transform="translate(13 2)"/></g></svg>
diff --git a/scene/resources/default_theme/picker_shape_rectangle.svg b/scene/resources/default_theme/picker_shape_rectangle.svg
new file mode 100644
index 0000000000..3c7dd46884
--- /dev/null
+++ b/scene/resources/default_theme/picker_shape_rectangle.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h16v16h-16z"/></clipPath><g clip-path="url(#a)" fill="#eaeaea"><path d="m0 0h11v11h-11z" transform="translate(1 2)"/><path d="m0 0h2v11h-2z" transform="translate(13 2)"/></g></svg>
diff --git a/scene/resources/default_theme/picker_shape_rectangle_wheel.svg b/scene/resources/default_theme/picker_shape_rectangle_wheel.svg
new file mode 100644
index 0000000000..e85665a8f2
--- /dev/null
+++ b/scene/resources/default_theme/picker_shape_rectangle_wheel.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ height="16"
+ viewBox="0 0 16 16"
+ width="16"
+ version="1.1"
+ id="svg11"
+ sodipodi:docname="PickerShapeRectangleWheel.svg"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs15" />
+ <sodipodi:namedview
+ id="namedview13"
+ pagecolor="#505050"
+ bordercolor="#ffffff"
+ borderopacity="1"
+ inkscape:pageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="1"
+ showgrid="true"
+ inkscape:zoom="16"
+ inkscape:cx="0.53125"
+ inkscape:cy="5.28125"
+ inkscape:window-width="1920"
+ inkscape:window-height="1001"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg11">
+ <inkscape:grid
+ type="xygrid"
+ id="grid944" />
+ </sodipodi:namedview>
+ <clipPath
+ id="a">
+ <path
+ d="m0 0h16v16h-16z"
+ id="path2" />
+ </clipPath>
+ <g
+ clip-path="url(#a)"
+ fill="#eaeaea"
+ id="g9"
+ transform="matrix(0.85714286,0,0,0.85714286,1.1428571,1.1428571)">
+ <path
+ d="M 7,2 A 5,5 0 1 0 12,7 5.006,5.006 0 0 0 7,2 M 7,0 A 7,7 0 1 1 0,7 7,7 0 0 1 7,0 Z"
+ transform="translate(1,1)"
+ id="path5" />
+ <path
+ d="M 0,0 H 7 V 7 H 0 Z"
+ transform="translate(4.5,4.5)"
+ id="path7" />
+ </g>
+</svg>
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index ebdaaaa95f..23bd8a4be4 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -78,7 +78,7 @@ float Environment::get_sky_custom_fov() const {
void Environment::set_sky_rotation(const Vector3 &p_rotation) {
bg_sky_rotation = p_rotation;
- RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation));
+ RS::get_singleton()->environment_set_sky_orientation(environment, Basis::from_euler(p_rotation));
}
Vector3 Environment::get_sky_rotation() const {
diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp
index 0395ed0346..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_less"), "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");
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 189d8d5502..79ca87e9d6 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -127,16 +127,18 @@ void Font::_invalidate_rids() {
}
bool Font::_is_cyclic(const Ref<Font> &p_f, int p_depth) const {
- ERR_FAIL_COND_V(p_depth > MAX_FALLBACK_DEPTH, false);
+ ERR_FAIL_COND_V(p_depth > MAX_FALLBACK_DEPTH, true);
if (p_f.is_null()) {
return false;
}
+ if (p_f == this) {
+ return true;
+ }
for (int i = 0; i < p_f->fallbacks.size(); i++) {
const Ref<Font> &f = p_f->fallbacks[i];
- if (f == this) {
+ if (_is_cyclic(f, p_depth + 1)) {
return true;
}
- return _is_cyclic(f, p_depth + 1);
}
return false;
}
@@ -147,7 +149,10 @@ void Font::reset_state() {
// Fallbacks.
void Font::set_fallbacks(const TypedArray<Font> &p_fallbacks) {
- ERR_FAIL_COND(_is_cyclic(this, 0));
+ for (int i = 0; i < p_fallbacks.size(); i++) {
+ const Ref<Font> &f = p_fallbacks[i];
+ ERR_FAIL_COND_MSG(_is_cyclic(f, 0), "Cyclic font fallback.");
+ }
for (int i = 0; i < fallbacks.size(); i++) {
Ref<Font> f = fallbacks[i];
if (f.is_valid()) {
@@ -259,7 +264,7 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen
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_jst_flags.operator int64_t(), hash);
}
hash = hash_djb2_one_64(p_direction, hash);
hash = hash_djb2_one_64(p_orientation, hash);
@@ -272,13 +277,15 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen
buffer->set_direction(p_direction);
buffer->set_orientation(p_orientation);
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- buffer->set_horizontal_alignment(p_alignment);
- buffer->set_width(p_width);
- buffer->set_flags(p_jst_flags);
- }
cache.insert(hash, buffer);
}
+
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_flags);
+ }
+
return buffer->get_size();
}
@@ -286,8 +293,8 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment
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_brk_flags.operator int64_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
hash = hash_djb2_one_64(p_direction, hash);
hash = hash_djb2_one_64(p_orientation, hash);
@@ -316,7 +323,7 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
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_jst_flags.operator int64_t(), hash);
}
hash = hash_djb2_one_64(p_direction, hash);
hash = hash_djb2_one_64(p_orientation, hash);
@@ -352,8 +359,8 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S
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_brk_flags.operator int64_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
hash = hash_djb2_one_64(p_direction, hash);
hash = hash_djb2_one_64(p_orientation, hash);
@@ -389,7 +396,7 @@ void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const Str
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_jst_flags.operator int64_t(), hash);
}
hash = hash_djb2_one_64(p_direction, hash);
hash = hash_djb2_one_64(p_orientation, hash);
@@ -425,8 +432,8 @@ void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos,
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_brk_flags.operator int64_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
hash = hash_djb2_one_64(p_direction, hash);
hash = hash_djb2_one_64(p_orientation, hash);
@@ -554,7 +561,6 @@ Font::Font() {
}
Font::~Font() {
- reset_state();
}
/*************************************************************************/
@@ -997,11 +1003,11 @@ void FontFile::_bind_methods() {
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::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", 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::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");
@@ -1059,12 +1065,12 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
}
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));
+ const int32_t *char_data = &arr[i * 9];
+ char32_t c = char_data[0];
+ set_glyph_texture_idx(0, Vector2i(16, 0), c, char_data[1]);
+ set_glyph_uv_rect(0, Vector2i(16, 0), c, Rect2(char_data[2], char_data[3], char_data[4], char_data[5]));
+ set_glyph_offset(0, Vector2i(16, 0), c, Size2(char_data[6], char_data[7]));
+ set_glyph_advance(0, 16, c, Vector2(char_data[8], 0));
}
} else if (tokens.size() == 1 && tokens[0] == "kernings") {
// Compatibility, BitmapFont.
@@ -1076,8 +1082,8 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
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));
+ const int32_t *kern_data = &arr[i * 3];
+ set_kerning(0, 16, Vector2i(kern_data[0], kern_data[1]), Vector2(kern_data[2], 0));
}
} else if (tokens.size() == 1 && tokens[0] == "height") {
// Compatibility, BitmapFont.
@@ -1102,12 +1108,12 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
#endif // DISABLE_DEPRECATED
if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- set_language_support_override(lang, p_value);
+ String lang_code = tokens[1];
+ set_language_support_override(lang_code, 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);
+ String script_code = tokens[1];
+ set_script_support_override(script_code, p_value);
return true;
} else if (tokens.size() >= 3 && tokens[0] == "cache") {
int cache_index = tokens[1].to_int();
@@ -1181,12 +1187,12 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
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);
+ String lang_code = tokens[1];
+ r_ret = get_language_support_override(lang_code);
return true;
} else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- r_ret = get_script_support_override(script);
+ String script_code = tokens[1];
+ r_ret = get_script_support_override(script_code);
return true;
} else if (tokens.size() >= 3 && tokens[0] == "cache") {
int cache_index = tokens[1].to_int();
@@ -1335,6 +1341,19 @@ void FontFile::reset_state() {
/*************************************************************************/
+// OEM encoding mapping for 0x80..0xFF range.
+static const char32_t _oem_to_unicode[][129] = {
+ U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\u0160\u2039\u015a\u0164\u017d\u0179\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0161\u203a\u015b\u0165\u017e\u017a\xa0\u02c7\u02d8\u0141\xa4\u0104\xa6\xa7\xa8\xa9\u015e\xab\xac\xad\xae\u017b\xb0\xb1\u02db\u0142\xb4\xb5\xb6\xb7\xb8\u0105\u015f\xbb\u013d\u02dd\u013e\u017c\u0154\xc1\xc2\u0102\xc4\u0139\u0106\xc7\u010c\xc9\u0118\xcb\u011a\xcd\xce\u010e\u0110\u0143\u0147\xd3\xd4\u0150\xd6\xd7\u0158\u016e\xda\u0170\xdc\xdd\u0162\xdf\u0155\xe1\xe2\u0103\xe4\u013a\u0107\xe7\u010d\xe9\u0119\xeb\u011b\xed\xee\u010f\u0111\u0144\u0148\xf3\xf4\u0151\xf6\xf7\u0159\u016f\xfa\u0171\xfc\xfd\u0163\u02d9", // 1250 - Latin 2
+ U"\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", // 1251 - Cyrillic
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\u017d\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\u017e\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", // 1252 - Latin 1
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\u0385\u0386\xa3\xa4\xa5\xa6\xa7\xa8\xa9\ufffe\xab\xac\xad\xae\u2015\xb0\xb1\xb2\xb3\u0384\xb5\xb6\xb7\u0388\u0389\u038a\xbb\u038c\xbd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffe\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffe", // 1253 - Greek
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\u011e\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\u0130\u015e\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\u011f\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u0131\u015f\xff", // 1254 - Turkish
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\xa1\xa2\xa3\u20aa\xa5\xa6\xa7\xa8\xa9\xd7\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xf7\xbb\xbc\xbd\xbe\xbf\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\ufffe\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05f0\u05f1\u05f2\u05f3\u05f4\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffe\ufffe\u200e\u200f\ufffe", // 1255 - Hebrew
+ U"\u20ac\u067e\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0679\u2039\u0152\u0686\u0698\u0688\u06af\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u06a9\u2122\u0691\u203a\u0153\u200c\u200d\u06ba\xa0\u060c\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\u06be\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\u061b\xbb\xbc\xbd\xbe\u061f\u06c1\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\xd7\u0637\u0638\u0639\u063a\u0640\u0641\u0642\u0643\xe0\u0644\xe2\u0645\u0646\u0647\u0648\xe7\xe8\xe9\xea\xeb\u0649\u064a\xee\xef\u064b\u064c\u064d\u064e\xf4\u064f\u0650\xf7\u0651\xf9\u0652\xfb\xfc\u200e\u200f\u06d2", // 1256 - Arabic
+ U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\xa8\u02c7\xb8\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\xaf\u02db\ufffe\xa0\ufffe\xa2\xa3\xa4\ufffe\xa6\xa7\xd8\xa9\u0156\xab\xac\xad\xae\xc6\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xf8\xb9\u0157\xbb\xbc\xbd\xbe\xe6\u0104\u012e\u0100\u0106\xc4\xc5\u0118\u0112\u010c\xc9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\xd3\u014c\xd5\xd6\xd7\u0172\u0141\u015a\u016a\xdc\u017b\u017d\xdf\u0105\u012f\u0101\u0107\xe4\xe5\u0119\u0113\u010d\xe9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\xf3\u014d\xf5\xf6\xf7\u0173\u0142\u015b\u016b\xfc\u017c\u017e\u02d9", // 1257 - Baltic
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\u0102\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\u0300\xcd\xce\xcf\u0110\xd1\u0309\xd3\xd4\u01a0\xd6\xd7\xd8\xd9\xda\xdb\xdc\u01af\u0303\xdf\xe0\xe1\xe2\u0103\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\u0301\xed\xee\xef\u0111\xf1\u0323\xf3\xf4\u01a1\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u01b0\u20ab\xff", // 1258 - Vietnamese
+};
+
Error FontFile::load_bitmap_font(const String &p_path) {
reset_state();
@@ -1365,10 +1384,12 @@ Error FontFile::load_bitmap_font(const String &p_path) {
f->get_buffer((unsigned char *)&magic, 4);
if (magic[0] == 'B' && magic[1] == 'M' && magic[2] == 'F') {
// Binary BMFont file.
- ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported."), (int)magic[3]));
+ ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported (should be 3)."), (int)magic[3]));
uint8_t block_type = f->get_8();
uint32_t block_size = f->get_32();
+ bool unicode = false;
+ uint8_t encoding = 9;
while (!f->eof_reached()) {
uint64_t off = f->get_position();
switch (block_type) {
@@ -1376,14 +1397,48 @@ Error FontFile::load_bitmap_font(const String &p_path) {
ERR_FAIL_COND_V_MSG(block_size < 15, ERR_CANT_CREATE, RTR("Invalid BMFont info block size."));
base_size = f->get_16();
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.set_flag(TextServer::FONT_BOLD);
}
if (flags & (1 << 2)) {
st_flags.set_flag(TextServer::FONT_ITALIC);
}
- f->get_8(); // non-unicode charset, skip
+ unicode = (flags & 0x02);
+ uint8_t encoding_id = f->get_8(); // non-unicode charset
+ if (!unicode) {
+ switch (encoding_id) {
+ case 0x00: {
+ encoding = 2;
+ } break;
+ case 0xB2: {
+ encoding = 6;
+ } break;
+ case 0xBA: {
+ encoding = 7;
+ } break;
+ case 0xEE: {
+ encoding = 0;
+ } break;
+ case 0xA1: {
+ encoding = 3;
+ } break;
+ case 0xB1: {
+ encoding = 5;
+ } break;
+ case 0xCC: {
+ encoding = 1;
+ } break;
+ case 0xA2: {
+ encoding = 4;
+ } break;
+ case 0xA3: {
+ encoding = 8;
+ } break;
+ default: {
+ WARN_PRINT(vformat("Unknown BMFont OEM encoding %x, parsing as Unicode (should be 0x00 - Latin 1, 0xB2 - Arabic, 0xBA - Baltic, 0xEE - Latin 2, 0xA1 - Greek, 0xB1 - Hebrew, 0xCC - Cyrillic, 0xA2 - Turkish, 0xA3 - Vietnamese).", encoding_id));
+ } break;
+ };
+ }
f->get_16(); // stretch_h, skip
f->get_8(); // aa, skip
f->get_32(); // padding, skip
@@ -1486,6 +1541,14 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Rect2 uv_rect;
char32_t idx = f->get_32();
+ if (!unicode && encoding < 9) {
+ if (idx >= 0x80 && idx <= 0xFF) {
+ idx = _oem_to_unicode[encoding][idx - 0x80];
+ } else if (idx > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
+ idx = 0x00;
+ }
+ }
uv_rect.position.x = (int16_t)f->get_16();
uv_rect.position.y = (int16_t)f->get_16();
uv_rect.size.width = (int16_t)f->get_16();
@@ -1502,24 +1565,25 @@ Error FontFile::load_bitmap_font(const String &p_path) {
int texture_idx = f->get_8();
uint8_t channel = f->get_8();
- ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, RTR("Invalid glyph channel."));
int ch_off = 0;
- switch (channel) {
- case 1:
- ch_off = 2;
- break; // B
- case 2:
- ch_off = 1;
- break; // G
- case 4:
- ch_off = 0;
- break; // R
- case 8:
- ch_off = 3;
- break; // A
- default:
- ch_off = 0;
- break;
+ if (packed) {
+ switch (channel) {
+ case 1:
+ ch_off = 2;
+ break; // B
+ case 2:
+ ch_off = 1;
+ break; // G
+ case 4:
+ ch_off = 0;
+ break; // R
+ case 8:
+ ch_off = 3;
+ break; // A
+ default:
+ ch_off = 0;
+ break;
+ }
}
set_glyph_advance(0, base_size, idx, advance);
set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
@@ -1540,6 +1604,20 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Vector2i kpk;
kpk.x = f->get_32();
kpk.y = f->get_32();
+ if (!unicode && encoding < 9) {
+ if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
+ kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
+ } else if (kpk.x > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.x = 0x00;
+ }
+ if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
+ kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
+ } else if (kpk.y > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.y));
+ kpk.y = 0x00;
+ }
+ }
set_kerning(0, base_size, kpk, Vector2((int16_t)f->get_16(), 0));
}
} break;
@@ -1555,6 +1633,8 @@ Error FontFile::load_bitmap_font(const String &p_path) {
} else {
// Text BMFont file.
f->seek(0);
+ bool unicode = false;
+ uint8_t encoding = 9;
while (true) {
String line = f->get_line();
@@ -1619,7 +1699,37 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("face")) {
font_name = keys["face"];
}
- ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
+ if (keys.has("unicode")) {
+ unicode = keys["unicode"].to_int();
+ }
+ if (!unicode) {
+ if (keys.has("charset")) {
+ String encoding_name = keys["charset"].to_upper();
+ if (encoding_name == "" || encoding_name == "ASCII" || encoding_name == "ANSI") {
+ encoding = 2;
+ } else if (encoding_name == "ARABIC") {
+ encoding = 6;
+ } else if (encoding_name == "BALTIC") {
+ encoding = 7;
+ } else if (encoding_name == "EASTEUROPE") {
+ encoding = 0;
+ } else if (encoding_name == "GREEK") {
+ encoding = 3;
+ } else if (encoding_name == "HEBREW") {
+ encoding = 5;
+ } else if (encoding_name == "RUSSIAN") {
+ encoding = 1;
+ } else if (encoding_name == "TURKISH") {
+ encoding = 4;
+ } else if (encoding_name == "VIETNAMESE") {
+ encoding = 8;
+ } else {
+ WARN_PRINT(vformat("Unknown BMFont OEM encoding %s, parsing as Unicode (should be ANSI, ASCII, ARABIC, BALTIC, EASTEUROPE, GREEK, HEBREW, RUSSIAN, TURKISH or VIETNAMESE).", encoding_name));
+ }
+ } else {
+ encoding = 2;
+ }
+ }
} else if (type == "common") {
if (keys.has("lineHeight")) {
height = keys["lineHeight"].to_int();
@@ -1678,7 +1788,10 @@ Error FontFile::load_bitmap_font(const String &p_path) {
ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Unsupported BMFont texture format."));
}
} else {
- if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline
+ if ((ch[3] == 0) && (ch[0] == 4) && (ch[1] == 4) && (ch[2] == 4) && img->get_format() == Image::FORMAT_RGBA8) { // might be RGBA8 color, no outline (color part of the image should be sold white, but some apps designed for Godot 3 generate color fonts with this config)
+ outline = 0;
+ set_texture_image(0, Vector2i(base_size, 0), page, img);
+ } else if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline
outline = 0;
ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
set_texture_image(0, Vector2i(base_size, 0), page, img);
@@ -1713,6 +1826,14 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("id")) {
idx = keys["id"].to_int();
+ if (!unicode && encoding < 9) {
+ if (idx >= 0x80 && idx <= 0xFF) {
+ idx = _oem_to_unicode[encoding][idx - 0x80];
+ } else if (idx > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
+ idx = 0x00;
+ }
+ }
}
if (keys.has("x")) {
uv_rect.position.x = keys["x"].to_int();
@@ -1747,24 +1868,25 @@ Error FontFile::load_bitmap_font(const String &p_path) {
channel = keys["chnl"].to_int();
}
- ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, RTR("Invalid glyph channel."));
int ch_off = 0;
- switch (channel) {
- case 1:
- ch_off = 2;
- break; // B
- case 2:
- ch_off = 1;
- break; // G
- case 4:
- ch_off = 0;
- break; // R
- case 8:
- ch_off = 3;
- break; // A
- default:
- ch_off = 0;
- break;
+ if (packed) {
+ switch (channel) {
+ case 1:
+ ch_off = 2;
+ break; // B
+ case 2:
+ ch_off = 1;
+ break; // G
+ case 4:
+ ch_off = 0;
+ break; // R
+ case 8:
+ ch_off = 3;
+ break; // A
+ default:
+ ch_off = 0;
+ break;
+ }
}
set_glyph_advance(0, base_size, idx, advance);
set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
@@ -1785,6 +1907,20 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("second")) {
kpk.y = keys["second"].to_int();
}
+ if (!unicode && encoding < 9) {
+ if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
+ kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
+ } else if (kpk.x > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.x = 0x00;
+ }
+ if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
+ kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
+ } else if (kpk.y > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.y = 0x00;
+ }
+ }
if (keys.has("amount")) {
set_kerning(0, base_size, kpk, Vector2(keys["amount"].to_int(), 0));
}
@@ -1807,8 +1943,8 @@ Error FontFile::load_bitmap_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);
- set_data(data);
+ Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path);
+ set_data(font_data);
return OK;
}
@@ -2433,11 +2569,10 @@ int32_t FontFile::get_glyph_index(int p_size, char32_t p_char, char32_t p_variat
}
FontFile::FontFile() {
- /* NOP */
}
FontFile::~FontFile() {
- reset_state();
+ _clear_cache();
}
/*************************************************************************/
@@ -2688,7 +2823,6 @@ FontVariation::FontVariation() {
}
FontVariation::~FontVariation() {
- reset_state();
}
/*************************************************************************/
@@ -2724,11 +2858,11 @@ void SystemFont::_bind_methods() {
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::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", 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::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");
@@ -3081,5 +3215,4 @@ SystemFont::SystemFont() {
}
SystemFont::~SystemFont() {
- reset_state();
}
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 0afca95de0..b728c24e0d 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -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,6 +322,22 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
+ 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));
@@ -792,9 +829,9 @@ void ImporterMesh::_set_data(const Dictionary &p_data) {
ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX);
Array arr = s["arrays"];
Dictionary lods;
- String name;
+ String surf_name;
if (s.has("name")) {
- name = s["name"];
+ surf_name = s["name"];
}
if (s.has("lods")) {
lods = s["lods"];
@@ -811,7 +848,7 @@ void ImporterMesh::_set_data(const Dictionary &p_data) {
if (s.has("flags")) {
flags = s["flags"];
}
- add_surface(prim, arr, b_shapes, lods, material, name, flags);
+ add_surface(prim, arr, b_shapes, lods, material, surf_name, flags);
}
}
}
@@ -1246,7 +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"), &ImporterMesh::generate_lods);
+ 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 dce2638c19..088a77edd1 100644
--- a/scene/resources/importer_mesh.h
+++ b/scene/resources/importer_mesh.h
@@ -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;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 448ff74a53..10d193f950 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -107,18 +107,15 @@ Shader::Mode Material::get_shader_mode() const {
}
bool Material::_can_do_next_pass() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_do_next_pass, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_do_next_pass, ret);
+ return ret;
}
+
bool Material::_can_use_render_priority() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_use_render_priority, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_use_render_priority, ret);
+ return ret;
}
void Material::_bind_methods() {
@@ -156,17 +153,7 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("shader_parameter/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_parameter/", "");
- } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_uniform/", "");
- } else if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- }
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
set_shader_parameter(pr, p_value);
return true;
@@ -178,25 +165,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_uniform(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("shader_parameter/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_parameter/", "");
- } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_uniform/", "");
- } else if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- }
-
+ 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;
}
}
@@ -238,6 +209,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
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);
@@ -252,6 +224,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_SUBGROUP;
info.name = last_subgroup.capitalize();
+ info.hint_string = "shader_parameter/";
List<PropertyInfo> subgroup;
subgroup.push_back(info);
@@ -271,39 +244,42 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
- info.name = "Shader Param";
+ info.name = "Shader Parameters";
+ info.hint_string = "shader_parameter/";
groups["<None>"]["<None>"].push_back(info);
}
PropertyInfo info = E->get();
- info.name = info.name;
+ info.name = "shader_parameter/" + info.name;
groups[last_group][last_subgroup].push_back(info);
}
- // Sort groups alphabetically.
- List<UniformProp> props;
+ List<String> group_names;
for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
- for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
- for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
- if (subgroup->key == "<None>") {
- props.push_back({ group->key, item->get() });
- } else {
- props.push_back({ group->key + "::" + subgroup->key, item->get() });
- }
- }
- }
+ group_names.push_back(group->key);
}
- props.sort_custom<UniformPropComparator>();
+ group_names.sort();
- for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
- p_list->push_back(E->get().info);
+ 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 StringName &p_name) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
Variant current_value;
@@ -316,7 +292,7 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
return true;
@@ -924,6 +900,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";
@@ -931,6 +908,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
@@ -939,6 +917,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";
@@ -949,7 +929,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;
@@ -2365,7 +2345,7 @@ void BaseMaterial3D::set_on_top_of_alpha() {
set_flag(FLAG_DISABLE_DEPTH_TEST, true);
}
-void BaseMaterial3D::set_proximity_fade(bool p_enable) {
+void BaseMaterial3D::set_proximity_fade_enabled(bool p_enable) {
proximity_fade_enabled = p_enable;
_queue_shader_change();
notify_property_list_changed();
@@ -2641,7 +2621,7 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refraction_texture_channel", "channel"), &BaseMaterial3D::set_refraction_texture_channel);
ClassDB::bind_method(D_METHOD("get_refraction_texture_channel"), &BaseMaterial3D::get_refraction_texture_channel);
- ClassDB::bind_method(D_METHOD("set_proximity_fade", "enabled"), &BaseMaterial3D::set_proximity_fade);
+ ClassDB::bind_method(D_METHOD("set_proximity_fade_enabled", "enabled"), &BaseMaterial3D::set_proximity_fade_enabled);
ClassDB::bind_method(D_METHOD("is_proximity_fade_enabled"), &BaseMaterial3D::is_proximity_fade_enabled);
ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &BaseMaterial3D::set_proximity_fade_distance);
@@ -2825,7 +2805,7 @@ void BaseMaterial3D::_bind_methods() {
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::BOOL, "proximity_fade_enabled"), "set_proximity_fade_enabled", "is_proximity_fade_enabled");
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");
@@ -3140,8 +3120,6 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
WARN_PRINT("Godot 3.x SpatialMaterial remapped parameter not found: " + String(p_name));
return true;
}
-
- return false;
}
#endif // DISABLE_DEPRECATED
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 6c81293ee3..b3c2159e70 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -84,17 +84,6 @@ class ShaderMaterial : public Material {
HashMap<StringName, Variant> param_cache;
- struct UniformProp {
- String str;
- PropertyInfo info;
- };
-
- struct UniformPropComparator {
- bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
- return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
- }
- };
-
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -730,7 +719,7 @@ public:
void set_on_top_of_alpha();
- void set_proximity_fade(bool p_enable);
+ void set_proximity_fade_enabled(bool p_enable);
bool is_proximity_fade_enabled() const;
void set_proximity_fade_distance(float p_distance);
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index b42e65c8df..d1e300e057 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -313,11 +313,11 @@ Ref<TriangleMesh> Mesh::generate_surface_triangle_mesh(int p_surface) const {
}
}
- Ref<TriangleMesh> triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
- triangle_mesh->create(faces);
- surface_triangle_meshes.set(p_surface, triangle_mesh);
+ Ref<TriangleMesh> tr_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
+ tr_mesh->create(faces);
+ surface_triangle_meshes.set(p_surface, tr_mesh);
- return triangle_mesh;
+ return tr_mesh;
}
void Mesh::generate_debug_mesh_lines(Vector<Vector3> &r_lines) {
@@ -940,7 +940,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
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(int16_t) * 2;
+ src_offset += sizeof(int8_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];
@@ -962,7 +962,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(uint8_t) * 4; // 1 byte padding
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
@@ -973,7 +973,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(float) * 3;
}
}
@@ -988,7 +988,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
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(uint16_t) * 2;
+ src_offset += sizeof(uint8_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];
@@ -1010,7 +1010,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(uint8_t) * 4;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
@@ -1021,7 +1021,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(float) * 4;
}
}
} break;
@@ -1251,7 +1251,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
index_count = d["index_count"];
}
- Vector<uint8_t> blend_shapes;
+ Vector<uint8_t> blend_shapes_new;
if (d.has("blend_shape_data")) {
Array blend_shape_data = d["blend_shape_data"];
@@ -1263,7 +1263,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
Vector<uint8_t> shape = blend_shape_data[i];
_fix_array_compatibility(shape, old_format, new_format, vertex_count, blend_vertex_array, blend_attribute_array, blend_skin_array);
- blend_shapes.append_array(blend_vertex_array);
+ blend_shapes_new.append_array(blend_vertex_array);
}
}
@@ -1273,7 +1273,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
print_verbose("Mesh format post-conversion: " + itos(new_format));
ERR_FAIL_COND_V(!d.has("aabb"), false);
- AABB aabb = d["aabb"];
+ AABB aabb_new = d["aabb"];
Vector<AABB> bone_aabb;
if (d.has("skeleton_aabb")) {
@@ -1285,7 +1285,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
}
}
- add_surface(new_format, PrimitiveType(primitive), vertex_array, attribute_array, skin_array, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb);
+ add_surface(new_format, PrimitiveType(primitive), vertex_array, attribute_array, skin_array, vertex_count, array_index_data, index_count, aabb_new, blend_shapes_new, bone_aabb);
} else {
ERR_FAIL_V(false);
@@ -1462,9 +1462,9 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
}
}
- String name;
+ String surf_name;
if (d.has("name")) {
- name = d["name"];
+ surf_name = d["name"];
}
bool _2d = false;
@@ -1474,7 +1474,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
surface_data.push_back(surface);
surface_materials.push_back(material);
- surface_names.push_back(name);
+ surface_names.push_back(surf_name);
surface_2d.push_back(_2d);
}
@@ -1576,9 +1576,8 @@ void ArrayMesh::_recompute_aabb() {
}
}
}
-#ifndef _MSC_VER
-#warning need to add binding to add_surface using future MeshSurfaceData object
-#endif
+
+// TODO: Need to add binding to add_surface using future MeshSurfaceData object.
void ArrayMesh::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, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
_create_if_empty();
@@ -1657,17 +1656,17 @@ int ArrayMesh::get_surface_count() const {
void ArrayMesh::add_blend_shape(const StringName &p_name) {
ERR_FAIL_COND_MSG(surfaces.size(), "Can't add a shape key count if surfaces are already created.");
- StringName name = p_name;
+ StringName shape_name = p_name;
- if (blend_shapes.has(name)) {
+ if (blend_shapes.has(shape_name)) {
int count = 2;
do {
- name = String(p_name) + " " + itos(count);
+ shape_name = String(p_name) + " " + itos(count);
count++;
- } while (blend_shapes.has(name));
+ } while (blend_shapes.has(shape_name));
}
- blend_shapes.push_back(name);
+ blend_shapes.push_back(shape_name);
if (mesh.is_valid()) {
RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
@@ -1686,17 +1685,17 @@ StringName ArrayMesh::get_blend_shape_name(int p_index) const {
void ArrayMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
ERR_FAIL_INDEX(p_index, blend_shapes.size());
- StringName name = p_name;
- int found = blend_shapes.find(name);
+ StringName shape_name = p_name;
+ int found = blend_shapes.find(shape_name);
if (found != -1 && found != p_index) {
int count = 2;
do {
- name = String(p_name) + " " + itos(count);
+ shape_name = String(p_name) + " " + itos(count);
count++;
- } while (blend_shapes.find(name) != -1);
+ } while (blend_shapes.find(shape_name) != -1);
}
- blend_shapes.write[p_index] = name;
+ blend_shapes.write[p_index] = shape_name;
}
void ArrayMesh::clear_blend_shapes() {
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 2d3f9d9afc..7c78b757c7 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -33,10 +33,10 @@
#include "box_shape_3d.h"
bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name.begins_with("item/")) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ String prop_name = p_name;
+ if (prop_name.begins_with("item/")) {
+ int idx = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (!item_map.has(idx)) {
create_item(idx);
}
@@ -72,10 +72,10 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
}
bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- int idx = name.get_slicec('/', 1).to_int();
+ String prop_name = p_name;
+ int idx = prop_name.get_slicec('/', 1).to_int();
ERR_FAIL_COND_V(!item_map.has(idx), false);
- String what = name.get_slicec('/', 2);
+ String what = prop_name.get_slicec('/', 2);
if (what == "name") {
r_ret = get_item_name(idx);
@@ -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 = 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));
+ String prop_name = vformat("%s/%d/", PNAME("item"), E.key);
+ p_list->push_back(PropertyInfo(Variant::STRING, prop_name + PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, prop_name + PNAME("shapes")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
}
}
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 90ea879012..de97498674 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -527,7 +527,7 @@ void NavigationMesh::_bind_methods() {
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::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_");
@@ -590,16 +590,16 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
#ifndef DISABLE_DEPRECATED
bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name.find("/") != -1) {
+ String prop_name = p_name;
+ if (prop_name.find("/") != -1) {
// Compatibility with pre-3.5 "category/path" property names.
- name = name.replace("/", "_");
- if (name == "sample_partition_type_sample_partition_type") {
+ prop_name = prop_name.replace("/", "_");
+ if (prop_name == "sample_partition_type_sample_partition_type") {
set("sample_partition_type", p_value);
- } else if (name == "filter_filter_walkable_low_height_spans") {
+ } else if (prop_name == "filter_filter_walkable_low_height_spans") {
set("filter_walkable_low_height_spans", p_value);
} else {
- set(name, p_value);
+ set(prop_name, p_value);
}
return true;
@@ -608,16 +608,16 @@ bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
}
bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name.find("/") != -1) {
+ String prop_name = p_name;
+ if (prop_name.find("/") != -1) {
// Compatibility with pre-3.5 "category/path" property names.
- name = name.replace("/", "_");
- if (name == "sample_partition_type_sample_partition_type") {
+ prop_name = prop_name.replace("/", "_");
+ if (prop_name == "sample_partition_type_sample_partition_type") {
r_ret = get("sample_partition_type");
- } else if (name == "filter_filter_walkable_low_height_spans") {
+ } else if (prop_name == "filter_filter_walkable_low_height_spans") {
r_ret = get("filter_walkable_low_height_spans");
} else {
- r_ret = get(name);
+ r_ret = get(prop_name);
}
return true;
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index e0bedad595..1c99fa5554 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -150,15 +150,15 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
} else if (n.instance >= 0) {
//instance a scene into this node
if (n.instance & FLAG_INSTANCE_IS_PLACEHOLDER) {
- String path = props[n.instance & FLAG_MASK];
+ String scene_path = props[n.instance & FLAG_MASK];
if (disable_placeholders) {
- Ref<PackedScene> sdata = ResourceLoader::load(path, "PackedScene");
+ Ref<PackedScene> sdata = ResourceLoader::load(scene_path, "PackedScene");
ERR_FAIL_COND_V(!sdata.is_valid(), nullptr);
node = sdata->instantiate(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE);
ERR_FAIL_COND_V(!node, nullptr);
} else {
InstancePlaceholder *ip = memnew(InstancePlaceholder);
- ip->set_instance_path(path);
+ ip->set_instance_path(scene_path);
node = ip;
}
node->set_scene_instance_load_placeholder(true);
@@ -938,8 +938,8 @@ Error SceneState::pack(Node *p_scene) {
// If using scene inheritance, pack the scene it inherits from.
if (scene->get_scene_inherited_state().is_valid()) {
- String path = scene->get_scene_inherited_state()->get_path();
- Ref<PackedScene> instance = ResourceLoader::load(path);
+ String scene_path = scene->get_scene_inherited_state()->get_path();
+ Ref<PackedScene> instance = ResourceLoader::load(scene_path);
if (instance.is_valid()) {
base_scene_idx = _vm_get_variant(instance, variant_map);
}
@@ -1546,7 +1546,7 @@ Array SceneState::get_connection_binds(int p_idx) const {
return binds;
}
-bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method) {
+bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance) {
// this method cannot be const because of this
Ref<SceneState> ss = this;
@@ -1578,6 +1578,10 @@ bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p
}
}
+ if (p_no_inheritance) {
+ break;
+ }
+
ss = ss->get_base_scene_state();
} while (ss.is_valid());
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 8e1a1d29b6..c6f82ddd5e 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -176,7 +176,7 @@ public:
int get_connection_unbinds(int p_idx) const;
Array get_connection_binds(int p_idx) const;
- bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method);
+ bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance = false);
Vector<NodePath> get_editable_instances() const;
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index e51c786786..b77430c154 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -115,6 +115,7 @@ void ParticleProcessMaterial::init_shaders() {
shader_names->sub_emitter_frequency = "sub_emitter_frequency";
shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end";
+ shader_names->sub_emitter_amount_at_collision = "sub_emitter_amount_at_collision";
shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity";
shader_names->collision_friction = "collision_friction";
@@ -235,6 +236,9 @@ void ParticleProcessMaterial::_update_shader() {
if (sub_emitter_mode == SUB_EMITTER_AT_END) {
code += "uniform int sub_emitter_amount_at_end;\n";
}
+ if (sub_emitter_mode == SUB_EMITTER_AT_COLLISION) {
+ code += "uniform int sub_emitter_amount_at_collision;\n";
+ }
code += "uniform bool sub_emitter_keep_velocity;\n";
}
@@ -830,6 +834,13 @@ void ParticleProcessMaterial::_update_shader() {
code += " TRANSFORM[3].z = 0.0;\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 (collision_mode == COLLISION_RIGID) {
code += " if (COLLIDED) {\n";
code += " if (length(VELOCITY) > 3.0) {\n";
@@ -844,21 +855,6 @@ void ParticleProcessMaterial::_update_shader() {
}
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 (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";
@@ -874,7 +870,7 @@ void ParticleProcessMaterial::_update_shader() {
code += " if (DELTA >= interval_rem) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_COLLISION: {
- code += " if (COLLIDED) emit_count = 1;\n";
+ code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n";
} break;
case SUB_EMITTER_AT_END: {
code += " float unit_delta = DELTA/LIFETIME;\n";
@@ -1433,6 +1429,10 @@ void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const
p_property.usage = PROPERTY_USAGE_NONE;
}
+ if (p_property.name == "sub_emitter_amount_at_collision" && sub_emitter_mode != SUB_EMITTER_AT_COLLISION) {
+ 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;
}
@@ -1488,6 +1488,15 @@ int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const {
return sub_emitter_amount_at_end;
}
+void ParticleProcessMaterial::set_sub_emitter_amount_at_collision(int p_amount) {
+ sub_emitter_amount_at_collision = p_amount;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_collision, p_amount);
+}
+
+int ParticleProcessMaterial::get_sub_emitter_amount_at_collision() const {
+ return sub_emitter_amount_at_collision;
+}
+
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);
@@ -1640,6 +1649,9 @@ void ParticleProcessMaterial::_bind_methods() {
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_amount_at_collision"), &ParticleProcessMaterial::get_sub_emitter_amount_at_collision);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_collision", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_collision);
+
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);
@@ -1752,6 +1764,7 @@ void ParticleProcessMaterial::_bind_methods() {
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,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::INT, "sub_emitter_amount_at_collision", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_collision", "get_sub_emitter_amount_at_collision");
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_");
@@ -1859,6 +1872,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() :
set_sub_emitter_mode(SUB_EMITTER_DISABLED);
set_sub_emitter_frequency(4);
set_sub_emitter_amount_at_end(1);
+ set_sub_emitter_amount_at_collision(1);
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h
index fe4741d6e5..64d828b3e7 100644
--- a/scene/resources/particle_process_material.h
+++ b/scene/resources/particle_process_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 PARTICLE_PROCESS_MATERIAL_H
#define PARTICLE_PROCESS_MATERIAL_H
+#include "core/templates/rid.h"
+#include "scene/resources/material.h"
+
/*
TODO:
-Path following
@@ -246,6 +246,7 @@ private:
StringName sub_emitter_frequency;
StringName sub_emitter_amount_at_end;
+ StringName sub_emitter_amount_at_collision;
StringName sub_emitter_keep_velocity;
StringName collision_friction;
@@ -265,9 +266,9 @@ private:
float spread = 0.0f;
float flatness = 0.0f;
- float params_min[PARAM_MAX];
- float params_max[PARAM_MAX];
- float params[PARAM_MAX];
+ float params_min[PARAM_MAX] = {};
+ float params_max[PARAM_MAX] = {};
+ float params[PARAM_MAX] = {};
Ref<Texture2D> tex_parameters[PARAM_MAX];
Color color;
@@ -304,6 +305,7 @@ private:
SubEmitterMode sub_emitter_mode;
double sub_emitter_frequency = 0.0;
int sub_emitter_amount_at_end = 0;
+ int sub_emitter_amount_at_collision = 0;
bool sub_emitter_keep_velocity = false;
//do not save emission points here
@@ -418,6 +420,9 @@ public:
void set_sub_emitter_amount_at_end(int p_amount);
int get_sub_emitter_amount_at_end() const;
+ void set_sub_emitter_amount_at_collision(int p_amount);
+ int get_sub_emitter_amount_at_collision() const;
+
void set_sub_emitter_keep_velocity(bool p_enable);
bool get_sub_emitter_keep_velocity() const;
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 5e18671c11..2c80e234e9 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -441,9 +441,9 @@ Dictionary PolygonPathFinder::_get_data() const {
Dictionary d;
Vector<Vector2> p;
Vector<int> ind;
- Array connections;
+ Array path_connections;
p.resize(MAX(0, points.size() - 2));
- connections.resize(MAX(0, points.size() - 2));
+ path_connections.resize(MAX(0, points.size() - 2));
ind.resize(edges.size() * 2);
Vector<real_t> penalties;
penalties.resize(MAX(0, points.size() - 2));
@@ -463,7 +463,7 @@ Dictionary PolygonPathFinder::_get_data() const {
cw[idx++] = E;
}
}
- connections[i] = c;
+ path_connections[i] = c;
}
}
{
@@ -478,7 +478,7 @@ Dictionary PolygonPathFinder::_get_data() const {
d["bounds"] = bounds;
d["points"] = p;
d["penalties"] = penalties;
- d["connections"] = connections;
+ d["connections"] = path_connections;
d["segments"] = ind;
return d;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index c017c90370..e5ad590c0a 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -30,6 +30,7 @@
#include "primitive_meshes.h"
+#include "core/config/project_settings.h"
#include "core/core_string_names.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
@@ -37,6 +38,8 @@
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
+#define PADDING_REF_SIZE 1024.0
+
/**
PrimitiveMesh
*/
@@ -94,6 +97,26 @@ void PrimitiveMesh::_update() const {
}
}
+ if (add_uv2) {
+ // _create_mesh_array should populate our UV2, this is a fallback in case it doesn't.
+ // As we don't know anything about the geometry we only pad the right and bottom edge
+ // of our texture.
+ Vector<Vector2> uv = arr[RS::ARRAY_TEX_UV];
+ Vector<Vector2> uv2 = arr[RS::ARRAY_TEX_UV2];
+
+ if (uv.size() > 0 && uv2.size() == 0) {
+ Vector2 uv2_scale = get_uv2_scale();
+ uv2.resize(uv.size());
+
+ Vector2 *uv2w = uv2.ptrw();
+ for (int i = 0; i < uv.size(); i++) {
+ uv2w[i] = uv[i] * uv2_scale;
+ }
+ }
+
+ arr[RS::ARRAY_TEX_UV2] = uv2;
+ }
+
array_len = pc;
index_array_len = indices.size();
// in with the new
@@ -160,7 +183,12 @@ TypedArray<Array> PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) c
uint32_t PrimitiveMesh::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 | RS::ARRAY_FORMAT_INDEX;
+ uint32_t mesh_format = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
+ if (add_uv2) {
+ mesh_format |= RS::ARRAY_FORMAT_TEX_UV2;
+ }
+
+ return mesh_format;
}
Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {
@@ -219,9 +247,17 @@ void PrimitiveMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces);
ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces);
+ ClassDB::bind_method(D_METHOD("set_add_uv2", "add_uv2"), &PrimitiveMesh::set_add_uv2);
+ ClassDB::bind_method(D_METHOD("get_add_uv2"), &PrimitiveMesh::get_add_uv2);
+
+ ClassDB::bind_method(D_METHOD("set_uv2_padding", "uv2_padding"), &PrimitiveMesh::set_uv2_padding);
+ ClassDB::bind_method(D_METHOD("get_uv2_padding"), &PrimitiveMesh::get_uv2_padding);
+
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, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "add_uv2"), "set_add_uv2", "get_add_uv2");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_padding"), "set_uv2_padding", "get_uv2_padding");
GDVIRTUAL_BIND(_create_mesh_array);
}
@@ -263,6 +299,42 @@ bool PrimitiveMesh::get_flip_faces() const {
return flip_faces;
}
+void PrimitiveMesh::set_add_uv2(bool p_enable) {
+ add_uv2 = p_enable;
+ _update_lightmap_size();
+ _request_update();
+}
+
+void PrimitiveMesh::set_uv2_padding(float p_padding) {
+ uv2_padding = p_padding;
+ _update_lightmap_size();
+ _request_update();
+}
+
+Vector2 PrimitiveMesh::get_uv2_scale(Vector2 p_margin_scale) const {
+ Vector2 uv2_scale;
+ Vector2 lightmap_size = get_lightmap_size_hint();
+
+ // Calculate it as a margin, if no lightmap size hint is given we assume "PADDING_REF_SIZE" as our texture size.
+ uv2_scale.x = p_margin_scale.x * uv2_padding / (lightmap_size.x == 0.0 ? PADDING_REF_SIZE : lightmap_size.x);
+ uv2_scale.y = p_margin_scale.y * uv2_padding / (lightmap_size.y == 0.0 ? PADDING_REF_SIZE : lightmap_size.y);
+
+ // Inverse it to turn our margin into a scale
+ uv2_scale = Vector2(1.0, 1.0) - uv2_scale;
+
+ return uv2_scale;
+}
+
+float PrimitiveMesh::get_lightmap_texel_size() const {
+ float texel_size = GLOBAL_GET("rendering/lightmapping/primitive_meshes/texel_size");
+
+ if (texel_size <= 0.0) {
+ texel_size = 0.2;
+ }
+
+ return texel_size;
+}
+
PrimitiveMesh::PrimitiveMesh() {
mesh = RenderingServer::get_singleton()->mesh_create();
}
@@ -275,22 +347,52 @@ PrimitiveMesh::~PrimitiveMesh() {
CapsuleMesh
*/
+void CapsuleMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float radial_length = radius * Math_PI * 0.5; // circumference of 90 degree bend
+ float vertical_length = radial_length * 2 + (height - 2.0 * radius); // total vertical length
+
+ _lightmap_size_hint.x = MAX(1.0, 4.0 * radial_length / texel_size) + padding;
+ _lightmap_size_hint.y = MAX(1.0, vertical_length / texel_size) + padding;
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, radius, height, radial_segments, rings);
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ create_mesh_array(p_arr, radius, height, radial_segments, rings, _add_uv2, _uv2_padding);
}
-void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const float height, const int radial_segments, const int rings) {
+void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const float height, const int radial_segments, const int rings, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
float x, y, z, u, v, w;
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
+ // Only used if we calculate UV2
+ float radial_width = 2.0 * radius * Math_PI;
+ float radial_h = radial_width / (radial_width + p_uv2_padding);
+ float radial_length = radius * Math_PI * 0.5; // circumference of 90 degree bend
+ float vertical_length = radial_length * 2 + (height - 2.0 * radius) + p_uv2_padding; // total vertical length
+ float radial_v = radial_length / vertical_length; // v size of top and bottom section
+ float height_v = (height - 2.0 * radius) / vertical_length; // v size of height section
+
// note, this has been aligned with our collision shape but I've left the descriptions as top/middle/bottom
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -322,6 +424,9 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
normals.push_back(p.normalized());
ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * onethird));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u * radial_h, v * radial_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -361,6 +466,9 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
normals.push_back(Vector3(x, 0.0, -z));
ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, onethird + (v * onethird)));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u * radial_h, radial_v + (v * height_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -390,17 +498,20 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
y = radius * cos(0.5 * Math_PI * v);
for (i = 0; i <= radial_segments; i++) {
- float u2 = i;
- u2 /= radial_segments;
+ u = i;
+ u /= radial_segments;
- x = -sin(u2 * Math_TAU);
- z = cos(u2 * Math_TAU);
+ x = -sin(u * Math_TAU);
+ z = cos(u * Math_TAU);
Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0));
normals.push_back(p.normalized());
ADD_TANGENT(-z, 0.0, -x, 1.0)
- uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird)));
+ uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird)));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u * radial_h, radial_v + height_v + ((v - 1.0) * radial_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -422,6 +533,9 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -450,6 +564,7 @@ void CapsuleMesh::set_radius(const float p_radius) {
if (radius > height * 0.5) {
height = radius * 2.0;
}
+ _update_lightmap_size();
_request_update();
}
@@ -462,6 +577,7 @@ void CapsuleMesh::set_height(const float p_height) {
if (radius > height * 0.5) {
radius = height * 0.5;
}
+ _update_lightmap_size();
_request_update();
}
@@ -493,16 +609,53 @@ CapsuleMesh::CapsuleMesh() {}
BoxMesh
*/
+void BoxMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float width = (size.x + size.z) / texel_size;
+ float length = (size.y + size.y + MAX(size.x, size.z)) / texel_size;
+
+ _lightmap_size_hint.x = MAX(1.0, width) + 2.0 * padding;
+ _lightmap_size_hint.y = MAX(1.0, length) + 3.0 * padding;
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void BoxMesh::_create_mesh_array(Array &p_arr) const {
- BoxMesh::create_mesh_array(p_arr, size, subdivide_w, subdivide_h, subdivide_d);
+ // Note about padding, with our box each face of the box faces a different direction so we want a seam
+ // around every face. We thus add our padding to the right and bottom of each face.
+ // With 3 faces along the width and 2 along the height of the texture we need to adjust our scale
+ // accordingly.
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ BoxMesh::create_mesh_array(p_arr, size, subdivide_w, subdivide_h, subdivide_d, _add_uv2, _uv2_padding);
}
-void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int subdivide_h, int subdivide_d) {
+void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int subdivide_h, int subdivide_d, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
float x, y, z;
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
+ // Only used if we calculate UV2
+ // TODO this could be improved by changing the order depending on which side is the longest (basically the below works best if size.y is the longest)
+ float total_h = (size.x + size.z + (2.0 * p_uv2_padding));
+ float padding_h = p_uv2_padding / total_h;
+ float width_h = size.x / total_h;
+ float depth_h = size.z / total_h;
+ float total_v = (size.y + size.y + MAX(size.x, size.z) + (3.0 * p_uv2_padding));
+ float padding_v = p_uv2_padding / total_v;
+ float width_v = size.x / total_v;
+ float height_v = size.y / total_v;
+ float depth_v = size.z / total_v;
+
Vector3 start_pos = size * -0.5;
// set our bounding box
@@ -511,6 +664,7 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -525,18 +679,24 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
thisrow = point;
prevrow = 0;
for (j = 0; j <= subdivide_h + 1; j++) {
+ float v = j;
+ float v2 = v / (subdivide_w + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
x = start_pos.x;
for (i = 0; i <= subdivide_w + 1; i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
// front
points.push_back(Vector3(x, -y, -start_pos.z)); // double negative on the Z!
normals.push_back(Vector3(0.0, 0.0, 1.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, v2 * height_v));
+ }
point++;
// back
@@ -544,6 +704,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
normals.push_back(Vector3(0.0, 0.0, -1.0));
ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, height_v + padding_v + (v2 * height_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -579,18 +742,24 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_h + 1); j++) {
+ float v = j;
+ float v2 = v / (subdivide_h + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
z = start_pos.z;
for (i = 0; i <= (subdivide_d + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_d + 1.0);
u /= (3.0 * (subdivide_d + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
// right
points.push_back(Vector3(-start_pos.x, -y, -z));
normals.push_back(Vector3(1.0, 0.0, 0.0));
ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
uvs.push_back(Vector2(onethird + u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + (u2 * depth_h), v2 * height_v));
+ }
point++;
// left
@@ -598,6 +767,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
normals.push_back(Vector3(-1.0, 0.0, 0.0));
ADD_TANGENT(0.0, 0.0, 1.0, 1.0);
uvs.push_back(Vector2(u, 0.5 + v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + (u2 * depth_h), height_v + padding_v + (v2 * height_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -633,18 +805,24 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_d + 1); j++) {
+ float v = j;
+ float v2 = v / (subdivide_d + 1.0);
+ v /= (2.0 * (subdivide_d + 1.0));
+
x = start_pos.x;
for (i = 0; i <= (subdivide_w + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_d + 1.0));
// top
points.push_back(Vector3(-x, -start_pos.y, -z));
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(onethird + u, 0.5 + v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, ((height_v + padding_v) * 2.0) + (v2 * depth_v)));
+ }
point++;
// bottom
@@ -652,6 +830,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + u, 0.5 + v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + (u2 * depth_h), ((height_v + padding_v) * 2.0) + (v2 * width_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -686,6 +867,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -708,6 +892,7 @@ void BoxMesh::_bind_methods() {
void BoxMesh::set_size(const Vector3 &p_size) {
size = p_size;
+ _update_lightmap_size();
_request_update();
}
@@ -748,18 +933,58 @@ BoxMesh::BoxMesh() {}
CylinderMesh
*/
+void CylinderMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float top_circumference = top_radius * Math_PI * 2.0;
+ float bottom_circumference = bottom_radius * Math_PI * 2.0;
+
+ float _width = MAX(top_circumference, bottom_circumference) / texel_size + padding;
+ _width = MAX(_width, (((top_radius + bottom_radius) / texel_size) + padding) * 2.0); // this is extremely unlikely to be larger, will only happen if padding is larger then our diameter.
+ _lightmap_size_hint.x = MAX(1.0, _width);
+
+ float _height = ((height + (MAX(top_radius, bottom_radius) * 2.0)) / texel_size) + (2.0 * padding);
+
+ _lightmap_size_hint.y = MAX(1.0, _height);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void CylinderMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom);
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom, _add_uv2, _uv2_padding);
}
-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) {
+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, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
- float x, y, z, u, v, radius;
+ float x, y, z, u, v, radius, radius_h;
+
+ // Only used if we calculate UV2
+ float top_circumference = top_radius * Math_PI * 2.0;
+ float bottom_circumference = bottom_radius * Math_PI * 2.0;
+ float vertical_length = height + MAX(2.0 * top_radius, 2.0 * bottom_radius) + (2.0 * p_uv2_padding);
+ float height_v = height / vertical_length;
+ float padding_v = p_uv2_padding / vertical_length;
+
+ float horizonal_length = MAX(MAX(2.0 * (top_radius + bottom_radius + p_uv2_padding), top_circumference + p_uv2_padding), bottom_circumference + p_uv2_padding);
+ float center_h = 0.5 * (horizonal_length - p_uv2_padding) / horizonal_length;
+ float top_h = top_circumference / horizonal_length;
+ float bottom_h = bottom_circumference / horizonal_length;
+ float padding_h = p_uv2_padding / horizonal_length;
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -771,11 +996,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
thisrow = 0;
prevrow = 0;
+ const real_t side_normal_y = (bottom_radius - top_radius) / height;
for (j = 0; j <= (rings + 1); j++) {
v = j;
v /= (rings + 1);
radius = top_radius + ((bottom_radius - top_radius) * v);
+ radius_h = top_h + ((bottom_h - top_h) * v);
y = height * v;
y = (height * 0.5) - y;
@@ -789,9 +1016,12 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
Vector3 p = Vector3(x * radius, y, z * radius);
points.push_back(p);
- normals.push_back(Vector3(x, 0.0, z));
+ normals.push_back(Vector3(x, side_normal_y, z).normalized());
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * 0.5));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(center_h + (u - 0.5) * radius_h, v * height_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -809,6 +1039,12 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
thisrow = point;
};
+ // Adjust for buttom section, only used if we calculate UV2s
+ top_h = top_radius / horizonal_length;
+ float top_v = top_radius / vertical_length;
+ bottom_h = bottom_radius / horizonal_length;
+ float bottom_v = bottom_radius / vertical_length;
+
// add top
if (cap_top && top_radius > 0.0) {
y = height * 0.5;
@@ -818,6 +1054,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(0.25, 0.75));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h, height_v + padding_v + MAX(top_v, bottom_v)));
+ }
point++;
for (i = 0; i <= radial_segments; i++) {
@@ -835,6 +1074,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h + (x * top_h), height_v + padding_v + MAX(top_v, bottom_v) + (z * top_v)));
+ }
point++;
if (i > 0) {
@@ -854,6 +1096,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(0.75, 0.75));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h + top_h + padding_h + bottom_h, height_v + padding_v + MAX(top_v, bottom_v)));
+ }
point++;
for (i = 0; i <= radial_segments; i++) {
@@ -871,6 +1116,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h + top_h + padding_h + bottom_h + (x * bottom_h), height_v + padding_v + MAX(top_v, bottom_v) - (z * bottom_v)));
+ }
point++;
if (i > 0) {
@@ -885,6 +1133,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -918,6 +1169,7 @@ void CylinderMesh::_bind_methods() {
void CylinderMesh::set_top_radius(const float p_radius) {
top_radius = p_radius;
+ _update_lightmap_size();
_request_update();
}
@@ -927,6 +1179,7 @@ float CylinderMesh::get_top_radius() const {
void CylinderMesh::set_bottom_radius(const float p_radius) {
bottom_radius = p_radius;
+ _update_lightmap_size();
_request_update();
}
@@ -936,6 +1189,7 @@ float CylinderMesh::get_bottom_radius() const {
void CylinderMesh::set_height(const float p_height) {
height = p_height;
+ _update_lightmap_size();
_request_update();
}
@@ -985,10 +1239,26 @@ CylinderMesh::CylinderMesh() {}
PlaneMesh
*/
+void PlaneMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ _lightmap_size_hint.x = MAX(1.0, (size.x / texel_size) + padding);
+ _lightmap_size_hint.y = MAX(1.0, (size.y / texel_size) + padding);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void PlaneMesh::_create_mesh_array(Array &p_arr) const {
int i, j, prevrow, thisrow, point;
float x, z;
+ // Plane mesh can use default UV2 calculation as implemented in Primitive Mesh
+
Size2 start_pos = size * -0.5;
Vector3 normal = Vector3(0.0, 1.0, 0.0);
@@ -1078,7 +1348,7 @@ void PlaneMesh::_bind_methods() {
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", 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");
+ 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)
@@ -1087,6 +1357,7 @@ void PlaneMesh::_bind_methods() {
void PlaneMesh::set_size(const Size2 &p_size) {
size = p_size;
+ _update_lightmap_size();
_request_update();
}
@@ -1136,12 +1407,49 @@ PlaneMesh::PlaneMesh() {}
PrismMesh
*/
+void PrismMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ // left_to_right does not effect the surface area of the prism so we ignore that.
+ // TODO we could combine the two triangles and save some space but we need to re-align the uv1 and adjust the tangent.
+
+ float width = (size.x + size.z) / texel_size;
+ float length = (size.y + size.y + size.z) / texel_size;
+
+ _lightmap_size_hint.x = MAX(1.0, width) + 2.0 * padding;
+ _lightmap_size_hint.y = MAX(1.0, length) + 3.0 * padding;
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void PrismMesh::_create_mesh_array(Array &p_arr) const {
int i, j, prevrow, thisrow, point;
float x, y, z;
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
+ // Only used if we calculate UV2
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ float horizontal_total = size.x + size.z + 2.0 * _uv2_padding;
+ float width_h = size.x / horizontal_total;
+ float depth_h = size.z / horizontal_total;
+ float padding_h = _uv2_padding / horizontal_total;
+
+ float vertical_total = (size.y + size.y + size.z) + (3.0 * _uv2_padding);
+ float height_v = size.y / vertical_total;
+ float depth_v = size.z / vertical_total;
+ float padding_v = _uv2_padding / vertical_total;
+
+ // and start building
+
Vector3 start_pos = size * -0.5;
// set our bounding box
@@ -1150,6 +1458,7 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -1170,12 +1479,15 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
float offset_front = (1.0 - scale) * onethird * left_to_right;
float offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right);
+ float v = j;
+ float v2 = j / (subdivide_h + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
x = 0.0;
for (i = 0; i <= (subdivide_w + 1); i++) {
float u = i;
- float v = j;
+ float u2 = i / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
u *= scale;
@@ -1184,6 +1496,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
normals.push_back(Vector3(0.0, 0.0, 1.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(offset_front + u, v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(u2 * scale * width_h, v2 * height_v));
+ }
point++;
/* back */
@@ -1191,6 +1506,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
normals.push_back(Vector3(0.0, 0.0, -1.0));
ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + offset_back + u, v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(u2 * scale * width_h, height_v + padding_v + v2 * height_v));
+ }
point++;
if (i > 0 && j == 1) {
@@ -1245,6 +1563,10 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_h + 1); j++) {
+ float v = j;
+ float v2 = j / (subdivide_h + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
float left, right;
float scale = (y - start_pos.y) / size.y;
@@ -1254,15 +1576,17 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
z = start_pos.z;
for (i = 0; i <= (subdivide_d + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_d + 1.0);
u /= (3.0 * (subdivide_d + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
/* right */
points.push_back(Vector3(right, -y, -z));
normals.push_back(normal_right);
ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
uvs.push_back(Vector2(onethird + u, v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + u2 * depth_h, v2 * height_v));
+ }
point++;
/* left */
@@ -1270,6 +1594,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
normals.push_back(normal_left);
ADD_TANGENT(0.0, 0.0, 1.0, 1.0);
uvs.push_back(Vector2(u, 0.5 + v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + u2 * depth_h, height_v + padding_v + v2 * height_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -1305,18 +1632,24 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_d + 1); j++) {
+ float v = j;
+ float v2 = v / (subdivide_d + 1.0);
+ v /= (2.0 * (subdivide_d + 1.0));
+
x = start_pos.x;
for (i = 0; i <= (subdivide_w + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_d + 1.0));
/* bottom */
points.push_back(Vector3(x, start_pos.y, -z));
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + u, 0.5 + v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, 2.0 * (height_v + padding_v) + v2 * depth_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -1341,6 +1674,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -1376,6 +1712,7 @@ float PrismMesh::get_left_to_right() const {
void PrismMesh::set_size(const Vector3 &p_size) {
size = p_size;
+ _update_lightmap_size();
_request_update();
}
@@ -1416,22 +1753,50 @@ PrismMesh::PrismMesh() {}
SphereMesh
*/
+void SphereMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float _width = radius * Math_TAU;
+ _lightmap_size_hint.x = MAX(1.0, (_width / texel_size) + padding);
+ float _height = (is_hemisphere ? 1.0 : 0.5) * height * Math_PI; // note, with hemisphere height is our radius, while with a full sphere it is the diameter..
+ _lightmap_size_hint.y = MAX(1.0, (_height / texel_size) + padding);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void SphereMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, radius, height, radial_segments, rings, is_hemisphere);
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ create_mesh_array(p_arr, radius, height, radial_segments, rings, is_hemisphere, _add_uv2, _uv2_padding);
}
-void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int radial_segments, int rings, bool is_hemisphere) {
+void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int radial_segments, int rings, bool is_hemisphere, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
float x, y, z;
float scale = height * (is_hemisphere ? 1.0 : 0.5);
+ // Only used if we calculate UV2
+ float circumference = radius * Math_TAU;
+ float horizontal_length = circumference + p_uv2_padding;
+ float center_h = 0.5 * circumference / horizontal_length;
+
+ float height_v = scale * Math_PI / ((scale * Math_PI) + p_uv2_padding);
+
// set our bounding box
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -1469,6 +1834,10 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int
};
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ float w_h = w * 2.0 * center_h;
+ uv2s.push_back(Vector2(center_h + ((u - 0.5) * w_h), v * height_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -1490,6 +1859,9 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -1516,6 +1888,7 @@ void SphereMesh::_bind_methods() {
void SphereMesh::set_radius(const float p_radius) {
radius = p_radius;
+ _update_lightmap_size();
_request_update();
}
@@ -1525,6 +1898,7 @@ float SphereMesh::get_radius() const {
void SphereMesh::set_height(const float p_height) {
height = p_height;
+ _update_lightmap_size();
_request_update();
}
@@ -1552,6 +1926,7 @@ int SphereMesh::get_rings() const {
void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
is_hemisphere = p_is_hemisphere;
+ _update_lightmap_size();
_request_update();
}
@@ -1565,6 +1940,31 @@ SphereMesh::SphereMesh() {}
TorusMesh
*/
+void TorusMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ 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;
+
+ float _width = max_radius * Math_TAU;
+ _lightmap_size_hint.x = MAX(1.0, (_width / texel_size) + padding);
+ float _height = radius * Math_TAU;
+ _lightmap_size_hint.y = MAX(1.0, (_height / texel_size) + padding);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void TorusMesh::_create_mesh_array(Array &p_arr) const {
// set our bounding box
@@ -1572,6 +1972,7 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
@@ -1591,6 +1992,17 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
float radius = (max_radius - min_radius) * 0.5;
+ // Only used if we calculate UV2
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ float horizontal_total = max_radius * Math_TAU + _uv2_padding;
+ float max_h = max_radius * Math_TAU / horizontal_total;
+ float delta_h = (max_radius - min_radius) * Math_TAU / horizontal_total;
+
+ float height_v = radius * Math_TAU / (radius * Math_TAU + _uv2_padding);
+
for (int i = 0; i <= rings; i++) {
int prevrow = (i - 1) * (ring_segments + 1);
int thisrow = i * (ring_segments + 1);
@@ -1606,10 +2018,17 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj));
Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0);
+ float offset_h = 0.5 * (1.0 - normalj.x) * delta_h;
+ float adj_h = max_h - offset_h;
+ offset_h *= 0.5;
+
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 (_add_uv2) {
+ uv2s.push_back(Vector2(offset_h + inci * adj_h, incj * height_v));
+ }
if (i > 0 && j > 0) {
indices.push_back(thisrow + j - 1);
@@ -1627,6 +2046,9 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -1784,6 +2206,8 @@ Transform3D TubeTrailMesh::get_builtin_bind_pose(int p_index) const {
}
void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
+ // Seeing use case for TubeTrailMesh, no need to do anything more then default UV2 calculation
+
PackedVector3Array points;
PackedVector3Array normals;
PackedFloat32Array tangents;
@@ -2108,6 +2532,8 @@ Transform3D RibbonTrailMesh::get_builtin_bind_pose(int p_index) const {
}
void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const {
+ // Seeing use case of ribbon trail mesh, no need to implement special UV2 calculation
+
PackedVector3Array points;
PackedVector3Array normals;
PackedFloat32Array tangents;
@@ -2443,17 +2869,17 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
TS->shaped_text_clear(text_rid);
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, font->get_opentype_features(), language);
+ String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
+ TS->shaped_text_add_string(text_rid, txt, 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) {
- GDVIRTUAL_CALL(_structured_text_parser, st_args, text, stt);
+ GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
- stt = TS->parse_structured_text(st_parser, st_args, text);
+ stt = TS->parse_structured_text(st_parser, st_args, txt);
}
TS->shaped_text_set_bidi_override(text_rid, stt);
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 280477ebfa..06f9781b84 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -56,6 +56,9 @@ private:
Ref<Material> material;
bool flip_faces = false;
+ bool add_uv2 = false;
+ float uv2_padding = 2.0;
+
// make sure we do an update after we've finished constructing our object
mutable bool pending_request = true;
void _update() const;
@@ -70,6 +73,10 @@ protected:
void _request_update();
GDVIRTUAL0RC(Array, _create_mesh_array)
+ Vector2 get_uv2_scale(Vector2 p_margin_scale = Vector2(1.0, 1.0)) const;
+ float get_lightmap_texel_size() const;
+ virtual void _update_lightmap_size(){};
+
public:
virtual int get_surface_count() const override;
virtual int surface_get_array_len(int p_idx) const override;
@@ -98,6 +105,12 @@ public:
void set_flip_faces(bool p_enable);
bool get_flip_faces() const;
+ void set_add_uv2(bool p_enable);
+ bool get_add_uv2() const { return add_uv2; }
+
+ void set_uv2_padding(float p_padding);
+ float get_uv2_padding() const { return uv2_padding; }
+
PrimitiveMesh();
~PrimitiveMesh();
};
@@ -118,8 +131,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8);
+ static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_radius(const float p_radius);
float get_radius() const;
@@ -152,8 +167,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0);
+ static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_size(const Vector3 &p_size);
Vector3 get_size() const;
@@ -190,8 +207,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() 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, bool cap_top = true, bool cap_bottom = true);
+ 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, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_top_radius(const float p_radius);
float get_top_radius() const;
@@ -241,6 +260,8 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
void set_size(const Size2 &p_size);
Size2 get_size() const;
@@ -262,6 +283,19 @@ public:
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.
*/
@@ -279,6 +313,8 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
void set_left_to_right(const float p_left_to_right);
float get_left_to_right() const;
@@ -315,8 +351,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false);
+ static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_radius(const float p_radius);
float get_radius() const;
@@ -352,6 +390,8 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
void set_inner_radius(const float p_inner_radius);
float get_inner_radius() const;
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 0d798d2e27..85b538b1d9 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -445,7 +445,14 @@ Error ResourceLoaderText::load() {
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
path = ResourceUID::get_singleton()->get_id_path(uid);
} else {
+#ifdef TOOLS_ENABLED
+ // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
+ if (ResourceLoader::get_resource_uid(path) != uid) {
+ WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
+ }
+#else
WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
+#endif
}
}
@@ -1114,10 +1121,10 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
//go with external resources
DummyReadData dummy_read;
- VariantParser::ResourceParser rp;
- rp.ext_func = _parse_ext_resource_dummys;
- rp.sub_func = _parse_sub_resource_dummys;
- rp.userdata = &dummy_read;
+ VariantParser::ResourceParser rp_new;
+ rp_new.ext_func = _parse_ext_resource_dummys;
+ rp_new.sub_func = _parse_sub_resource_dummys;
+ rp_new.userdata = &dummy_read;
while (next_tag.name == "ext_resource") {
if (!next_tag.fields.has("path")) {
@@ -1161,7 +1168,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
dummy_read.external_resources[dr] = lindex;
dummy_read.rev_external_resources[id] = dr;
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new);
if (error) {
_printerr();
@@ -1244,7 +1251,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
String assign;
Variant value;
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
if (error) {
if (main_res && error == ERR_FILE_EOF) {
@@ -1288,7 +1295,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
return error;
}
- Ref<PackedScene> packed_scene = _parse_node_tag(rp);
+ Ref<PackedScene> packed_scene = _parse_node_tag(rp_new);
if (!packed_scene.is_valid()) {
return error;
@@ -1363,13 +1370,13 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
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;
+ VariantParser::ResourceParser rp_new;
+ rp_new.ext_func = _parse_ext_resource_dummys;
+ rp_new.sub_func = _parse_sub_resource_dummys;
+ rp_new.userdata = &dummy_read;
while (next_tag.name == "ext_resource") {
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new);
if (error) {
_printerr();
@@ -1396,7 +1403,7 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
String assign;
Variant value;
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
if (error) {
if (error == ERR_FILE_EOF) {
@@ -1444,7 +1451,7 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
String assign;
Variant value;
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
if (error) {
if (error == ERR_FILE_MISSING_DEPENDENCIES) {
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 4d566178a5..3a671edeea 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -177,7 +177,7 @@ bool Shader::is_text_shader() const {
}
bool Shader::has_parameter(const StringName &p_name) const {
- return params_cache.has("shader_parameter/" + p_name);
+ return params_cache.has(p_name);
}
void Shader::_update_shader() const {
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index d267e6520e..57be142a95 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -87,15 +87,44 @@ public:
virtual bool is_text_shader() const;
- _FORCE_INLINE_ StringName remap_uniform(const StringName &p_uniform) 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_shader_uniform_list(nullptr);
}
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_uniform);
- 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();
}
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index fe43f345d4..af84144591 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -105,6 +105,7 @@ void Shape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("collide_and_get_contacts", "local_xform", "with_shape", "shape_xform"), &Shape2D::collide_and_get_contacts);
ClassDB::bind_method(D_METHOD("collide_with_motion_and_get_contacts", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion_and_get_contacts);
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "color"), &Shape2D::draw);
+ ClassDB::bind_method(D_METHOD("get_rect"), &Shape2D::get_rect);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
}
@@ -115,7 +116,7 @@ bool Shape2D::is_collision_outline_enabled() {
return true;
}
#endif
- return GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+ return GLOBAL_GET("debug/shapes/collision/draw_2d_outlines");
}
Shape2D::Shape2D(const RID &p_rid) {
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
index 885cf0f1b8..1b7354853d 100644
--- a/scene/resources/skeleton_modification_2d.cpp
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -127,7 +127,7 @@ void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_b
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
}
#endif // TOOLS_ENABLED
@@ -230,7 +230,7 @@ void SkeletonModification2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_draw_gizmo"), &SkeletonModification2D::get_editor_draw_gizmo);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
}
SkeletonModification2D::SkeletonModification2D() {
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index d3c62e441f..6593f476f5 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -212,7 +212,7 @@ void SkeletonModification2DTwoBoneIK::_draw_editor_gizmo() {
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
}
#endif // TOOLS_ENABLED
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
index 2c0f6e779e..fa487cb061 100644
--- a/scene/resources/skeleton_modification_3d.cpp
+++ b/scene/resources/skeleton_modification_3d.cpp
@@ -142,7 +142,7 @@ void SkeletonModification3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification3D::clamp_angle);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
}
SkeletonModification3D::SkeletonModification3D() {
diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
index 3251ee4189..82dc30ec5f 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_3d_ccdik.cpp
@@ -98,7 +98,7 @@ void SkeletonModification3DCCDIK::_get_property_list(List<PropertyInfo> *p_list)
p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::INT, base_string + "ccdik_axis",
- PROPERTY_HINT_ENUM, "X Axis, Y Axis, Z Axis", PROPERTY_USAGE_DEFAULT));
+ PROPERTY_HINT_ENUM, "X Axis,Y Axis,Z Axis", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_joint_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (ccdik_data_chain[i].enable_constraint) {
diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
index 69167cb308..8ada7d0a5b 100644
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ b/scene/resources/skeleton_modification_3d_lookat.cpp
@@ -67,7 +67,7 @@ bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret
void SkeletonModification3DLookAt::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "lock_rotation_to_plane", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (lock_rotation_to_plane) {
- p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane, Y plane, Z plane", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane,Y plane,Z plane", PROPERTY_USAGE_DEFAULT));
}
p_list->push_back(PropertyInfo(Variant::VECTOR3, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
}
diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index 068c756849..56234a8a14 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -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_profile.cpp b/scene/resources/skeleton_profile.cpp
index 1367ea86dd..61a0350440 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -566,7 +566,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[14].bone_name = "LeftThumbMetacarpal";
bones.write[14].bone_parent = "LeftHand";
- bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0.707, 0.577, 0.408, -0.707, 0.577, 0.408, -0.025, 0, 0);
+ bones.write[14].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";
@@ -686,7 +686,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[33].bone_name = "RightThumbMetacarpal";
bones.write[33].bone_parent = "RightHand";
- bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, -0.707, 0.577, 0.408, 0.707, 0.577, 0.408, 0.025, 0, 0);
+ bones.write[33].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";
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index 1c04ba0cd4..9d320e0b2c 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -86,13 +86,13 @@ void Skin::reset_state() {
}
bool Skin::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name == "bind_count") {
+ String prop_name = p_name;
+ if (prop_name == "bind_count") {
set_bind_count(p_value);
return true;
- } else if (name.begins_with("bind/")) {
- int index = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("bind/")) {
+ int index = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (what == "bone") {
set_bind_bone(index, p_value);
return true;
@@ -108,13 +108,13 @@ bool Skin::_set(const StringName &p_name, const Variant &p_value) {
}
bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name == "bind_count") {
+ String prop_name = p_name;
+ if (prop_name == "bind_count") {
r_ret = get_bind_count();
return true;
- } else if (name.begins_with("bind/")) {
- int index = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("bind/")) {
+ int index = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (what == "bone") {
r_ret = get_bind_bone(index);
return true;
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index fc999d5fcb..d21f04fab8 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -34,7 +34,7 @@
#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;
@@ -147,7 +147,11 @@ float ProceduralSkyMaterial::get_sun_curve() const {
void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
use_debanding = p_use_debanding;
- RS::get_singleton()->material_set_param(_get_material(), "use_debanding", 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)]);
+ }
}
bool ProceduralSkyMaterial::get_use_debanding() const {
@@ -161,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();
@@ -169,7 +174,7 @@ 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 {
@@ -241,21 +246,24 @@ void ProceduralSkyMaterial::_bind_methods() {
}
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 : 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);
@@ -269,14 +277,6 @@ 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 bool use_debanding = true;
-
-// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
-vec3 interleaved_gradient_noise(vec2 pos) {
- const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
- float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
- return vec3(res, -res, res) / 255.0;
-}
void sky() {
float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
@@ -332,11 +332,10 @@ void sky() {
ground *= ground_energy;
COLOR = mix(ground, sky, step(0.0, EYEDIR.y));
- if (use_debanding) {
- COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
- }
}
-)");
+)",
+ i ? "render_mode use_debanding;" : ""));
+ }
}
shader_mutex.unlock();
}
@@ -546,7 +545,11 @@ float PhysicalSkyMaterial::get_energy_multiplier() const {
void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
use_debanding = p_use_debanding;
- RS::get_singleton()->material_set_param(_get_material(), "use_debanding", 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)]);
+ }
}
bool PhysicalSkyMaterial::get_use_debanding() const {
@@ -570,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();
@@ -578,7 +582,7 @@ 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 {
@@ -588,7 +592,7 @@ void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
}
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);
@@ -642,21 +646,24 @@ void PhysicalSkyMaterial::_bind_methods() {
}
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 : source_color = vec4(0.3, 0.405, 0.6, 1.0);
@@ -668,7 +675,6 @@ uniform float turbidity : hint_range(0, 1000) = 10.0;
uniform float sun_disk_scale : hint_range(0, 360) = 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 bool use_debanding = true;
uniform sampler2D night_sky : source_color, hint_default_black;
@@ -683,13 +689,6 @@ 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));
}
-// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
-vec3 interleaved_gradient_noise(vec2 pos) {
- const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
- float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
- return vec3(res, -res, res) / 255.0;
-}
-
void sky() {
if (LIGHT0_ENABLED) {
float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
@@ -737,16 +736,15 @@ void sky() {
vec3 color = Lin + L0;
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
COLOR *= exposure;
- if (use_debanding) {
- COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
- }
} else {
// There is no sun, so display night_sky and nothing else.
COLOR = texture(night_sky, SKY_COORDS).xyz;
COLOR *= exposure;
}
}
-)");
+)",
+ i ? "render_mode use_debanding;" : ""));
+ }
}
shader_mutex.unlock();
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index b517fd806b..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);
@@ -55,7 +55,7 @@ private:
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;
@@ -160,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;
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index 3533e86c3a..838566f696 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -143,10 +143,10 @@ Array SpriteFrames::_get_animations() const {
get_animation_list(&sorted_names);
sorted_names.sort_custom<StringName::AlphCompare>();
- for (const StringName &name : sorted_names) {
- const Anim &anim = animations[name];
+ for (const StringName &anim_name : sorted_names) {
+ const Anim &anim = animations[anim_name];
Dictionary d;
- d["name"] = name;
+ d["name"] = anim_name;
d["speed"] = anim.speed;
d["loop"] = anim.loop;
Array frames;
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index cd893d8c23..f379f88bed 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -43,12 +43,9 @@ float StyleBox::get_style_margin(Side p_side) const {
}
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)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret);
+ return ret;
}
void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
@@ -109,11 +106,8 @@ Point2 StyleBox::get_offset() const {
Size2 StyleBox::get_center_size() const {
Size2 ret;
- if (GDVIRTUAL_CALL(_get_center_size, ret)) {
- return ret;
- }
-
- return Size2();
+ GDVIRTUAL_CALL(_get_center_size, ret);
+ return ret;
}
Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 9829c7e86b..94967352c8 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -986,7 +986,7 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
format = 0;
}
- uint32_t nformat;
+ uint32_t nformat = 0;
LocalVector<Vertex> nvertices;
LocalVector<int> nindices;
_create_list(p_existing, p_surface, &nvertices, &nindices, nformat);
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 823d742d72..afab44834d 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -218,7 +218,48 @@ Array TextLine::get_objects() const {
}
Rect2 TextLine::get_object_rect(Variant p_key) const {
- return TS->shaped_text_get_object_rect(rid, p_key);
+ Vector2 ofs;
+
+ float length = TS->shaped_text_get_width(rid);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ } break;
+ }
+ }
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(rid);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(rid);
+ }
+
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, p_key);
+ rect.position += ofs;
+
+ return rect;
}
void TextLine::set_horizontal_alignment(HorizontalAlignment p_alignment) {
@@ -276,11 +317,7 @@ 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);
- } else {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
- }
+ return TS->shaped_text_get_size(rid);
}
float TextLine::get_line_ascent() const {
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 7e9a2591e4..59bb24c8b8 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -540,16 +540,90 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
const_cast<TextParagraph *>(this)->_shape_lines();
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]);
+
+ Vector2 ofs;
+
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ for (int i = 0; i <= p_line; i++) {
+ float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- xrect.position.y += lsize.y;
+ ofs.x = 0.f;
+ 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;
+ }
+ l_width -= h_offset;
+ }
} else {
- xrect.position.x += lsize.x;
+ ofs.y = 0.f;
+ 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;
+ }
+ l_width -= h_offset;
+ }
+ }
+ float length = TS->shaped_text_get_width(lines_rid[i]);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ break;
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ } break;
+ }
+ }
+ if (i != p_line) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = 0.f;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
+ } else {
+ ofs.y = 0.f;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
+ }
}
}
- return xrect;
+
+ Rect2 rect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
+ rect.position += ofs;
+
+ return rect;
}
Size2 TextParagraph::get_line_size(int p_line) const {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index d53dc1a8fc..a6fb359051 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -38,6 +38,7 @@
#include "scene/resources/bit_map.h"
#include "scene/resources/mesh.h"
#include "servers/camera/camera_feed.h"
+
int Texture2D::get_width() const {
int ret;
if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) {
@@ -59,20 +60,14 @@ Size2 Texture2D::get_size() const {
}
bool Texture2D::is_pixel_opaque(int p_x, int p_y) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret);
+ return ret;
}
bool Texture2D::has_alpha() const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_alpha, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_has_alpha, ret);
+ return ret;
}
void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
@@ -121,7 +116,7 @@ void Texture2D::_bind_methods() {
GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose")
GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose")
- GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
+ GDVIRTUAL_BIND(_draw_rect_region, "to_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
}
Texture2D::Texture2D() {
@@ -652,7 +647,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
Image::Format format = Image::Format(f->get_32());
if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
- //look for a PNG or WEBP file inside
+ //look for a PNG or WebP file inside
int sw = w;
int sh = h;
@@ -739,7 +734,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
}
}
- image->create(w, h, true, mipmap_images[0]->get_format(), img_data);
+ image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data);
return image;
}
@@ -765,10 +760,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
f->get_buffer(wr, data.size());
}
- Ref<Image> image;
- image.instantiate();
-
- image->create(tw, th, mipmaps - i ? true : false, format, data);
+ Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data);
return image;
}
@@ -1208,6 +1200,8 @@ Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height,
if (texture.is_valid()) {
RenderingServer::get_singleton()->texture_replace(texture, tex);
+ } else {
+ texture = tex;
}
return OK;
@@ -1285,15 +1279,15 @@ Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &
f->get_32(); // ignored (data format)
f->get_32(); //ignored
- int mipmaps = f->get_32();
+ int mipmap_count = f->get_32();
f->get_32(); //ignored
f->get_32(); //ignored
- r_mipmaps = mipmaps != 0;
+ r_mipmaps = mipmap_count != 0;
r_data.clear();
- for (int i = 0; i < (r_depth + mipmaps); i++) {
+ for (int i = 0; i < (r_depth + mipmap_count); i++) {
Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0);
ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
if (i == 0) {
@@ -1488,7 +1482,15 @@ void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) {
if (atlas == p_atlas) {
return;
}
+ // Support recursive AtlasTextures.
+ if (Ref<AtlasTexture>(atlas).is_valid()) {
+ atlas->disconnect(CoreStringNames::get_singleton()->changed, callable_mp((Resource *)this, &AtlasTexture::emit_changed));
+ }
atlas = p_atlas;
+ if (Ref<AtlasTexture>(atlas).is_valid()) {
+ atlas->connect(CoreStringNames::get_singleton()->changed, callable_mp((Resource *)this, &AtlasTexture::emit_changed));
+ }
+
emit_changed();
}
@@ -1661,7 +1663,7 @@ Ref<Image> AtlasTexture::get_image() const {
return Ref<Image>();
}
- return atlas->get_image()->get_rect(region);
+ return atlas->get_image()->get_region(region);
}
AtlasTexture::AtlasTexture() {}
@@ -2325,11 +2327,11 @@ void GradientTexture2D::_update() {
image.instantiate();
if (gradient->get_points_count() <= 1) { // No need to interpolate.
- image->create(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
+ image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
} else {
if (use_hdr) {
- image->create(width, height, false, Image::FORMAT_RGBAF);
+ image->initialize_data(width, height, false, Image::FORMAT_RGBAF);
Gradient &g = **gradient;
// `create()` isn't available for non-uint8_t data, so fill in the data manually.
for (int y = 0; y < height; y++) {
@@ -2356,7 +2358,7 @@ void GradientTexture2D::_update() {
}
}
}
- image->create(width, height, false, Image::FORMAT_RGBA8, data);
+ image->set_data(width, height, false, Image::FORMAT_RGBA8, data);
}
}
@@ -3105,7 +3107,7 @@ Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Imag
uint32_t layer_count = f->get_32(); //layer count
uint32_t type = f->get_32(); //layer count
- ERR_FAIL_COND_V(type != layered_type, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V((int)type != layered_type, ERR_INVALID_DATA);
uint32_t df = f->get_32(); //data format
mipmap_limit = int(f->get_32());
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index da4b8046a5..9a9f0ad1af 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -238,7 +238,7 @@ private:
Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
mutable Ref<BitMap> alpha_cache;
@@ -415,7 +415,7 @@ class ImageTextureLayered : public TextureLayered {
LayeredType layered_type;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int width = 0;
int height = 0;
@@ -495,7 +495,7 @@ private:
Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
int layers = 0;
@@ -587,7 +587,7 @@ class ImageTexture3D : public Texture3D {
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int width = 1;
int height = 1;
int depth = 1;
@@ -641,7 +641,7 @@ private:
Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
int d = 0;
@@ -769,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;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 3321392821..ed0d5ee688 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -40,20 +40,20 @@ bool Theme::_set(const StringName &p_name, const Variant &p_value) {
if (sname.contains("/")) {
String type = sname.get_slicec('/', 1);
String theme_type = sname.get_slicec('/', 0);
- String name = sname.get_slicec('/', 2);
+ String prop_name = sname.get_slicec('/', 2);
if (type == "icons") {
- set_icon(name, theme_type, p_value);
+ set_icon(prop_name, theme_type, p_value);
} else if (type == "styles") {
- set_stylebox(name, theme_type, p_value);
+ set_stylebox(prop_name, theme_type, p_value);
} else if (type == "fonts") {
- set_font(name, theme_type, p_value);
+ set_font(prop_name, theme_type, p_value);
} else if (type == "font_sizes") {
- set_font_size(name, theme_type, p_value);
+ set_font_size(prop_name, theme_type, p_value);
} else if (type == "colors") {
- set_color(name, theme_type, p_value);
+ set_color(prop_name, theme_type, p_value);
} else if (type == "constants") {
- set_constant(name, theme_type, p_value);
+ set_constant(prop_name, theme_type, p_value);
} else if (type == "base_type") {
set_type_variation(theme_type, p_value);
} else {
@@ -72,32 +72,32 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const {
if (sname.contains("/")) {
String type = sname.get_slicec('/', 1);
String theme_type = sname.get_slicec('/', 0);
- String name = sname.get_slicec('/', 2);
+ String prop_name = sname.get_slicec('/', 2);
if (type == "icons") {
- if (!has_icon(name, theme_type)) {
+ if (!has_icon(prop_name, theme_type)) {
r_ret = Ref<Texture2D>();
} else {
- r_ret = get_icon(name, theme_type);
+ r_ret = get_icon(prop_name, theme_type);
}
} else if (type == "styles") {
- if (!has_stylebox(name, theme_type)) {
+ if (!has_stylebox(prop_name, theme_type)) {
r_ret = Ref<StyleBox>();
} else {
- r_ret = get_stylebox(name, theme_type);
+ r_ret = get_stylebox(prop_name, theme_type);
}
} else if (type == "fonts") {
- if (!has_font(name, theme_type)) {
+ if (!has_font(prop_name, theme_type)) {
r_ret = Ref<Font>();
} else {
- r_ret = get_font(name, theme_type);
+ r_ret = get_font(prop_name, theme_type);
}
} else if (type == "font_sizes") {
- r_ret = get_font_size(name, theme_type);
+ r_ret = get_font_size(prop_name, theme_type);
} else if (type == "colors") {
- r_ret = get_color(name, theme_type);
+ r_ret = get_color(prop_name, theme_type);
} else if (type == "constants") {
- r_ret = get_constant(name, theme_type);
+ r_ret = get_constant(prop_name, theme_type);
} else if (type == "base_type") {
r_ret = get_type_variation_base(theme_type);
} else {
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 9138a82ba8..3caf6484d9 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1537,7 +1537,6 @@ Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
}
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) {
@@ -1802,11 +1801,11 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
// Get the best tile.
Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
Rect2i region = counts[terrain_set][terrain].region;
- image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
+ image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
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->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
}
Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
@@ -3780,14 +3779,14 @@ bool TileSetAtlasSource::get_use_texture_padding() const {
}
Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
- Ref<Texture2D> texture = get_texture();
- if (!texture.is_valid()) {
+ Ref<Texture2D> txt = get_texture();
+ if (!txt.is_valid()) {
return Vector2i();
}
ERR_FAIL_COND_V(texture_region_size.x <= 0 || texture_region_size.y <= 0, Vector2i());
- Size2i valid_area = texture->get_size() - margins;
+ Size2i valid_area = txt->get_size() - margins;
// Compute the number of valid tiles in the tiles atlas
Size2i grid_size = Size2i();
@@ -4603,9 +4602,7 @@ void TileSetAtlasSource::_update_padded_texture() {
return;
}
- Ref<Image> image;
- image.instantiate();
- image->create(size.x, size.y, false, src->get_format());
+ Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format());
for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
@@ -5018,7 +5015,7 @@ void TileData::add_custom_data_layer(int p_to_pos) {
void TileData::move_custom_data_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, custom_data.size());
ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
- custom_data.insert(p_to_pos, navigation[p_from_index]);
+ custom_data.insert(p_to_pos, custom_data[p_from_index]);
custom_data.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
}
@@ -5276,6 +5273,7 @@ void TileData::set_terrain_set(int p_terrain_set) {
}
if (tile_set) {
ERR_FAIL_COND(p_terrain_set >= tile_set->get_terrain_sets_count());
+ terrain = -1;
for (int i = 0; i < 16; i++) {
terrain_peering_bits[i] = -1;
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index e156679711..8f175e99a6 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -277,6 +277,9 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
+ bool operator!=(const TerrainsPattern &p_terrains_pattern) const {
+ return !operator==(p_terrains_pattern);
+ };
void set_terrain(int p_terrain);
int get_terrain() const;
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 35686b293c..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;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 262dbe28ed..b30ca3e721 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -456,11 +456,9 @@ void VisualShaderNodeCustom::update_ports() {
}
String VisualShaderNodeCustom::get_caption() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_name, ret)) {
- return ret;
- }
- return "Unnamed";
+ String ret = "Unnamed";
+ GDVIRTUAL_CALL(_get_name, ret);
+ return ret;
}
int VisualShaderNodeCustom::get_input_port_count() const {
@@ -559,11 +557,9 @@ String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, Vis
}
bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret)) {
- return ret;
- }
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret);
+ return ret;
}
void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) {
@@ -955,7 +951,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
}
bool VisualShader::is_port_types_compatible(int p_a, int p_b) const {
- return MAX(0, p_a - 4) == (MAX(0, p_b - 4));
+ return MAX(0, p_a - 5) == (MAX(0, p_b - 5));
}
void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
@@ -1148,7 +1144,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
StringBuilder global_code;
StringBuilder global_code_per_node;
HashMap<Type, StringBuilder> global_code_per_func;
- StringBuilder code;
+ StringBuilder shader_code;
HashSet<StringName> classes;
global_code += String() + "shader_type canvas_item;\n";
@@ -1189,69 +1185,69 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
input_connections.insert(to_key, E);
}
- code += "\nvoid fragment() {\n";
+ shader_code += "\nvoid fragment() {\n";
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);
+ Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, shader_code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
ERR_FAIL_COND_V(err != OK, String());
switch (node->get_output_port_type(p_port)) {
case VisualShaderNode::PORT_TYPE_SCALAR: {
- code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ");\n";
+ shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ");\n";
} break;
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
- code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n";
+ shader_code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n";
} break;
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
- code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n";
+ shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ", 0.0);\n";
+ shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ", 0.0);\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
+ shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
+ shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
} break;
default: {
- code += " COLOR.rgb = vec3(0.0);\n";
+ shader_code += " COLOR.rgb = vec3(0.0);\n";
} break;
}
- code += "}\n";
+ shader_code += "}\n";
//set code secretly
global_code += "\n\n";
String final_code = global_code;
final_code += global_code_per_node;
- final_code += code;
+ final_code += shader_code;
return final_code;
}
String VisualShader::validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const {
- String name = p_port_name;
+ String port_name = p_port_name;
- if (name.is_empty()) {
+ if (port_name.is_empty()) {
return String();
}
- while (name.length() && !is_ascii_char(name[0])) {
- name = name.substr(1, name.length() - 1);
+ while (port_name.length() && !is_ascii_char(port_name[0])) {
+ port_name = port_name.substr(1, port_name.length() - 1);
}
- if (!name.is_empty()) {
+ if (!port_name.is_empty()) {
String valid_name;
- for (int i = 0; i < name.length(); i++) {
- if (is_ascii_identifier_char(name[i])) {
- valid_name += String::chr(name[i]);
- } else if (name[i] == ' ') {
+ for (int i = 0; i < port_name.length(); i++) {
+ if (is_ascii_identifier_char(port_name[i])) {
+ valid_name += String::chr(port_name[i]);
+ } else if (port_name[i] == ' ') {
valid_name += "_";
}
}
- name = valid_name;
+ port_name = valid_name;
} else {
return String();
}
@@ -1263,7 +1259,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
if (!p_output && i == p_port_id) {
continue;
}
- if (name == p_node->get_input_port_name(i)) {
+ if (port_name == p_node->get_input_port_name(i)) {
return String();
}
}
@@ -1271,35 +1267,35 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
if (p_output && i == p_port_id) {
continue;
}
- if (name == p_node->get_output_port_name(i)) {
+ if (port_name == p_node->get_output_port_name(i)) {
return String();
}
}
- return name;
+ return port_name;
}
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);
+ String param_name = p_name; //validate name first
+ while (param_name.length() && !is_ascii_char(param_name[0])) {
+ param_name = param_name.substr(1, param_name.length() - 1);
}
- if (!name.is_empty()) {
+ if (!param_name.is_empty()) {
String valid_name;
- for (int i = 0; i < name.length(); i++) {
- if (is_ascii_identifier_char(name[i])) {
- valid_name += String::chr(name[i]);
- } else if (name[i] == ' ') {
+ for (int i = 0; i < param_name.length(); i++) {
+ if (is_ascii_identifier_char(param_name[i])) {
+ valid_name += String::chr(param_name[i]);
+ } else if (param_name[i] == ' ') {
valid_name += "_";
}
}
- name = valid_name;
+ param_name = valid_name;
}
- if (name.is_empty()) {
- name = p_parameter->get_caption();
+ if (param_name.is_empty()) {
+ param_name = p_parameter->get_caption();
}
int attempt = 1;
@@ -1312,7 +1308,7 @@ String VisualShader::validate_parameter_name(const String &p_name, const Ref<Vis
if (node == p_parameter) { //do not test on self
continue;
}
- if (node.is_valid() && node->get_parameter_name() == name) {
+ if (node.is_valid() && node->get_parameter_name() == param_name) {
exists = true;
break;
}
@@ -1325,17 +1321,17 @@ String VisualShader::validate_parameter_name(const String &p_name, const Ref<Vis
if (exists) {
//remove numbers, put new and try again
attempt++;
- while (name.length() && is_digit(name[name.length() - 1])) {
- name = name.substr(0, name.length() - 1);
+ while (param_name.length() && is_digit(param_name[param_name.length() - 1])) {
+ param_name = param_name.substr(0, param_name.length() - 1);
}
- ERR_FAIL_COND_V(name.is_empty(), String());
- name += itos(attempt);
+ ERR_FAIL_COND_V(param_name.is_empty(), String());
+ param_name += itos(attempt);
} else {
break;
}
}
- return name;
+ return param_name;
}
static const char *type_string[VisualShader::TYPE_MAX] = {
@@ -1352,12 +1348,12 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name == "mode") {
+ String prop_name = p_name;
+ if (prop_name == "mode") {
set_mode(Shader::Mode(int(p_value)));
return true;
- } else if (name.begins_with("flags/")) {
- StringName flag = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("flags/")) {
+ StringName flag = prop_name.get_slicec('/', 1);
bool enable = p_value;
if (enable) {
flags.insert(flag);
@@ -1366,18 +1362,18 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
_queue_update();
return true;
- } else if (name.begins_with("modes/")) {
- String mode = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("modes/")) {
+ String mode_name = prop_name.get_slicec('/', 1);
int value = p_value;
if (value == 0) {
- modes.erase(mode); //means it's default anyway, so don't store it
+ modes.erase(mode_name); //means it's default anyway, so don't store it
} else {
- modes[mode] = value;
+ modes[mode_name] = value;
}
_queue_update();
return true;
- } else if (name.begins_with("varyings/")) {
- String var_name = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("varyings/")) {
+ String var_name = prop_name.get_slicec('/', 1);
Varying value = Varying();
value.name = var_name;
if (value.from_string(p_value) && !varyings.has(var_name)) {
@@ -1386,8 +1382,8 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
_queue_update();
return true;
- } else if (name.begins_with("nodes/")) {
- String typestr = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("nodes/")) {
+ String typestr = prop_name.get_slicec('/', 1);
Type type = TYPE_VERTEX;
for (int i = 0; i < TYPE_MAX; i++) {
if (typestr == type_string[i]) {
@@ -1396,7 +1392,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
}
- String index = name.get_slicec('/', 2);
+ String index = prop_name.get_slicec('/', 2);
if (index == "connections") {
Vector<int> conns = p_value;
if (conns.size() % 4 == 0) {
@@ -1408,7 +1404,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
int id = index.to_int();
- String what = name.get_slicec('/', 3);
+ String what = prop_name.get_slicec('/', 3);
if (what == "node") {
add_node(type, p_value, Vector2(), id);
@@ -1434,32 +1430,32 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name == "mode") {
+ String prop_name = p_name;
+ if (prop_name == "mode") {
r_ret = get_mode();
return true;
- } else if (name.begins_with("flags/")) {
- StringName flag = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("flags/")) {
+ StringName flag = prop_name.get_slicec('/', 1);
r_ret = flags.has(flag);
return true;
- } else if (name.begins_with("modes/")) {
- String mode = name.get_slicec('/', 1);
- if (modes.has(mode)) {
- r_ret = modes[mode];
+ } else if (prop_name.begins_with("modes/")) {
+ String mode_name = prop_name.get_slicec('/', 1);
+ if (modes.has(mode_name)) {
+ r_ret = modes[mode_name];
} else {
r_ret = 0;
}
return true;
- } else if (name.begins_with("varyings/")) {
- String var_name = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("varyings/")) {
+ String var_name = prop_name.get_slicec('/', 1);
if (varyings.has(var_name)) {
r_ret = varyings[var_name].to_string();
} else {
r_ret = String();
}
return true;
- } else if (name.begins_with("nodes/")) {
- String typestr = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("nodes/")) {
+ String typestr = prop_name.get_slicec('/', 1);
Type type = TYPE_VERTEX;
for (int i = 0; i < TYPE_MAX; i++) {
if (typestr == type_string[i]) {
@@ -1468,7 +1464,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
}
- String index = name.get_slicec('/', 2);
+ String index = prop_name.get_slicec('/', 2);
if (index == "connections") {
Vector<int> conns;
for (const Connection &E : graph[type].connections) {
@@ -1483,7 +1479,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
int id = index.to_int();
- String what = name.get_slicec('/', 3);
+ String what = prop_name.get_slicec('/', 3);
if (what == "node") {
r_ret = get_node(type, id);
@@ -1509,11 +1505,10 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
void VisualShader::reset_state() {
-#ifndef _MSC_VER
-#warning everything needs to be cleared here
-#endif
+ // TODO: Everything needs to be cleared here.
emit_changed();
}
+
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
@@ -1580,12 +1575,12 @@ 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, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const {
- const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
+Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringBuilder *p_global_code_per_node, HashMap<Type, StringBuilder> *p_global_code_per_func, StringBuilder &r_code, Vector<VisualShader::DefaultTextureParam> &r_def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &p_input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &p_output_connections, int p_node, HashSet<int> &r_processed, bool p_for_preview, HashSet<StringName> &r_classes) const {
+ const Ref<VisualShaderNode> vsnode = graph[type].nodes[p_node].node;
if (vsnode->is_disabled()) {
- code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
- code += " // Node is disabled and code is not generated.\n";
+ r_code += "// " + vsnode->get_caption() + ":" + itos(p_node) + "\n";
+ r_code += " // Node is disabled and code is not generated.\n";
return OK;
}
@@ -1593,16 +1588,16 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
int input_count = vsnode->get_input_port_count();
for (int i = 0; i < input_count; i++) {
ConnectionKey ck;
- ck.node = node;
+ ck.node = p_node;
ck.port = i;
- if (input_connections.has(ck)) {
- int from_node = input_connections[ck]->get().from_node;
- if (processed.has(from_node)) {
+ if (p_input_connections.has(ck)) {
+ int from_node = p_input_connections[ck]->get().from_node;
+ if (r_processed.has(from_node)) {
continue;
}
- Error err = _write_node(type, global_code, global_code_per_node, global_code_per_func, code, def_tex_params, input_connections, output_connections, from_node, processed, for_preview, r_classes);
+ Error err = _write_node(type, p_global_code, p_global_code_per_node, p_global_code_per_func, r_code, r_def_tex_params, p_input_connections, p_output_connections, from_node, r_processed, p_for_preview, r_classes);
if (err) {
return err;
}
@@ -1611,19 +1606,19 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
// then this node
- Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
+ Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, p_node);
for (int i = 0; i < params.size(); i++) {
- def_tex_params.push_back(params[i]);
+ r_def_tex_params.push_back(params[i]);
}
Ref<VisualShaderNodeInput> input = vsnode;
- bool skip_global = input.is_valid() && for_preview;
+ bool skip_global = input.is_valid() && p_for_preview;
if (!skip_global) {
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);
+ if (p_global_code) {
+ *p_global_code += vsnode->generate_global(get_mode(), type, p_node);
}
}
@@ -1632,12 +1627,12 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
class_name = vsnode->get_script_instance()->get_script()->get_path();
}
if (!r_classes.has(class_name)) {
- if (global_code_per_node) {
- *global_code_per_node += vsnode->generate_global_per_node(get_mode(), node);
+ if (p_global_code_per_node) {
+ *p_global_code_per_node += vsnode->generate_global_per_node(get_mode(), p_node);
}
for (int i = 0; i < TYPE_MAX; i++) {
- if (global_code_per_func) {
- (*global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
+ if (p_global_code_per_func) {
+ (*p_global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), p_node);
}
}
r_classes.insert(class_name);
@@ -1645,11 +1640,11 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
}
if (!vsnode->is_code_generated()) { // just generate globals and ignore locals
- processed.insert(node);
+ r_processed.insert(p_node);
return OK;
}
- String node_name = "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
+ String node_name = "// " + vsnode->get_caption() + ":" + itos(p_node) + "\n";
String node_code;
Vector<String> input_vars;
@@ -1658,18 +1653,18 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
for (int i = 0; i < input_count; i++) {
ConnectionKey ck;
- ck.node = node;
+ ck.node = p_node;
ck.port = i;
- if (input_connections.has(ck)) {
+ if (p_input_connections.has(ck)) {
//connected to something, use that output
- int from_node = input_connections[ck]->get().from_node;
+ int from_node = p_input_connections[ck]->get().from_node;
if (graph[type].nodes[from_node].node->is_disabled()) {
continue;
}
- int from_port = input_connections[ck]->get().from_port;
+ int from_port = p_input_connections[ck]->get().from_port;
VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i);
VisualShaderNode::PortType out_type = graph[type].nodes[from_node].node->get_output_port_type(from_port);
@@ -1826,32 +1821,32 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
Variant defval = vsnode->get_input_port_default_value(i);
if (defval.get_type() == Variant::FLOAT) {
float val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " float " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
} else if (defval.get_type() == Variant::INT) {
int val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " int " + inputs[i] + " = " + itos(val) + ";\n";
} else if (defval.get_type() == Variant::BOOL) {
bool val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " bool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n";
} else if (defval.get_type() == Variant::VECTOR2) {
Vector2 val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec2 " + inputs[i] + " = " + vformat("vec2(%.5f, %.5f);\n", val.x, val.y);
} else if (defval.get_type() == Variant::VECTOR3) {
Vector3 val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
} else if (defval.get_type() == Variant::QUATERNION) {
Quaternion val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec4 " + inputs[i] + " = " + vformat("vec4(%.5f, %.5f, %.5f, %.5f);\n", val.x, val.y, val.z, val.w);
} else if (defval.get_type() == Variant::TRANSFORM3D) {
Transform3D val = defval;
val.basis.transpose();
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
Array values;
for (int j = 0; j < 3; j++) {
values.push_back(val.basis[j].x);
@@ -1903,7 +1898,7 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
if (vsnode->is_simple_decl()) { // less code to generate for some simple_decl nodes
for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
- String var_name = "n_out" + itos(node) + "p" + itos(j);
+ String var_name = "n_out" + itos(p_node) + "p" + itos(j);
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR:
outputs[i] = "float " + var_name;
@@ -1948,28 +1943,28 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
} else {
for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
- outputs[i] = "n_out" + itos(node) + "p" + itos(j);
+ outputs[i] = "n_out" + itos(p_node) + "p" + itos(j);
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR:
- code += " float " + outputs[i] + ";\n";
+ r_code += " float " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
- code += " int " + outputs[i] + ";\n";
+ r_code += " int " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D:
- code += " vec2 " + outputs[i] + ";\n";
+ r_code += " vec2 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
- code += " vec3 " + outputs[i] + ";\n";
+ r_code += " vec3 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D:
- code += " vec4 " + outputs[i] + ";\n";
+ r_code += " vec4 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
- code += " bool " + outputs[i] + ";\n";
+ r_code += " bool " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_TRANSFORM:
- code += " mat4 " + outputs[i] + ";\n";
+ r_code += " mat4 " + outputs[i] + ";\n";
break;
default:
break;
@@ -1992,73 +1987,73 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
}
}
- node_code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
+ node_code += vsnode->generate_code(get_mode(), type, p_node, inputs, outputs, p_for_preview);
if (!node_code.is_empty()) {
- code += node_name;
- code += node_code;
+ r_code += node_name;
+ r_code += node_code;
}
for (int i = 0; i < output_count; i++) {
if (expanded_output_ports[i]) {
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- String r = "n_out" + itos(node) + "p" + itos(i + 1);
- code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
+ r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
- if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- String g = "n_out" + itos(node) + "p" + itos(i + 2);
- code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
+ r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
i += 2;
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- String r = "n_out" + itos(node) + "p" + itos(i + 1);
- code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
+ r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
- if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- String g = "n_out" + itos(node) + "p" + itos(i + 2);
- code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
+ r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
- if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
- String b = "n_out" + itos(node) + "p" + itos(i + 3);
- code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
+ if (vsnode->is_output_port_connected(i + 3) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
+ String b = "n_out" + itos(p_node) + "p" + itos(i + 3);
+ r_code += " float " + b + " = n_out" + itos(p_node) + "p" + itos(i) + ".b;\n";
outputs[i + 3] = b;
}
i += 3;
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- String r = "n_out" + itos(node) + "p" + itos(i + 1);
- code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
+ r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
- if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- String g = "n_out" + itos(node) + "p" + itos(i + 2);
- code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
+ r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
- if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
- String b = "n_out" + itos(node) + "p" + itos(i + 3);
- code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
+ if (vsnode->is_output_port_connected(i + 3) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
+ String b = "n_out" + itos(p_node) + "p" + itos(i + 3);
+ r_code += " float " + b + " = n_out" + itos(p_node) + "p" + itos(i) + ".b;\n";
outputs[i + 3] = b;
}
- if (vsnode->is_output_port_connected(i + 4) || (for_preview && vsnode->get_output_port_for_preview() == (i + 4))) { // alpha-component
- String a = "n_out" + itos(node) + "p" + itos(i + 4);
- code += " float " + a + " = n_out" + itos(node) + "p" + itos(i) + ".a;\n";
+ if (vsnode->is_output_port_connected(i + 4) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 4))) { // alpha-component
+ String a = "n_out" + itos(p_node) + "p" + itos(i + 4);
+ r_code += " float " + a + " = n_out" + itos(p_node) + "p" + itos(i) + ".a;\n";
outputs[i + 4] = a;
}
@@ -2071,11 +2066,11 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
}
if (!node_code.is_empty()) {
- code += "\n";
+ r_code += "\n";
}
- code += "\n"; //
- processed.insert(node);
+ r_code += "\n"; //
+ r_processed.insert(p_node);
return OK;
}
@@ -2103,7 +2098,7 @@ void VisualShader::_update_shader() const {
StringBuilder global_code;
StringBuilder global_code_per_node;
HashMap<Type, StringBuilder> global_code_per_func;
- StringBuilder code;
+ StringBuilder shader_code;
Vector<VisualShader::DefaultTextureParam> default_tex_params;
HashSet<StringName> classes;
HashMap<int, int> insertion_pos;
@@ -2340,7 +2335,7 @@ void VisualShader::_update_shader() const {
if (shader_mode != Shader::MODE_PARTICLES) {
func_code += "\nvoid " + String(func_name[i]) + "() {\n";
}
- insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length());
+ insertion_pos.insert(i, shader_code.get_string_length() + func_code.get_string_length());
Error err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
ERR_FAIL_COND(err != OK);
@@ -2364,7 +2359,7 @@ void VisualShader::_update_shader() const {
} else {
func_code += varying_code;
func_code += "}\n";
- code += func_code;
+ shader_code += func_code;
}
}
@@ -2377,65 +2372,65 @@ void VisualShader::_update_shader() const {
bool has_process_custom = !code_map[TYPE_PROCESS_CUSTOM].is_empty();
bool has_collide = !code_map[TYPE_COLLIDE].is_empty();
- code += "void start() {\n";
+ shader_code += "void start() {\n";
if (has_start || has_start_custom) {
- code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
- code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
- code += " float __radians;\n";
- code += " vec3 __vec3_buff1;\n";
- code += " vec3 __vec3_buff2;\n";
- code += " float __scalar_buff1;\n";
- code += " float __scalar_buff2;\n";
- code += " int __scalar_ibuff;\n";
- code += " vec4 __vec4_buff;\n";
- code += " vec3 __ndiff = normalize(__diff);\n\n";
+ shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
+ shader_code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
+ shader_code += " float __radians;\n";
+ shader_code += " vec3 __vec3_buff1;\n";
+ shader_code += " vec3 __vec3_buff2;\n";
+ shader_code += " float __scalar_buff1;\n";
+ shader_code += " float __scalar_buff2;\n";
+ shader_code += " int __scalar_ibuff;\n";
+ shader_code += " vec4 __vec4_buff;\n";
+ shader_code += " vec3 __ndiff = normalize(__diff);\n\n";
}
if (has_start) {
- code += " {\n";
- code += code_map[TYPE_START].replace("\n ", "\n ");
- code += " }\n";
+ shader_code += " {\n";
+ shader_code += code_map[TYPE_START].replace("\n ", "\n ");
+ shader_code += " }\n";
if (has_start_custom) {
- code += " \n";
+ shader_code += " \n";
}
}
if (has_start_custom) {
- code += " {\n";
- code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n ");
- code += " }\n";
+ shader_code += " {\n";
+ shader_code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n ");
+ shader_code += " }\n";
}
- code += "}\n\n";
- code += "void process() {\n";
+ shader_code += "}\n\n";
+ shader_code += "void process() {\n";
if (has_process || has_process_custom || has_collide) {
- code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
- code += " vec3 __vec3_buff1;\n";
- code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
- code += " vec3 __ndiff = normalize(__diff);\n\n";
+ shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
+ shader_code += " vec3 __vec3_buff1;\n";
+ shader_code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
+ shader_code += " vec3 __ndiff = normalize(__diff);\n\n";
}
- code += " {\n";
+ shader_code += " {\n";
String tab = " ";
if (has_collide) {
- code += " if (COLLIDED) {\n\n";
- code += code_map[TYPE_COLLIDE].replace("\n ", "\n ");
+ shader_code += " if (COLLIDED) {\n\n";
+ shader_code += code_map[TYPE_COLLIDE].replace("\n ", "\n ");
if (has_process) {
- code += " } else {\n\n";
+ shader_code += " } else {\n\n";
tab += " ";
}
}
if (has_process) {
- code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab);
+ shader_code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab);
}
if (has_collide) {
- code += " }\n";
+ shader_code += " }\n";
}
- code += " }\n";
+ shader_code += " }\n";
if (has_process_custom) {
- code += " {\n\n";
- code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n ");
- code += " }\n";
+ shader_code += " {\n\n";
+ shader_code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n ");
+ shader_code += " }\n";
}
- code += "}\n\n";
+ shader_code += "}\n\n";
global_compute_code += "float __rand_from_seed(inout uint seed) {\n";
global_compute_code += " int k;\n";
@@ -2504,7 +2499,7 @@ void VisualShader::_update_shader() const {
final_code += global_compute_code;
final_code += global_code_per_node;
final_code += global_expressions;
- String tcode = code;
+ String tcode = shader_code;
for (int i = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
continue;
@@ -2763,6 +2758,9 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ 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_4D, "light_color", "LIGHT_COLOR" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_position", "LIGHT_POSITION" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_direction", "LIGHT_DIRECTION" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light_is_directional", "LIGHT_IS_DIRECTIONAL" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_energy", "LIGHT_ENERGY" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "shadow", "SHADOW_MODULATE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
@@ -3645,12 +3643,12 @@ String VisualShaderNodeOutput::get_output_port_name(int p_port) const {
bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_VERTEX) {
- String name = get_input_port_name(p_index);
- return bool(name == "Model View Matrix");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "Model View Matrix");
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
- String name = get_input_port_name(p_index);
- return bool(name == "AO" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "AO" || port_name == "Normal" || port_name == "Rim" || port_name == "Clearcoat" || port_name == "Anisotropy" || port_name == "Subsurf Scatter" || port_name == "Alpha Scissor Threshold");
}
return false;
}
@@ -3663,15 +3661,15 @@ String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::
int idx = 0;
int count = 0;
- String code;
+ String shader_code;
while (ports[idx].mode != Shader::MODE_MAX) {
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
if (!p_input_vars[count].is_empty()) {
String s = ports[idx].string;
if (s.contains(":")) {
- code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n";
+ shader_code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n";
} else {
- code += " " + s + " = " + p_input_vars[count] + ";\n";
+ shader_code += " " + s + " = " + p_input_vars[count] + ";\n";
}
}
count++;
@@ -3679,7 +3677,7 @@ String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::
idx++;
}
- return code;
+ return shader_code;
}
VisualShaderNodeOutput::VisualShaderNodeOutput() {
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 4116eaa196..5ed5f22cd0 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -90,11 +90,10 @@ public:
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) {}
@@ -157,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, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const;
+ Error _write_node(Type p_type, StringBuilder *p_global_code, StringBuilder *p_global_code_per_node, HashMap<Type, StringBuilder> *p_global_code_per_func, StringBuilder &r_code, Vector<DefaultTextureParam> &r_def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &p_input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &p_output_connections, int p_node, HashSet<int> &r_processed, bool p_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;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index de13912b75..03abac1b3e 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1642,17 +1642,20 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const
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 += " {\n";
- 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]);
+ 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;\n";
+ code += vformat(" %s = -__depth_view.z;\n", p_output_vars[0]);
+ code += " }\n";
return code;
}
VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
+ simple_decl = false;
}
////////////// Float Op
@@ -3105,9 +3108,9 @@ void VisualShaderNodeUVFunc::set_function(VisualShaderNodeUVFunc::Function p_fun
return;
}
if (p_func == FUNC_PANNING) {
- set_input_port_default_value(2, Vector2()); // offset
+ set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); // offset
} else { // FUNC_SCALING
- set_input_port_default_value(2, Vector2(0.5, 0.5)); // pivot
+ set_input_port_default_value(2, Vector2(0.5, 0.5), get_input_port_default_value(2)); // pivot
}
func = p_func;
emit_changed();
@@ -3204,6 +3207,7 @@ String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const {
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;
+ code += " {\n";
String uv;
if (p_input_vars[0].is_empty()) {
@@ -3220,17 +3224,18 @@ String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualSh
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);
+ 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);
+ 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);
}
+ code += " }\n";
return code;
}
@@ -3238,6 +3243,8 @@ 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
+
+ simple_decl = false;
}
////////////// Dot Product
@@ -7256,22 +7263,26 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
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;
+ code += " {\n";
String proximity_fade_distance = vformat("%s", p_input_vars[0]);
- code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ 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";
+ 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 += " 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]);
+ code += " __depth_world_pos.xyz /= __depth_world_pos.w;\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]);
+ code += " }\n";
return code;
}
VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() {
set_input_port_default_value(0, 1.0);
+
+ simple_decl = false;
}
////////////// Random Range
@@ -7416,11 +7427,11 @@ String VisualShaderNodeRemap::get_output_port_name(int p_port) const {
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]);
-
+ code += " {\n";
+ 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]);
+ code += " }\n";
return code;
}
@@ -7429,4 +7440,6 @@ VisualShaderNodeRemap::VisualShaderNodeRemap() {
set_input_port_default_value(2, 1.0);
set_input_port_default_value(3, 0.0);
set_input_port_default_value(4, 1.0);
+
+ simple_decl = false;
}
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
index bdfbb59fa6..f125b05a26 100644
--- a/scene/resources/visual_shader_particle_nodes.cpp
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -460,9 +460,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2>
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -481,9 +481,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3>
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -502,9 +502,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBA8);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBA8);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -1130,31 +1130,38 @@ VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() {
// VisualShaderNodeParticleOutput
String VisualShaderNodeParticleOutput::get_caption() const {
- if (shader_type == VisualShader::TYPE_START) {
- return "StartOutput";
- } else if (shader_type == VisualShader::TYPE_PROCESS) {
- return "ProcessOutput";
- } else if (shader_type == VisualShader::TYPE_COLLIDE) {
- return "CollideOutput";
- } else if (shader_type == VisualShader::TYPE_START_CUSTOM) {
- return "CustomStartOutput";
- } else if (shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
- return "CustomProcessOutput";
+ switch (shader_type) {
+ case VisualShader::TYPE_START:
+ return "StartOutput";
+ case VisualShader::TYPE_PROCESS:
+ return "ProcessOutput";
+ case VisualShader::TYPE_COLLIDE:
+ return "CollideOutput";
+ case VisualShader::TYPE_START_CUSTOM:
+ return "CustomStartOutput";
+ case VisualShader::TYPE_PROCESS_CUSTOM:
+ return "CustomProcessOutput";
+ default:
+ ERR_PRINT(vformat("Unexpected shader_type %d for VisualShaderNodeParticleOutput.", shader_type));
+ return "";
}
- return String();
}
int VisualShaderNodeParticleOutput::get_input_port_count() const {
- if (shader_type == VisualShader::TYPE_START) {
- return 8;
- } else if (shader_type == VisualShader::TYPE_COLLIDE) {
- return 5;
- } else if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
- return 6;
- } else { // TYPE_PROCESS
- return 7;
+ switch (shader_type) {
+ case VisualShader::TYPE_START:
+ return 8;
+ case VisualShader::TYPE_PROCESS:
+ return 7;
+ case VisualShader::TYPE_COLLIDE:
+ return 5;
+ case VisualShader::TYPE_START_CUSTOM:
+ case VisualShader::TYPE_PROCESS_CUSTOM:
+ return 6;
+ default:
+ ERR_PRINT(vformat("Unexpected shader_type %d for VisualShaderNodeParticleOutput.", shader_type));
+ return 0;
}
- return 0;
}
VisualShaderNodeParticleOutput::PortType VisualShaderNodeParticleOutput::get_input_port_type(int p_port) const {
@@ -1284,12 +1291,12 @@ String VisualShaderNodeParticleOutput::get_input_port_name(int p_port) const {
bool VisualShaderNodeParticleOutput::is_port_separator(int p_index) const {
if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) {
- String name = get_input_port_name(p_index);
- return bool(name == "Scale");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "Scale");
}
if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
- String name = get_input_port_name(p_index);
- return bool(name == "Velocity");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "Velocity");
}
return false;
}
@@ -1597,24 +1604,24 @@ String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualSh
flags_arr.push_back("FLAG_EMIT_CUSTOM");
}
- String flags;
+ String flags_str;
for (int i = 0; i < flags_arr.size(); i++) {
if (i > 0) {
- flags += "|";
+ flags_str += "|";
}
- flags += flags_arr[i];
+ flags_str += flags_arr[i];
}
- if (flags.is_empty()) {
- flags = "uint(0)";
+ if (flags_str.is_empty()) {
+ flags_str = "uint(0)";
}
if (!default_condition) {
code += " if (" + p_input_vars[0] + ") {\n";
}
- code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags + ");\n";
+ code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags_str + ");\n";
if (!default_condition) {
code += " }\n";