Merge pull request #69568 from timothyqiu/3.x-cherrypicks

Cherry-picks for the 3.x branch (future 3.6) - 8th batch
This commit is contained in:
Rémi Verschelde 2022-12-04 15:18:36 +01:00 committed by GitHub
commit 6a99678bc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 245 additions and 88 deletions

1
.gitignore vendored
View file

@ -154,6 +154,7 @@ gmon.out
# Jetbrains IDEs
.idea/
.fleet/
# Kate
*.kate-swp

View file

@ -88,7 +88,11 @@ public:
num_items++;
return id;
}
#ifdef DEV_ENABLED
return -1;
#else
ERR_FAIL_V_MSG(0, "BVH request_item error.");
#endif
}
};

View file

@ -353,6 +353,7 @@
<method name="sort">
<description>
Sorts the array.
[b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/wiki/Sorting_algorithm#Stability]stable[/url]. This means that values considered equal may have their order changed when using [method sort].
[b]Note:[/b] Strings are sorted in alphabetical order (as opposed to natural order). This may lead to unexpected behavior when sorting an array of strings ending with a sequence of numbers. Consider the following example:
[codeblock]
var strings = ["string1", "string2", "string10", "string11"]
@ -367,7 +368,8 @@
<description>
Sorts the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return either [code]true[/code] or [code]false[/code].
For two elements [code]a[/code] and [code]b[/code], if the given method returns [code]true[/code], element [code]b[/code] will be after element [code]a[/code] in the array.
[b]Note:[/b] You cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior.
[b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/wiki/Sorting_algorithm#Stability]stable[/url]. This means that values considered equal may have their order changed when using [method sort_custom].
[b]Note:[/b] You cannot randomize the return value as the heapsort algorithm expects a deterministic result. Randomizing the return value will result in unexpected behavior.
[codeblock]
class MyCustomSorter:
static func sort_ascending(a, b):

View file

@ -15,6 +15,7 @@
print("Hello from the Godot Editor!")
[/codeblock]
[b]Note:[/b] The script is run in the Editor context, which means the output is visible in the console window started with the Editor (stdout) instead of the usual Godot [b]Output[/b] dock.
[b]Note:[/b] EditorScript is reference counted, meaning it is destroyed when nothing references it. This can cause errors during asynchronous operations if there are no references to the script.
</description>
<tutorials>
</tutorials>

View file

@ -37,85 +37,135 @@
#include <errno.h>
static int get_message_size(uint8_t message) {
switch (message & 0xF0) {
case 0x80: // note off
case 0x90: // note on
case 0xA0: // aftertouch
case 0xB0: // continuous controller
case 0xE0: // pitch bend
case 0xF2: // song position pointer
return 3;
MIDIDriverALSAMidi::MessageCategory MIDIDriverALSAMidi::msg_category(uint8_t msg_part) {
if (msg_part >= 0xf8) {
return MessageCategory::RealTime;
} else if (msg_part >= 0xf0) {
// System Exclusive begin/end are specified as System Common Category messages,
// but we separate them here and give them their own categories as their
// behaviour is significantly different.
if (msg_part == 0xf0) {
return MessageCategory::SysExBegin;
} else if (msg_part == 0xf7) {
return MessageCategory::SysExEnd;
}
return MessageCategory::SystemCommon;
} else if (msg_part >= 0x80) {
return MessageCategory::Voice;
}
return MessageCategory::Data;
}
case 0xC0: // patch change
case 0xD0: // channel pressure
case 0xF1: // time code quarter frame
case 0xF3: // song select
size_t MIDIDriverALSAMidi::msg_expected_data(uint8_t status_byte) {
if (msg_category(status_byte) == MessageCategory::Voice) {
// Voice messages have a channel number in the status byte, mask it out.
status_byte &= 0xf0;
}
switch (status_byte) {
case 0x80: // Note Off
case 0x90: // Note On
case 0xA0: // Polyphonic Key Pressure (Aftertouch)
case 0xB0: // Control Change (CC)
case 0xE0: // Pitch Bend Change
case 0xF2: // Song Position Pointer
return 2;
case 0xF0: // SysEx start
case 0xF4: // reserved
case 0xF5: // reserved
case 0xF6: // tune request
case 0xF7: // SysEx end
case 0xF8: // timing clock
case 0xF9: // reserved
case 0xFA: // start
case 0xFB: // continue
case 0xFC: // stop
case 0xFD: // reserved
case 0xFE: // active sensing
case 0xFF: // reset
case 0xC0: // Program Change
case 0xD0: // Channel Pressure (Aftertouch)
case 0xF1: // MIDI Time Code Quarter Frame
case 0xF3: // Song Select
return 1;
}
return 256;
return 0;
}
void MIDIDriverALSAMidi::InputConnection::parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver,
uint64_t timestamp) {
switch (msg_category(byte)) {
case MessageCategory::RealTime:
// Real-Time messages are single byte messages that can
// occur at any point.
// We pass them straight through.
driver.receive_input_packet(timestamp, &byte, 1);
break;
case MessageCategory::Data:
// We don't currently forward System Exclusive messages so skip their data.
// Collect any expected data for other message types.
if (!skipping_sys_ex && expected_data > received_data) {
buffer[received_data + 1] = byte;
received_data++;
// Forward a complete message and reset relevant state.
if (received_data == expected_data) {
driver.receive_input_packet(timestamp, buffer, received_data + 1);
received_data = 0;
if (msg_category(buffer[0]) != MessageCategory::Voice) {
// Voice Category messages can be sent with "running status".
// This means they don't resend the status byte until it changes.
// For other categories, we reset expected data, to require a new status byte.
expected_data = 0;
}
}
}
break;
case MessageCategory::SysExBegin:
buffer[0] = byte;
skipping_sys_ex = true;
break;
case MessageCategory::SysExEnd:
expected_data = 0;
skipping_sys_ex = false;
break;
case MessageCategory::Voice:
case MessageCategory::SystemCommon:
buffer[0] = byte;
received_data = 0;
expected_data = msg_expected_data(byte);
skipping_sys_ex = false;
if (expected_data == 0) {
driver.receive_input_packet(timestamp, &byte, 1);
}
break;
}
}
int MIDIDriverALSAMidi::InputConnection::read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp) {
int ret;
do {
uint8_t byte = 0;
ret = snd_rawmidi_read(rawmidi_ptr, &byte, 1);
if (ret < 0) {
if (ret != -EAGAIN) {
ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret)));
}
} else {
parse_byte(byte, driver, timestamp);
}
} while (ret > 0);
return ret;
}
void MIDIDriverALSAMidi::thread_func(void *p_udata) {
MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata;
uint64_t timestamp = 0;
uint8_t buffer[256];
int expected_size = 255;
int bytes = 0;
while (!md->exit_thread.is_set()) {
int ret;
md->lock();
for (int i = 0; i < md->connected_inputs.size(); i++) {
snd_rawmidi_t *midi_in = md->connected_inputs[i];
do {
uint8_t byte = 0;
ret = snd_rawmidi_read(midi_in, &byte, 1);
if (ret < 0) {
if (ret != -EAGAIN) {
ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret)));
}
} else {
if (byte & 0x80) {
// Flush previous packet if there is any
if (bytes) {
md->receive_input_packet(timestamp, buffer, bytes);
bytes = 0;
}
expected_size = get_message_size(byte);
// After a SysEx start, all bytes are data until a SysEx end, so
// we're going to end the command at the SES, and let the common
// driver ignore the following data bytes.
}
InputConnection *connections = md->connected_inputs.ptrw();
size_t connection_count = md->connected_inputs.size();
if (bytes < 256) {
buffer[bytes++] = byte;
// If we know the size of the current packet receive it if it reached the expected size
if (bytes >= expected_size) {
md->receive_input_packet(timestamp, buffer, bytes);
bytes = 0;
}
}
}
} while (ret > 0);
for (size_t i = 0; i < connection_count; i++) {
connections[i].read_in(*md, timestamp);
}
md->unlock();
@ -139,7 +189,7 @@ Error MIDIDriverALSAMidi::open() {
snd_rawmidi_t *midi_in;
int ret = snd_rawmidi_open(&midi_in, nullptr, name, SND_RAWMIDI_NONBLOCK);
if (ret >= 0) {
connected_inputs.insert(i++, midi_in);
connected_inputs.insert(i++, InputConnection(midi_in));
}
}
@ -160,7 +210,7 @@ void MIDIDriverALSAMidi::close() {
thread.wait_to_finish();
for (int i = 0; i < connected_inputs.size(); i++) {
snd_rawmidi_t *midi_in = connected_inputs[i];
snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
snd_rawmidi_close(midi_in);
}
connected_inputs.clear();
@ -179,7 +229,7 @@ PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
lock();
for (int i = 0; i < connected_inputs.size(); i++) {
snd_rawmidi_t *midi_in = connected_inputs[i];
snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
snd_rawmidi_info_t *info;
snd_rawmidi_info_malloc(&info);

View file

@ -46,12 +46,48 @@ class MIDIDriverALSAMidi : public MIDIDriver {
Thread thread;
Mutex mutex;
Vector<snd_rawmidi_t *> connected_inputs;
class InputConnection {
public:
InputConnection() = default;
InputConnection(snd_rawmidi_t *midi_in) :
rawmidi_ptr{ midi_in } {}
// Read in and parse available data, forwarding any complete messages through the driver.
int read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp);
snd_rawmidi_t *rawmidi_ptr = nullptr;
private:
static const size_t MSG_BUFFER_SIZE = 3;
uint8_t buffer[MSG_BUFFER_SIZE] = { 0 };
size_t expected_data = 0;
size_t received_data = 0;
bool skipping_sys_ex = false;
void parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver, uint64_t timestamp);
};
Vector<InputConnection> connected_inputs;
SafeFlag exit_thread;
static void thread_func(void *p_udata);
enum class MessageCategory {
Data,
Voice,
SysExBegin,
SystemCommon, // excluding System Exclusive Begin/End
SysExEnd,
RealTime,
};
// If the passed byte is a status byte, return the associated message category,
// else return MessageCategory::Data.
static MessageCategory msg_category(uint8_t msg_part);
// Return the number of data bytes expected for the provided status byte.
static size_t msg_expected_data(uint8_t status_byte);
void lock() const;
void unlock() const;

View file

@ -51,6 +51,7 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource == RES()) {
assign_button->set_icon(Ref<Texture>());
assign_button->set_text(TTR("[empty]"));
assign_button->set_tooltip("");
} else {
assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
@ -58,14 +59,15 @@ void EditorResourcePicker::_update_resource() {
assign_button->set_text(edited_resource->get_name());
} else if (edited_resource->get_path().is_resource_file()) {
assign_button->set_text(edited_resource->get_path().get_file());
assign_button->set_tooltip(edited_resource->get_path());
} else {
assign_button->set_text(edited_resource->get_class());
}
String resource_path;
if (edited_resource->get_path().is_resource_file()) {
assign_button->set_tooltip(edited_resource->get_path());
resource_path = edited_resource->get_path() + "\n";
}
assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class());
// Preview will override the above, so called at the end.
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
@ -520,6 +522,8 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, Set<String> *
p_vector->insert("Texture");
} else if (base == "ShaderMaterial") {
p_vector->insert("Shader");
} else if (base == "Texture") {
p_vector->insert("Image");
}
}
}
@ -638,18 +642,35 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
String at = E->get().strip_edges();
if (at == "SpatialMaterial" && ClassDB::is_parent_class(dropped_resource->get_class(), "Texture")) {
Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
// Use existing resource if possible and only replace its data.
Ref<SpatialMaterial> mat = edited_resource;
if (mat.is_null()) {
mat.instance();
}
mat->set_texture(SpatialMaterial::TextureParam::TEXTURE_ALBEDO, dropped_resource);
dropped_resource = mat;
break;
}
if (at == "ShaderMaterial" && ClassDB::is_parent_class(dropped_resource->get_class(), "Shader")) {
Ref<ShaderMaterial> mat = memnew(ShaderMaterial);
Ref<ShaderMaterial> mat = edited_resource;
if (mat.is_null()) {
mat.instance();
}
mat->set_shader(dropped_resource);
dropped_resource = mat;
break;
}
if (at == "Texture" && ClassDB::is_parent_class(dropped_resource->get_class(), "Image")) {
Ref<ImageTexture> texture = edited_resource;
if (texture.is_null()) {
texture.instance();
}
texture->create_from_image(dropped_resource);
dropped_resource = texture;
break;
}
}
}

