summaryrefslogtreecommitdiffstats
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/2d/tile_set.cpp6
-rw-r--r--scene/resources/animation.cpp29
-rw-r--r--scene/resources/animation.h5
-rw-r--r--scene/resources/audio_stream_wav.cpp144
-rw-r--r--scene/resources/audio_stream_wav.h23
-rw-r--r--scene/resources/material.cpp11
-rw-r--r--scene/resources/material.h1
-rw-r--r--scene/resources/particle_process_material.cpp8
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/visual_shader.h1
10 files changed, 190 insertions, 42 deletions
diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp
index 57cc4ad602..6649cb9b82 100644
--- a/scene/resources/2d/tile_set.cpp
+++ b/scene/resources/2d/tile_set.cpp
@@ -4650,7 +4650,7 @@ Ref<Texture2D> TileSetAtlasSource::get_texture() const {
void TileSetAtlasSource::set_margins(Vector2i p_margins) {
if (p_margins.x < 0 || p_margins.y < 0) {
WARN_PRINT("Atlas source margins should be positive.");
- margins = p_margins.max(Vector2i());
+ margins = p_margins.maxi(0);
} else {
margins = p_margins;
}
@@ -4666,7 +4666,7 @@ Vector2i TileSetAtlasSource::get_margins() const {
void TileSetAtlasSource::set_separation(Vector2i p_separation) {
if (p_separation.x < 0 || p_separation.y < 0) {
WARN_PRINT("Atlas source separation should be positive.");
- separation = p_separation.max(Vector2i());
+ separation = p_separation.maxi(0);
} else {
separation = p_separation;
}
@@ -4682,7 +4682,7 @@ Vector2i TileSetAtlasSource::get_separation() const {
void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) {
if (p_tile_size.x <= 0 || p_tile_size.y <= 0) {
WARN_PRINT("Atlas source tile_size should be strictly positive.");
- texture_region_size = p_tile_size.max(Vector2i(1, 1));
+ texture_region_size = p_tile_size.maxi(1);
} else {
texture_region_size = p_tile_size;
}
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index cd530f100e..8ffb629ba9 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -247,6 +247,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
vt->update_mode = UpdateMode(um);
}
+ capture_included = capture_included || (vt->update_mode == UPDATE_CAPTURE);
Vector<real_t> times = d["times"];
Array values = d["values"];
@@ -966,6 +967,28 @@ void Animation::remove_track(int p_track) {
memdelete(t);
tracks.remove_at(p_track);
emit_changed();
+ _check_capture_included();
+}
+
+void Animation::set_capture_included(bool p_capture_included) {
+ capture_included = p_capture_included;
+}
+
+bool Animation::is_capture_included() const {
+ return capture_included;
+}
+
+void Animation::_check_capture_included() {
+ capture_included = false;
+ for (int i = 0; i < tracks.size(); i++) {
+ if (tracks[i]->type == TYPE_VALUE) {
+ ValueTrack *vt = static_cast<ValueTrack *>(tracks[i]);
+ if (vt->update_mode == UPDATE_CAPTURE) {
+ capture_included = true;
+ break;
+ }
+ }
+ }
}
int Animation::get_track_count() const {
@@ -2681,6 +2704,8 @@ void Animation::value_track_set_update_mode(int p_track, UpdateMode p_mode) {
ValueTrack *vt = static_cast<ValueTrack *>(t);
vt->update_mode = p_mode;
+
+ capture_included = capture_included || (p_mode == UPDATE_CAPTURE);
emit_changed();
}
@@ -3870,9 +3895,13 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("compress", "page_size", "fps", "split_tolerance"), &Animation::compress, DEFVAL(8192), DEFVAL(120), DEFVAL(4.0));
+ ClassDB::bind_method(D_METHOD("_set_capture_included", "capture_included"), &Animation::set_capture_included);
+ ClassDB::bind_method(D_METHOD("is_capture_included"), &Animation::is_capture_included);
+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001,suffix:s"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001,suffix:s"), "set_step", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_included", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_NO_EDITOR), "_set_capture_included", "is_capture_included");
BIND_ENUM_CONSTANT(TYPE_VALUE);
BIND_ENUM_CONSTANT(TYPE_POSITION_3D);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 6005172c11..cc7bbae8a3 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -268,6 +268,8 @@ private:
double length = 1.0;
real_t step = 1.0 / 30;
LoopMode loop_mode = LOOP_NONE;
+ bool capture_included = false;
+ void _check_capture_included();
void _track_update_hash(int p_track);
@@ -392,6 +394,9 @@ public:
int add_track(TrackType p_type, int p_at_pos = -1);
void remove_track(int p_track);
+ void set_capture_included(bool p_capture_included);
+ bool is_capture_included() const;
+
int get_track_count() const;
TrackType track_get_type(int p_track) const;
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index 0185c6ef85..ba5dad088f 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -86,15 +86,15 @@ void AudioStreamPlaybackWAV::seek(double p_time) {
offset = uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS;
}
-template <typename Depth, bool is_stereo, bool is_ima_adpcm>
-void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm) {
+template <typename Depth, bool is_stereo, bool is_ima_adpcm, bool is_qoa>
+void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa) {
// this function will be compiled branchless by any decent compiler
- int32_t final, final_r, next, next_r;
+ int32_t final = 0, final_r = 0, next = 0, next_r = 0;
while (p_amount) {
p_amount--;
int64_t pos = p_offset >> MIX_FRAC_BITS;
- if (is_stereo && !is_ima_adpcm) {
+ if (is_stereo && !is_ima_adpcm && !is_qoa) {
pos <<= 1;
}
@@ -175,32 +175,77 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst,
}
} else {
- final = p_src[pos];
- if (is_stereo) {
- final_r = p_src[pos + 1];
- }
+ if (is_qoa) {
+ if (pos != p_qoa->cache_pos) { // Prevents triple decoding on lower mix rates.
+ for (int i = 0; i < 2; i++) {
+ // Sign operations prevent triple decoding on backward loops, maxing prevents pop.
+ uint32_t interp_pos = MIN(pos + (i * sign) + (sign < 0), p_qoa->desc->samples - 1);
+ uint32_t new_data_ofs = 8 + interp_pos / QOA_FRAME_LEN * p_qoa->frame_len;
+
+ if (p_qoa->data_ofs != new_data_ofs) {
+ p_qoa->data_ofs = new_data_ofs;
+ const uint8_t *src_ptr = (const uint8_t *)base->data;
+ src_ptr += p_qoa->data_ofs + AudioStreamWAV::DATA_PAD;
+ qoa_decode_frame(src_ptr, p_qoa->frame_len, p_qoa->desc, p_qoa->dec, &p_qoa->dec_len);
+ }
- if constexpr (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */
- final <<= 8;
+ uint32_t dec_idx = (interp_pos % QOA_FRAME_LEN) * p_qoa->desc->channels;
+
+ if ((sign > 0 && i == 0) || (sign < 0 && i == 1)) {
+ final = p_qoa->dec[dec_idx];
+ p_qoa->cache[0] = final;
+ if (is_stereo) {
+ final_r = p_qoa->dec[dec_idx + 1];
+ p_qoa->cache_r[0] = final_r;
+ }
+ } else {
+ next = p_qoa->dec[dec_idx];
+ p_qoa->cache[1] = next;
+ if (is_stereo) {
+ next_r = p_qoa->dec[dec_idx + 1];
+ p_qoa->cache_r[1] = next_r;
+ }
+ }
+ }
+ p_qoa->cache_pos = pos;
+ } else {
+ final = p_qoa->cache[0];
+ if (is_stereo) {
+ final_r = p_qoa->cache_r[0];
+ }
+
+ next = p_qoa->cache[1];
+ if (is_stereo) {
+ next_r = p_qoa->cache_r[1];
+ }
+ }
+ } else {
+ final = p_src[pos];
if (is_stereo) {
- final_r <<= 8;
+ final_r = p_src[pos + 1];
}
- }
- if (is_stereo) {
- next = p_src[pos + 2];
- next_r = p_src[pos + 3];
- } else {
- next = p_src[pos + 1];
- }
+ if constexpr (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */
+ final <<= 8;
+ if (is_stereo) {
+ final_r <<= 8;
+ }
+ }
- if constexpr (sizeof(Depth) == 1) {
- next <<= 8;
if (is_stereo) {
- next_r <<= 8;
+ next = p_src[pos + 2];
+ next_r = p_src[pos + 3];
+ } else {
+ next = p_src[pos + 1];
}
- }
+ if constexpr (sizeof(Depth) == 1) {
+ next <<= 8;
+ if (is_stereo) {
+ next_r <<= 8;
+ }
+ }
+ }
int32_t frac = int64_t(p_offset & MIX_FRAC_MASK);
final = final + ((next - final) * frac >> MIX_FRAC_BITS);
@@ -240,6 +285,9 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_
case AudioStreamWAV::FORMAT_IMA_ADPCM:
len *= 2;
break;
+ case AudioStreamWAV::FORMAT_QOA:
+ len = qoa.desc->samples * qoa.desc->channels;
+ break;
}
if (base->stereo) {
@@ -368,27 +416,34 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_
switch (base->format) {
case AudioStreamWAV::FORMAT_8_BITS: {
if (is_stereo) {
- do_resample<int8_t, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
+ do_resample<int8_t, true, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
} else {
- do_resample<int8_t, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
+ do_resample<int8_t, false, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
}
} break;
case AudioStreamWAV::FORMAT_16_BITS: {
if (is_stereo) {
- do_resample<int16_t, true, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm);
+ do_resample<int16_t, true, false, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
} else {
- do_resample<int16_t, false, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm);
+ do_resample<int16_t, false, false, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
}
} break;
case AudioStreamWAV::FORMAT_IMA_ADPCM: {
if (is_stereo) {
- do_resample<int8_t, true, true>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
+ do_resample<int8_t, true, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
} else {
- do_resample<int8_t, false, true>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm);
+ do_resample<int8_t, false, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
}
} break;
+ case AudioStreamWAV::FORMAT_QOA: {
+ if (is_stereo) {
+ do_resample<uint8_t, true, false, true>((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
+ } else {
+ do_resample<uint8_t, false, false, true>((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
+ }
+ } break;
}
dst_buff += target;
@@ -412,6 +467,16 @@ void AudioStreamPlaybackWAV::tag_used_streams() {
AudioStreamPlaybackWAV::AudioStreamPlaybackWAV() {}
+AudioStreamPlaybackWAV::~AudioStreamPlaybackWAV() {
+ if (qoa.desc) {
+ memfree(qoa.desc);
+ }
+
+ if (qoa.dec) {
+ memfree(qoa.dec);
+ }
+}
+
/////////////////////
void AudioStreamWAV::set_format(Format p_format) {
@@ -475,6 +540,10 @@ double AudioStreamWAV::get_length() const {
case AudioStreamWAV::FORMAT_IMA_ADPCM:
len *= 2;
break;
+ case AudioStreamWAV::FORMAT_QOA:
+ qoa_desc desc = { 0, 0, 0, { { { 0 }, { 0 } } } };
+ qoa_decode_header((uint8_t *)data + DATA_PAD, QOA_MIN_FILESIZE, &desc);
+ len = desc.samples * desc.channels;
}
if (stereo) {
@@ -526,8 +595,8 @@ Vector<uint8_t> AudioStreamWAV::get_data() const {
}
Error AudioStreamWAV::save_to_wav(const String &p_path) {
- if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
- WARN_PRINT("Saving IMA_ADPC samples are not supported yet");
+ if (format == AudioStreamWAV::FORMAT_IMA_ADPCM || format == AudioStreamWAV::FORMAT_QOA) {
+ WARN_PRINT("Saving IMA_ADPCM and QOA samples is not supported yet");
return ERR_UNAVAILABLE;
}
@@ -548,6 +617,7 @@ Error AudioStreamWAV::save_to_wav(const String &p_path) {
byte_pr_sample = 1;
break;
case AudioStreamWAV::FORMAT_16_BITS:
+ case AudioStreamWAV::FORMAT_QOA:
byte_pr_sample = 2;
break;
case AudioStreamWAV::FORMAT_IMA_ADPCM:
@@ -590,6 +660,7 @@ Error AudioStreamWAV::save_to_wav(const String &p_path) {
}
break;
case AudioStreamWAV::FORMAT_16_BITS:
+ case AudioStreamWAV::FORMAT_QOA:
for (unsigned int i = 0; i < data_bytes / 2; i++) {
uint16_t data_point = decode_uint16(&read_data[i * 2]);
file->store_16(data_point);
@@ -607,6 +678,16 @@ Ref<AudioStreamPlayback> AudioStreamWAV::instantiate_playback() {
Ref<AudioStreamPlaybackWAV> sample;
sample.instantiate();
sample->base = Ref<AudioStreamWAV>(this);
+
+ if (format == AudioStreamWAV::FORMAT_QOA) {
+ sample->qoa.desc = (qoa_desc *)memalloc(sizeof(qoa_desc));
+ qoa_decode_header((uint8_t *)data + DATA_PAD, QOA_MIN_FILESIZE, sample->qoa.desc);
+ sample->qoa.frame_len = qoa_max_frame_size(sample->qoa.desc);
+ int samples_len = (sample->qoa.desc->samples > QOA_FRAME_LEN ? QOA_FRAME_LEN : sample->qoa.desc->samples);
+ int alloc_len = sample->qoa.desc->channels * samples_len * sizeof(int16_t);
+ sample->qoa.dec = (int16_t *)memalloc(alloc_len);
+ }
+
return sample;
}
@@ -639,7 +720,7 @@ void AudioStreamWAV::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_to_wav", "path"), &AudioStreamWAV::save_to_wav);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_data", "get_data");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM,QOA"), "set_format", "get_format");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "Disabled,Forward,Ping-Pong,Backward"), "set_loop_mode", "get_loop_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_begin"), "set_loop_begin", "get_loop_begin");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_end"), "set_loop_end", "get_loop_end");
@@ -649,6 +730,7 @@ void AudioStreamWAV::_bind_methods() {
BIND_ENUM_CONSTANT(FORMAT_8_BITS);
BIND_ENUM_CONSTANT(FORMAT_16_BITS);
BIND_ENUM_CONSTANT(FORMAT_IMA_ADPCM);
+ BIND_ENUM_CONSTANT(FORMAT_QOA);
BIND_ENUM_CONSTANT(LOOP_DISABLED);
BIND_ENUM_CONSTANT(LOOP_FORWARD);
diff --git a/scene/resources/audio_stream_wav.h b/scene/resources/audio_stream_wav.h
index 959d1ceca0..146142d8a4 100644
--- a/scene/resources/audio_stream_wav.h
+++ b/scene/resources/audio_stream_wav.h
@@ -31,7 +31,11 @@
#ifndef AUDIO_STREAM_WAV_H
#define AUDIO_STREAM_WAV_H
+#define QOA_IMPLEMENTATION
+#define QOA_NO_STDIO
+
#include "servers/audio/audio_stream.h"
+#include "thirdparty/misc/qoa.h"
class AudioStreamWAV;
@@ -54,14 +58,25 @@ class AudioStreamPlaybackWAV : public AudioStreamPlayback {
int32_t window_ofs = 0;
} ima_adpcm[2];
+ struct QOA_State {
+ qoa_desc *desc = nullptr;
+ uint32_t data_ofs = 0;
+ uint32_t frame_len = 0;
+ int16_t *dec = nullptr;
+ uint32_t dec_len = 0;
+ int64_t cache_pos = -1;
+ int16_t cache[2] = { 0, 0 };
+ int16_t cache_r[2] = { 0, 0 };
+ } qoa;
+
int64_t offset = 0;
int sign = 1;
bool active = false;
friend class AudioStreamWAV;
Ref<AudioStreamWAV> base;
- template <typename Depth, bool is_stereo, bool is_ima_adpcm>
- void do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm);
+ template <typename Depth, bool is_stereo, bool is_ima_adpcm, bool is_qoa>
+ void do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa);
public:
virtual void start(double p_from_pos = 0.0) override;
@@ -78,6 +93,7 @@ public:
virtual void tag_used_streams() override;
AudioStreamPlaybackWAV();
+ ~AudioStreamPlaybackWAV();
};
class AudioStreamWAV : public AudioStream {
@@ -88,7 +104,8 @@ public:
enum Format {
FORMAT_8_BITS,
FORMAT_16_BITS,
- FORMAT_IMA_ADPCM
+ FORMAT_IMA_ADPCM,
+ FORMAT_QOA,
};
// Keep the ResourceImporterWAV `edit/loop_mode` enum hint in sync with these options.
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index b381096df8..15b40e776c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -688,6 +688,9 @@ void BaseMaterial3D::_update_shader() {
case BLEND_MODE_MUL:
code += "blend_mul";
break;
+ case BLEND_MODE_PREMULT_ALPHA:
+ code += "blend_premul_alpha";
+ break;
case BLEND_MODE_MAX:
break; // Internal value, skip.
}
@@ -1819,6 +1822,11 @@ void fragment() {)";
vec3 detail = mix(ALBEDO.rgb, ALBEDO.rgb * detail_tex.rgb, detail_tex.a);
)";
} break;
+ case BLEND_MODE_PREMULT_ALPHA: {
+ // This is unlikely to ever be used for detail textures, and in order for it to function in the editor, another bit must be used in MaterialKey,
+ // but there are only 5 bits left, so I'm going to leave this disabled unless it's actually requested.
+ //code += "\tvec3 detail = (1.0-detail_tex.a)*ALBEDO.rgb+detail_tex.rgb;\n";
+ } break;
case BLEND_MODE_MAX:
break; // Internal value, skip.
}
@@ -3040,7 +3048,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply"), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply,Premultiplied Alpha"), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
@@ -3269,6 +3277,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
+ BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_OFF);
BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 073403f71e..ecf79c581b 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -219,6 +219,7 @@ public:
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
+ BLEND_MODE_PREMULT_ALPHA,
BLEND_MODE_MAX
};
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index 685625ab72..0b65b33240 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -634,7 +634,7 @@ void ParticleProcessMaterial::_update_shader() {
if (emission_shape == EMISSION_SHAPE_RING) {
code += " \n";
code += " float ring_spawn_angle = rand_from_seed(alt_seed) * 2.0 * pi;\n";
- code += " float ring_random_radius = rand_from_seed(alt_seed) * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius;\n";
+ code += " float ring_random_radius = sqrt(rand_from_seed(alt_seed) * (emission_ring_radius - emission_ring_inner_radius * emission_ring_inner_radius) + emission_ring_inner_radius * emission_ring_inner_radius);\n";
code += " vec3 axis = emission_ring_axis == vec3(0.0) ? vec3(0.0, 0.0, 1.0) : normalize(emission_ring_axis);\n";
code += " vec3 ortho_axis = vec3(0.0);\n";
code += " if (abs(axis) == vec3(1.0, 0.0, 0.0)) {\n";
@@ -1136,9 +1136,9 @@ void ParticleProcessMaterial::_update_shader() {
code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n";
} break;
case SUB_EMITTER_AT_END: {
- code += " float unit_delta = DELTA/LIFETIME;\n";
- code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter
- code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n";
+ code += " if ((CUSTOM.y / CUSTOM.w * LIFETIME) > (LIFETIME - DELTA)) {\n";
+ code += " emit_count = sub_emitter_amount_at_end;\n";
+ code += " }\n";
} break;
default: {
}
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 6f1aa5c850..4b51f6c471 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -4928,6 +4928,10 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad
return code;
}
+bool VisualShaderNodeExpression::is_output_port_expandable(int p_port) const {
+ return false;
+}
+
void VisualShaderNodeExpression::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_expression", "expression"), &VisualShaderNodeExpression::set_expression);
ClassDB::bind_method(D_METHOD("get_expression"), &VisualShaderNodeExpression::get_expression);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index d7270f3ac6..d32e2465b9 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -878,6 +878,7 @@ public:
String get_expression() const;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+ virtual bool is_output_port_expandable(int p_port) const override;
VisualShaderNodeExpression();
};