View file

@ -104,9 +104,10 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
file->get_buffer((uint8_t *)&riff, 4); //RIFF
if (riff[0] != 'R' || riff[1] != 'I' || riff[2] != 'F' || riff[3] != 'F') {
uint64_t length = file->get_len();
file->close();
memdelete(file);
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("Not a WAV file. File should start with 'RIFF', but found '%s', in file of size %d bytes", riff, length));
}
/* GET FILESIZE */
@ -114,14 +115,15 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
/* CHECK WAVE */
char wave[4];
file->get_buffer((uint8_t *)&wave, 4); //RIFF
char wave[5];
wave[4] = 0;
file->get_buffer((uint8_t *)&wave, 4); //WAVE
if (wave[0] != 'W' || wave[1] != 'A' || wave[2] != 'V' || wave[3] != 'E') {
uint64_t length = file->get_len();
file->close();
memdelete(file);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header).");
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("Not a WAV file. Header should contain 'WAVE', but found '%s', in file of size %d bytes", wave, length));
}
// Let users override potential loop points from the WAV.

View file

@ -208,6 +208,8 @@
<members>
<member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[ ]">
</member>
<member name="create_animations" type="bool" setter="set_create_animations" getter="get_create_animations" default="true">
</member>
<member name="glb_data" type="PoolByteArray" setter="set_glb_data" getter="get_glb_data" default="PoolByteArray( )">
</member>
<member name="json" type="Dictionary" setter="set_json" getter="get_json" default="{}">

View file

@ -81,6 +81,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skeletons", "skeletons"), &GLTFState::set_skeletons);
ClassDB::bind_method(D_METHOD("get_skeleton_to_node"), &GLTFState::get_skeleton_to_node);
ClassDB::bind_method(D_METHOD("set_skeleton_to_node", "skeleton_to_node"), &GLTFState::set_skeleton_to_node);
ClassDB::bind_method(D_METHOD("get_create_animations"), &GLTFState::get_create_animations);
ClassDB::bind_method(D_METHOD("set_create_animations", "create_animations"), &GLTFState::set_create_animations);
ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node);
@ -108,6 +110,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_animation_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_animation_names", "get_unique_animation_names"); // Set<String>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>>
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // Map<GLTFSkeletonIndex,
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
}
@ -295,6 +298,14 @@ void GLTFState::set_skeleton_to_node(Dictionary p_skeleton_to_node) {
GLTFTemplateConvert::set_from_dict(skeleton_to_node, p_skeleton_to_node);
}
bool GLTFState::get_create_animations() {
return create_animations;
}
void GLTFState::set_create_animations(bool p_create_animations) {
create_animations = p_create_animations;
}
Array GLTFState::get_animations() {
return GLTFTemplateConvert::to_array(animations);
}

View file

@ -59,6 +59,7 @@ class GLTFState : public Resource {
bool use_khr_texture_transform = false;
bool use_legacy_names = false;
uint32_t compress_flags = 0;
bool create_animations = true;
Vector<Ref<GLTFNode>> nodes;
Vector<Vector<uint8_t>> buffers;
@ -166,6 +167,9 @@ public:
Dictionary get_skeleton_to_node();
void set_skeleton_to_node(Dictionary p_skeleton_to_node);
bool get_create_animations();
void set_create_animations(bool p_create_animations);
Array get_animations();
void set_animations(Array p_animations);

View file

@ -67,6 +67,7 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
r_state->use_legacy_names =
p_flags & EditorSceneImporter::IMPORT_USE_LEGACY_NAMES;
r_state->compress_flags = p_compress_flags;
r_state->set_create_animations(p_flags & EditorSceneImporter::IMPORT_ANIMATION);
Ref<GLTFDocument> gltf_document;
gltf_document.instance();
@ -84,7 +85,7 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
gltf_document->_generate_scene_node(r_state, root, root, r_state->root_nodes[root_i]);
}
gltf_document->_process_mesh_instances(r_state, root);
if (r_state->animations.size()) {
if (r_state->get_create_animations() && r_state->animations.size()) {
AnimationPlayer *ap = memnew(AnimationPlayer);
root->add_child(ap);
ap->set_owner(root);

View file

@ -100,7 +100,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
uint32_t width = p_header.image_width;
uint32_t height = p_header.image_height;
tga_origin_e origin = static_cast<tga_origin_e>((p_header.image_descriptor & TGA_ORIGIN_MASK) >> TGA_ORIGIN_SHIFT);
uint8_t alpha_bits = p_header.image_descriptor & TGA_IMAGE_DESCRIPTOR_ALPHA_MASK;
uint32_t x_start;
int32_t x_step;
uint32_t x_end;
@ -184,6 +184,27 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
y += y_step;
}
}
} else if (p_header.pixel_depth == 16) {
while (y != y_end) {
while (x != x_end) {
if (i + 1 >= p_input_size) {
return ERR_PARSE_ERROR;
}
// Always stored as RGBA5551
uint8_t r = (p_buffer[i + 1] & 0x7c) << 1;
uint8_t g = ((p_buffer[i + 1] & 0x03) << 6) | ((p_buffer[i + 0] & 0xe0) >> 2);
uint8_t b = (p_buffer[i + 0] & 0x1f) << 3;
uint8_t a = (p_buffer[i + 1] & 0x80) ? 0xff : 0;
TGA_PUT_PIXEL(r, g, b, alpha_bits ? a : 0xff);
x += x_step;
i += 2;
}
x = x_start;
y += y_step;
}
} else if (p_header.pixel_depth == 24) {
while (y != y_end) {
while (x != x_end) {
@ -286,7 +307,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
err = FAILED;
}
if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) {
if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 16 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) {
err = FAILED;
}

View file

@ -36,6 +36,8 @@
/**
@author SaracenOne
*/
#define TGA_IMAGE_DESCRIPTOR_ALPHA_MASK 0xf
class ImageLoaderTGA : public ImageFormatLoader {
enum tga_type_e {
TGA_TYPE_NO_DATA = 0,

View file

@ -126,11 +126,10 @@ def configure(env):
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"])
env.Append(CCFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Oz"])
env.Append(CPPDEFINES=["NDEBUG"])
env.Append(CCFLAGS=["-ftree-vectorize"])
elif env["target"] == "debug":
env.Append(LINKFLAGS=["-O0"])
env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"])

View file

@ -54,10 +54,10 @@ def configure(env):
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
env.Append(CCFLAGS=[opt, "-ftree-vectorize", "-fomit-frame-pointer"])
env.Append(CCFLAGS=[opt])
env.Append(LINKFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
elif env["target"] == "debug":

View file

@ -43,9 +43,9 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"])
env.Prepend(CCFLAGS=["-O3"])
elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Prepend(CCFLAGS=["-Os"])
if env["arch"] != "arm64":
env.Prepend(CCFLAGS=["-msse2"])

View file

@ -1337,7 +1337,6 @@ float AnimationPlayer::get_current_animation_length() const {
void AnimationPlayer::_animation_changed() {
clear_caches();
emit_signal("caches_cleared");
if (is_playing()) {
playback.seeked = true; //need to restart stuff, like audio
}
@ -1376,6 +1375,8 @@ void AnimationPlayer::clear_caches() {
cache_update_size = 0;
cache_update_prop_size = 0;
cache_update_bezier_size = 0;
emit_signal("caches_cleared");
}
void AnimationPlayer::set_active(bool p_active) {

View file

@ -713,7 +713,6 @@ void AnimationTree::_clear_caches() {
memdelete(track_cache[*K]);
}
playing_caches.clear();
track_cache.clear();
cache_valid = false;
}