Merge pull request #87514 from YuriSizov/4.1-cherrypicks
Cherry-picks for the 4.1 branch (future 4.1.4) - 1st batch
This commit is contained in:
commit
b915d7d9f2
|
@ -15,3 +15,39 @@
|
|||
|
||||
# Style: clang-format: Disable AllowShortIfStatementsOnASingleLine
|
||||
e956e80c1fa1cc8aefcb1533e5acf5cf3c8ffdd9
|
||||
|
||||
# One Copyright Update to rule them all
|
||||
d95794ec8a7c362b06a9cf080e2554ef77adb667
|
||||
|
||||
# Update copyright statements to 2022
|
||||
fe52458154c64fb1b741df4f7bd10106395f7cbd
|
||||
|
||||
# Update copyright statements to 2021
|
||||
b5334d14f7a471f94bcbd64d5bae2ad853d0b7f1
|
||||
|
||||
# Update copyright statements to 2020
|
||||
a7f49ac9a107820a62677ee3fb49d38982a25165
|
||||
|
||||
# Update copyright statements to 2019
|
||||
b16c309f82c77d606472c3c721a1857e323a09e7
|
||||
|
||||
# Update copyright statements to 2018
|
||||
b50a9114b105dafafdda8248a38653bca314a6f3
|
||||
|
||||
# Welcome in 2017, dear changelog reader!
|
||||
c7bc44d5ad9aae4902280012f7654e2318cd910e
|
||||
|
||||
# Update copyright to 2016 in headers
|
||||
5be9ff7b6715a661e85f99b108f96340de7ef435
|
||||
|
||||
# Updated copyright year in all headers
|
||||
fdaa2920eb21fff3320a17e9239e04dfadecdb00
|
||||
|
||||
# Add missing copyright headers and fix formatting
|
||||
e4213e66b2dd8f5a87d8cf5015ac83ba3143279d
|
||||
|
||||
# Use HTTPS URL for Godot's website in the headers
|
||||
bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
|
||||
|
||||
# Add "Godot Engine contributors" copyright line
|
||||
df61dc4b2bd54a5a40c515493c76f5a458e5b541
|
||||
|
|
|
@ -139,10 +139,9 @@ doc_classes/* @godotengine/documentation
|
|||
|
||||
/platform/android/ @godotengine/android
|
||||
/platform/ios/ @godotengine/ios
|
||||
/platform/javascript/ @godotengine/html5
|
||||
/platform/linuxbsd/ @godotengine/linux-bsd
|
||||
/platform/macos/ @godotengine/macos
|
||||
/platform/uwp/ @godotengine/uwp
|
||||
/platform/web/ @godotengine/web
|
||||
/platform/windows/ @godotengine/windows
|
||||
|
||||
# Scene
|
||||
|
|
|
@ -150,7 +150,7 @@ jobs:
|
|||
run: |
|
||||
${{ matrix.bin }} --version
|
||||
${{ matrix.bin }} --help
|
||||
${{ matrix.bin }} --test --headless
|
||||
${{ matrix.bin }} --headless --test --force-colors
|
||||
|
||||
# Check class reference
|
||||
- name: Check for class reference updates
|
||||
|
|
|
@ -72,4 +72,4 @@ jobs:
|
|||
run: |
|
||||
${{ matrix.bin }} --version
|
||||
${{ matrix.bin }} --help
|
||||
${{ matrix.bin }} --test
|
||||
${{ matrix.bin }} --test --force-colors
|
||||
|
|
|
@ -7,7 +7,7 @@ env:
|
|||
# Used for the cache key. Add version suffix to force clean build.
|
||||
GODOT_BASE_BRANCH: '4.1'
|
||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no
|
||||
EM_VERSION: 3.1.45
|
||||
EM_VERSION: 3.1.39
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
|
||||
concurrency:
|
||||
|
|
|
@ -75,4 +75,4 @@ jobs:
|
|||
run: |
|
||||
${{ matrix.bin }} --version
|
||||
${{ matrix.bin }} --help
|
||||
${{ matrix.bin }} --test
|
||||
${{ matrix.bin }} --test --force-colors
|
||||
|
|
|
@ -132,23 +132,9 @@ cppcheck-cppcheck-build-dir/
|
|||
*.pydevproject
|
||||
*.launch
|
||||
|
||||
# Gcov and Lcov code coverage
|
||||
*.gcno
|
||||
# GCOV code coverage
|
||||
*.gcda
|
||||
*.gcov.html
|
||||
*.func.html
|
||||
*.func-sort-c.html
|
||||
*index-sort-f.html
|
||||
*index-sort-l.html
|
||||
*index.html
|
||||
godot.info
|
||||
amber.png
|
||||
emerald.png
|
||||
glass.png
|
||||
ruby.png
|
||||
snow.png
|
||||
updown.png
|
||||
gcov.css
|
||||
*.gcno
|
||||
|
||||
# Geany
|
||||
*.geany
|
||||
|
|
|
@ -1060,7 +1060,8 @@ void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
|
|||
return;
|
||||
}
|
||||
|
||||
JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value);
|
||||
JoyAxisRange range;
|
||||
JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value, range);
|
||||
|
||||
if (map.type == TYPE_BUTTON) {
|
||||
bool pressed = map.value > 0.5;
|
||||
|
@ -1100,7 +1101,7 @@ void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
|
|||
if (map.type == TYPE_AXIS) {
|
||||
JoyAxis axis = JoyAxis(map.index);
|
||||
float value = map.value;
|
||||
if (axis == JoyAxis::TRIGGER_LEFT || axis == JoyAxis::TRIGGER_RIGHT) {
|
||||
if (range == FULL_AXIS && (axis == JoyAxis::TRIGGER_LEFT || axis == JoyAxis::TRIGGER_RIGHT)) {
|
||||
// Convert to a value between 0.0f and 1.0f.
|
||||
value = 0.5f + value / 2.0f;
|
||||
}
|
||||
|
@ -1206,7 +1207,7 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping,
|
|||
return event;
|
||||
}
|
||||
|
||||
Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value) {
|
||||
Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range) {
|
||||
JoyEvent event;
|
||||
|
||||
for (int i = 0; i < mapping.bindings.size(); i++) {
|
||||
|
@ -1252,6 +1253,7 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, J
|
|||
case TYPE_AXIS:
|
||||
event.index = (int)binding.output.axis.axis;
|
||||
event.value = value;
|
||||
r_range = binding.output.axis.range;
|
||||
if (binding.output.axis.range != binding.input.axis.range) {
|
||||
switch (binding.output.axis.range) {
|
||||
case POSITIVE_HALF_AXIS:
|
||||
|
|
|
@ -219,7 +219,7 @@ private:
|
|||
Vector<JoyDeviceMapping> map_db;
|
||||
|
||||
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button);
|
||||
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value);
|
||||
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range);
|
||||
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]);
|
||||
JoyButton _get_output_button(String output);
|
||||
JoyAxis _get_output_axis(String output);
|
||||
|
|
|
@ -1619,8 +1619,10 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
|
|||
encode_uint32(datalen, buf);
|
||||
buf += 4;
|
||||
const uint8_t *r = data.ptr();
|
||||
memcpy(buf, &r[0], datalen * datasize);
|
||||
buf += datalen * datasize;
|
||||
if (r) {
|
||||
memcpy(buf, &r[0], datalen * datasize);
|
||||
buf += datalen * datasize;
|
||||
}
|
||||
}
|
||||
|
||||
r_len += 4 + datalen * datasize;
|
||||
|
|
|
@ -917,7 +917,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
|
|||
}
|
||||
|
||||
// Fallback to p_path if new_path does not exist.
|
||||
if (!FileAccess::exists(new_path)) {
|
||||
if (!FileAccess::exists(new_path + ".import") && !FileAccess::exists(new_path)) {
|
||||
WARN_PRINT(vformat("Translation remap '%s' does not exist. Falling back to '%s'.", new_path, p_path));
|
||||
new_path = p_path;
|
||||
}
|
||||
|
|
|
@ -81,35 +81,27 @@ template <class T, class... P>
|
|||
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
|
||||
struct Data {
|
||||
T *instance;
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t object_id;
|
||||
#endif
|
||||
void (T::*method)(P...);
|
||||
} data;
|
||||
|
||||
public:
|
||||
virtual ObjectID get_object() const {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
|
||||
return ObjectID();
|
||||
}
|
||||
#endif
|
||||
return data.instance->get_instance_id();
|
||||
}
|
||||
|
||||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
|
||||
#endif
|
||||
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
|
||||
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
|
||||
}
|
||||
|
||||
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
|
||||
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
|
||||
data.instance = p_instance;
|
||||
#ifdef DEBUG_ENABLED
|
||||
data.object_id = p_instance->get_instance_id();
|
||||
#endif
|
||||
data.method = p_method;
|
||||
_setup((uint32_t *)&data, sizeof(Data));
|
||||
}
|
||||
|
@ -135,36 +127,28 @@ template <class T, class R, class... P>
|
|||
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
|
||||
struct Data {
|
||||
T *instance;
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t object_id;
|
||||
#endif
|
||||
R(T::*method)
|
||||
(P...);
|
||||
} data;
|
||||
|
||||
public:
|
||||
virtual ObjectID get_object() const {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
|
||||
return ObjectID();
|
||||
}
|
||||
#endif
|
||||
return data.instance->get_instance_id();
|
||||
}
|
||||
|
||||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
|
||||
#endif
|
||||
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
|
||||
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
|
||||
}
|
||||
|
||||
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
|
||||
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
|
||||
data.instance = p_instance;
|
||||
#ifdef DEBUG_ENABLED
|
||||
data.object_id = p_instance->get_instance_id();
|
||||
#endif
|
||||
data.method = p_method;
|
||||
_setup((uint32_t *)&data, sizeof(Data));
|
||||
}
|
||||
|
@ -190,36 +174,28 @@ template <class T, class R, class... P>
|
|||
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
|
||||
struct Data {
|
||||
T *instance;
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t object_id;
|
||||
#endif
|
||||
R(T::*method)
|
||||
(P...) const;
|
||||
} data;
|
||||
|
||||
public:
|
||||
virtual ObjectID get_object() const override {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
|
||||
return ObjectID();
|
||||
}
|
||||
#endif
|
||||
return data.instance->get_instance_id();
|
||||
}
|
||||
|
||||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
|
||||
#endif
|
||||
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
|
||||
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
|
||||
}
|
||||
|
||||
CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) {
|
||||
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
|
||||
data.instance = p_instance;
|
||||
#ifdef DEBUG_ENABLED
|
||||
data.object_id = p_instance->get_instance_id();
|
||||
#endif
|
||||
data.method = p_method;
|
||||
_setup((uint32_t *)&data, sizeof(Data));
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "core/object/class_db.h"
|
||||
#include "core/object/script_language.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DEV_ENABLED
|
||||
// Includes sanity checks to ensure that a queue set as a thread singleton override
|
||||
// is only ever called from the thread it was set for.
|
||||
|
@ -93,7 +95,7 @@ Error CallQueue::push_callablep(const Callable &p_callable, const Variant **p_ar
|
|||
|
||||
if ((page_bytes[pages_used - 1] + room_needed) > uint32_t(PAGE_SIZE_BYTES)) {
|
||||
if (pages_used == max_pages) {
|
||||
ERR_PRINT("Failed method: " + p_callable + ". Message queue out of memory. " + error_text);
|
||||
fprintf(stderr, "Failed method: %s. Message queue out of memory. %s\n", String(p_callable).utf8().get_data(), error_text.utf8().get_data());
|
||||
statistics();
|
||||
UNLOCK_MUTEX;
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
|
@ -144,7 +146,7 @@ Error CallQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant
|
|||
if (ObjectDB::get_instance(p_id)) {
|
||||
type = ObjectDB::get_instance(p_id)->get_class();
|
||||
}
|
||||
ERR_PRINT("Failed set: " + type + ":" + p_prop + " target ID: " + itos(p_id) + ". Message queue out of memory. " + error_text);
|
||||
fprintf(stderr, "Failed set: %s: %s target ID: %s. Message queue out of memory. %s\n", type.utf8().get_data(), String(p_prop).utf8().get_data(), itos(p_id).utf8().get_data(), error_text.utf8().get_data());
|
||||
statistics();
|
||||
|
||||
UNLOCK_MUTEX;
|
||||
|
@ -181,7 +183,7 @@ Error CallQueue::push_notification(ObjectID p_id, int p_notification) {
|
|||
|
||||
if ((page_bytes[pages_used - 1] + room_needed) > uint32_t(PAGE_SIZE_BYTES)) {
|
||||
if (pages_used == max_pages) {
|
||||
ERR_PRINT("Failed notification: " + itos(p_notification) + " target ID: " + itos(p_id) + ". Message queue out of memory. " + error_text);
|
||||
fprintf(stderr, "Failed notification: %s target ID: %s. Message queue out of memory. %s\n", itos(p_notification).utf8().get_data(), itos(p_id).utf8().get_data(), error_text.utf8().get_data());
|
||||
statistics();
|
||||
UNLOCK_MUTEX;
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
|
|
|
@ -520,11 +520,11 @@ String TranslationServer::get_country_name(const String &p_country) const {
|
|||
void TranslationServer::set_locale(const String &p_locale) {
|
||||
locale = standardize_locale(p_locale);
|
||||
|
||||
ResourceLoader::reload_translation_remaps();
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
|
||||
}
|
||||
|
||||
ResourceLoader::reload_translation_remaps();
|
||||
}
|
||||
|
||||
String TranslationServer::get_locale() const {
|
||||
|
@ -816,10 +816,11 @@ bool TranslationServer::is_pseudolocalization_enabled() const {
|
|||
void TranslationServer::set_pseudolocalization_enabled(bool p_enabled) {
|
||||
pseudolocalization_enabled = p_enabled;
|
||||
|
||||
ResourceLoader::reload_translation_remaps();
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
|
||||
}
|
||||
ResourceLoader::reload_translation_remaps();
|
||||
}
|
||||
|
||||
void TranslationServer::set_editor_pseudolocalization(bool p_enabled) {
|
||||
|
@ -836,10 +837,11 @@ void TranslationServer::reload_pseudolocalization() {
|
|||
pseudolocalization_suffix = GLOBAL_GET("internationalization/pseudolocalization/suffix");
|
||||
pseudolocalization_skip_placeholders_enabled = GLOBAL_GET("internationalization/pseudolocalization/skip_placeholders");
|
||||
|
||||
ResourceLoader::reload_translation_remaps();
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
|
||||
}
|
||||
ResourceLoader::reload_translation_remaps();
|
||||
}
|
||||
|
||||
StringName TranslationServer::pseudolocalize(const StringName &p_message) const {
|
||||
|
|
|
@ -305,7 +305,11 @@ void String::copy_from(const char *p_cstr) {
|
|||
char32_t *dst = this->ptrw();
|
||||
|
||||
for (size_t i = 0; i <= len; i++) {
|
||||
#if CHAR_MIN == 0
|
||||
uint8_t c = p_cstr[i];
|
||||
#else
|
||||
uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]);
|
||||
#endif
|
||||
if (c == 0 && i < len) {
|
||||
print_unicode_error("NUL character", true);
|
||||
dst[i] = _replacement_char;
|
||||
|
@ -338,7 +342,11 @@ void String::copy_from(const char *p_cstr, const int p_clip_to) {
|
|||
char32_t *dst = this->ptrw();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
#if CHAR_MIN == 0
|
||||
uint8_t c = p_cstr[i];
|
||||
#else
|
||||
uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]);
|
||||
#endif
|
||||
if (c == 0) {
|
||||
print_unicode_error("NUL character", true);
|
||||
dst[i] = _replacement_char;
|
||||
|
@ -544,7 +552,11 @@ String &String::operator+=(const char *p_str) {
|
|||
char32_t *dst = ptrw() + lhs_len;
|
||||
|
||||
for (size_t i = 0; i <= rhs_len; i++) {
|
||||
#if CHAR_MIN == 0
|
||||
uint8_t c = p_str[i];
|
||||
#else
|
||||
uint8_t c = p_str[i] >= 0 ? p_str[i] : uint8_t(256 + p_str[i]);
|
||||
#endif
|
||||
if (c == 0 && i < rhs_len) {
|
||||
print_unicode_error("NUL character", true);
|
||||
dst[i] = _replacement_char;
|
||||
|
@ -1814,7 +1826,11 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
|
|||
int skip = 0;
|
||||
uint8_t c_start = 0;
|
||||
while (ptrtmp != ptrtmp_limit && *ptrtmp) {
|
||||
#if CHAR_MIN == 0
|
||||
uint8_t c = *ptrtmp;
|
||||
#else
|
||||
uint8_t c = *ptrtmp >= 0 ? *ptrtmp : uint8_t(256 + *ptrtmp);
|
||||
#endif
|
||||
|
||||
if (skip == 0) {
|
||||
if (p_skip_cr && c == '\r') {
|
||||
|
@ -1882,7 +1898,11 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
|
|||
int skip = 0;
|
||||
uint32_t unichar = 0;
|
||||
while (cstr_size) {
|
||||
#if CHAR_MIN == 0
|
||||
uint8_t c = *p_utf8;
|
||||
#else
|
||||
uint8_t c = *p_utf8 >= 0 ? *p_utf8 : uint8_t(256 + *p_utf8);
|
||||
#endif
|
||||
|
||||
if (skip == 0) {
|
||||
if (p_skip_cr && c == '\r') {
|
||||
|
@ -3945,24 +3965,22 @@ bool String::is_absolute_path() const {
|
|||
}
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool _is_valid_identifier_bit(int p_index, char32_t p_char) {
|
||||
if (p_index == 0 && is_digit(p_char)) {
|
||||
return false; // No start with number plz.
|
||||
}
|
||||
return is_ascii_identifier_char(p_char);
|
||||
}
|
||||
|
||||
String String::validate_identifier() const {
|
||||
if (is_empty()) {
|
||||
return "_"; // Empty string is not a valid identifier;
|
||||
}
|
||||
|
||||
String result = *this;
|
||||
String result;
|
||||
if (is_digit(operator[](0))) {
|
||||
result = "_" + *this;
|
||||
} else {
|
||||
result = *this;
|
||||
}
|
||||
|
||||
int len = result.length();
|
||||
char32_t *buffer = result.ptrw();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!_is_valid_identifier_bit(i, buffer[i])) {
|
||||
if (!is_ascii_identifier_char(buffer[i])) {
|
||||
buffer[i] = '_';
|
||||
}
|
||||
}
|
||||
|
@ -3977,10 +3995,14 @@ bool String::is_valid_identifier() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (is_digit(operator[](0))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char32_t *str = &operator[](0);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!_is_valid_identifier_bit(i, str[i])) {
|
||||
if (!is_ascii_identifier_char(str[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,10 @@ private:
|
|||
}
|
||||
|
||||
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
|
||||
if (unlikely(p_elements == 0)) {
|
||||
*out = 0;
|
||||
return true;
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
size_t o;
|
||||
size_t p;
|
||||
|
@ -101,13 +105,12 @@ private:
|
|||
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
|
||||
return false; // No longer allocated here.
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
// Speed is more important than correctness here, do the operations unchecked
|
||||
// and hope for the best.
|
||||
*out = _get_alloc_size(p_elements);
|
||||
return true;
|
||||
#endif
|
||||
return *out;
|
||||
}
|
||||
|
||||
void _unref(void *p_data);
|
||||
|
|
|
@ -310,7 +310,7 @@ struct HashMapHasherDefault {
|
|||
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.ptr()); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
|
||||
|
|
|
@ -257,7 +257,7 @@
|
|||
<param index="0" name="track_idx" type="int" />
|
||||
<param index="1" name="to_animation" type="Animation" />
|
||||
<description>
|
||||
Adds a new track that is a copy of the given track from [param to_animation].
|
||||
Adds a new track to [param to_animation] that is a copy of the given track from this animation.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_track" qualifiers="const">
|
||||
|
|
|
@ -498,22 +498,22 @@
|
|||
Represents the size of the [enum TextureParam] enum.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_NEAREST" value="0" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
|
||||
The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_LINEAR" value="1" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels. Use this when you want to avoid a pixelated style, but do not want mipmaps.
|
||||
The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="2" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel in the nearest mipmap. The fastest way to read from textures with mipmaps.
|
||||
The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="3" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for most cases as mipmaps are important to smooth out pixels that are far from the camera.
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="4" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_MAX" value="6" enum="TextureFilter">
|
||||
Represents the size of the [enum TextureFilter] enum.
|
||||
|
|
|
@ -290,7 +290,7 @@
|
|||
Particles are drawn in the order emitted.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||
Particles are drawn in order of remaining lifetime.
|
||||
Particles are drawn in order of remaining lifetime. In other words, the particle with the highest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="PARAM_INITIAL_LINEAR_VELOCITY" value="0" enum="Parameter">
|
||||
Use with [method set_param_min], [method set_param_max], and [method set_param_curve] to set initial velocity properties.
|
||||
|
|
|
@ -315,7 +315,7 @@
|
|||
Particles are drawn in the order emitted.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||
Particles are drawn in order of remaining lifetime.
|
||||
Particles are drawn in order of remaining lifetime. In other words, the particle with the highest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
|
||||
Particles are drawn in order of depth.
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
|
||||
</member>
|
||||
<member name="exposure_shutter_speed" type="float" setter="set_shutter_speed" getter="get_shutter_speed" default="100.0">
|
||||
Time for shutter to open and close, measured in seconds. A higher value will let in more light leading to a brighter image, while a lower amount will let in less light leading to a darker image.
|
||||
Time for shutter to open and close, evaluated as [code]1 / shutter_speed[/code] seconds. A higher value will allow less light (leading to a darker image), while a lower value will allow more light (leading to a brighter image).
|
||||
Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
|
||||
</member>
|
||||
<member name="frustum_far" type="float" setter="set_far" getter="get_far" default="4000.0">
|
||||
|
|
|
@ -660,24 +660,26 @@
|
|||
The [CanvasItem] will inherit the filter from its parent.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_NEAREST" value="1" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering. Useful for pixel art.
|
||||
The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_LINEAR" value="2" enum="TextureFilter">
|
||||
The texture filter blends between the nearest four pixels. Use this for most cases where you want to avoid a pixelated style.
|
||||
The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel in the nearest mipmap. This is the fastest way to read from textures with mipmaps.
|
||||
The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="4" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate.
|
||||
The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate in this case.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate.
|
||||
The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate in this case.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FILTER_MAX" value="7" enum="TextureFilter">
|
||||
Represents the size of the [enum TextureFilter] enum.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
A 2D polyline shape, intended for use in physics. Used internally in [CollisionPolygon2D] when it's in [code]BUILD_SEGMENTS[/code] mode.
|
||||
Being just a collection of interconnected line segments, [ConcavePolygonShape2D] is the most freely configurable single 2D shape. It can be used to form polygons of any nature, or even shapes that don't enclose an area. However, [ConvexPolygonShape2D] is [i]hollow[/i] even if the interconnected line segments do enclose an area, which often makes it unsuitable for physics or detection.
|
||||
Being just a collection of interconnected line segments, [ConcavePolygonShape2D] is the most freely configurable single 2D shape. It can be used to form polygons of any nature, or even shapes that don't enclose an area. However, [ConcavePolygonShape2D] is [i]hollow[/i] even if the interconnected line segments do enclose an area, which often makes it unsuitable for physics or detection.
|
||||
[b]Note:[/b] When used for collision, [ConcavePolygonShape2D] is intended to work with static [CollisionShape2D] nodes like [StaticBody2D] and will likely not behave well for [CharacterBody2D]s or [RigidBody2D]s in a mode other than Static.
|
||||
[b]Warning:[/b] Physics bodies that are small have a chance to clip through this shape when moving fast. This happens because on one frame, the physics body may be on the "outside" of the shape, and on the next frame it may be "inside" it. [ConcavePolygonShape2D] is hollow, so it won't detect a collision.
|
||||
[b]Performance:[/b] Due to its complexity, [ConcavePolygonShape2D] is the slowest 2D collision shape to check collisions against. Its use should generally be limited to level geometry. If the polyline is closed, [CollisionPolygon2D]'s [code]BUILD_SOLIDS[/code] mode can be used, which decomposes the polygon into convex ones; see [ConvexPolygonShape2D]'s documentation for instructions.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
A 3D trimesh shape, intended for use in physics. Usually used to provide a shape for a [CollisionShape3D].
|
||||
Being just a collection of interconnected triangles, [ConcavePolygonShape3D] is the most freely configurable single 3D shape. It can be used to form polyhedra of any nature, or even shapes that don't enclose a volume. However, [ConvexPolygonShape3D] is [i]hollow[/i] even if the interconnected triangles do enclose a volume, which often makes it unsuitable for physics or detection.
|
||||
Being just a collection of interconnected triangles, [ConcavePolygonShape3D] is the most freely configurable single 3D shape. It can be used to form polyhedra of any nature, or even shapes that don't enclose a volume. However, [ConcavePolygonShape3D] is [i]hollow[/i] even if the interconnected triangles do enclose a volume, which often makes it unsuitable for physics or detection.
|
||||
[b]Note:[/b] When used for collision, [ConcavePolygonShape3D] is intended to work with static [CollisionShape3D] nodes like [StaticBody3D] and will likely not behave well for [CharacterBody3D]s or [RigidBody3D]s in a mode other than Static.
|
||||
[b]Warning:[/b] Physics bodies that are small have a chance to clip through this shape when moving fast. This happens because on one frame, the physics body may be on the "outside" of the shape, and on the next frame it may be "inside" it. [ConcavePolygonShape3D] is hollow, so it won't detect a collision.
|
||||
[b]Performance:[/b] Due to its complexity, [ConcavePolygonShape3D] is the slowest 3D collision shape to check collisions against. Its use should generally be limited to level geometry. For convex geometry, [ConvexPolygonShape3D] should be used. For dynamic physics bodies that need concave collision, several [ConvexPolygonShape3D]s can be used to represent its collision by using convex decomposition; see [ConvexPolygonShape3D]'s documentation for instructions.
|
||||
|
|
|
@ -1161,10 +1161,12 @@
|
|||
[b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree.
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47">
|
||||
Sent when this node is inside a [ScrollContainer] which has begun being scrolled.
|
||||
Sent when this node is inside a [ScrollContainer] which has begun being scrolled when dragging the scrollable area [i]with a touch event[/i]. This notification is [i]not[/i] sent when scrolling by dragging the scrollbar, scrolling with the mouse wheel or scrolling with keyboard/gamepad events.
|
||||
[b]Note:[/b] This signal is only emitted on Android or iOS, or on desktop/web platforms when [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is enabled.
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_SCROLL_END" value="48">
|
||||
Sent when this node is inside a [ScrollContainer] which has stopped being scrolled.
|
||||
Sent when this node is inside a [ScrollContainer] which has stopped being scrolled when dragging the scrollable area [i]with a touch event[/i]. This notification is [i]not[/i] sent when scrolling by dragging the scrollbar, scrolling with the mouse wheel or scrolling with keyboard/gamepad events.
|
||||
[b]Note:[/b] This signal is only emitted on Android or iOS, or on desktop/web platforms when [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is enabled.
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_LAYOUT_DIRECTION_CHANGED" value="49">
|
||||
Sent when control layout direction is changed.
|
||||
|
|
|
@ -294,6 +294,42 @@
|
|||
<param index="1" name="overwrite" type="bool" default="false" />
|
||||
<description>
|
||||
Adds entries from [param dictionary] to this dictionary. By default, duplicate keys are not copied over, unless [param overwrite] is [code]true[/code].
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
var dict = { "item": "sword", "quantity": 2 }
|
||||
var other_dict = { "quantity": 15, "color": "silver" }
|
||||
|
||||
# Overwriting of existing keys is disabled by default.
|
||||
dict.merge(other_dict)
|
||||
print(dict) # { "item": "sword", "quantity": 2, "color": "silver" }
|
||||
|
||||
# With overwriting of existing keys enabled.
|
||||
dict.merge(other_dict, true)
|
||||
print(dict) # { "item": "sword", "quantity": 15, "color": "silver" }
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
var dict = new Godot.Collections.Dictionary
|
||||
{
|
||||
["item"] = "sword",
|
||||
["quantity"] = 2,
|
||||
};
|
||||
|
||||
var otherDict = new Godot.Collections.Dictionary
|
||||
{
|
||||
["quantity"] = 15,
|
||||
["color"] = "silver",
|
||||
};
|
||||
|
||||
// Overwriting of existing keys is disabled by default.
|
||||
dict.Merge(otherDict);
|
||||
GD.Print(dict); // { "item": "sword", "quantity": 2, "color": "silver" }
|
||||
|
||||
// With overwriting of existing keys enabled.
|
||||
dict.Merge(otherDict, true);
|
||||
GD.Print(dict); // { "item": "sword", "quantity": 15, "color": "silver" }
|
||||
[/csharp]
|
||||
[/codeblocks]
|
||||
[b]Note:[/b] [method merge] is [i]not[/i] recursive. Nested dictionaries are considered as keys that can be overwritten or not depending on the value of [param overwrite], but they will never be merged together.
|
||||
</description>
|
||||
</method>
|
||||
<method name="size" qualifiers="const">
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
This [Control] node is used in the editor's Inspector dock to allow editing of numeric values. Can be used with [EditorInspectorPlugin] to recreate the same behavior.
|
||||
If [member step] is [code]1[/code], the [EditorSpinSlider] will display up/down arrows, similar to [SpinBox]. If the [member step] is not [code]1[/code], a slider will be displayed instead.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
|
@ -14,7 +15,7 @@
|
|||
</member>
|
||||
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
|
||||
<member name="hide_slider" type="bool" setter="set_hide_slider" getter="is_hiding_slider" default="false">
|
||||
If [code]true[/code], the slider is hidden.
|
||||
If [code]true[/code], the slider and up/down arrows are hidden.
|
||||
</member>
|
||||
<member name="label" type="String" setter="set_label" getter="get_label" default="""">
|
||||
The text that displays to the left of the value.
|
||||
|
|
|
@ -113,9 +113,10 @@
|
|||
Particles are drawn in the order emitted.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||
Particles are drawn in order of remaining lifetime.
|
||||
Particles are drawn in order of remaining lifetime. In other words, the particle with the highest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="DrawOrder">
|
||||
Particles are drawn in reverse order of remaining lifetime. In other words, the particle with the lowest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="EMIT_FLAG_POSITION" value="1" enum="EmitFlags">
|
||||
Particle starts at the specified position.
|
||||
|
|
|
@ -137,9 +137,10 @@
|
|||
Particles are drawn in the order emitted.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||
Particles are drawn in order of remaining lifetime.
|
||||
Particles are drawn in order of remaining lifetime. In other words, the particle with the highest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="DrawOrder">
|
||||
Particles are drawn in reverse order of remaining lifetime. In other words, the particle with the lowest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_VIEW_DEPTH" value="3" enum="DrawOrder">
|
||||
Particles are drawn in order of depth.
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="Material" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Abstract base [Resource] for coloring and shading geometry.
|
||||
Virtual base class for applying visual properties to an object, such as color and roughness.
|
||||
</brief_description>
|
||||
<description>
|
||||
Material is a base [Resource] used for coloring and shading geometry. All materials inherit from it and almost all [VisualInstance3D] derived nodes carry a Material. A few flags and parameters are shared between all material types and are configured here.
|
||||
[Material] is a base resource used for coloring and shading geometry. All materials inherit from it and almost all [VisualInstance3D] derived nodes carry a [Material]. A few flags and parameters are shared between all material types and are configured here.
|
||||
Importantly, you can inherit from [Material] to create your own custom material type in script or in GDExtension.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="3D Material Testers Demo">https://godotengine.org/asset-library/asset/123</link>
|
||||
|
@ -14,21 +15,25 @@
|
|||
<method name="_can_do_next_pass" qualifiers="virtual const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Only exposed for the purpose of overriding. You cannot call this function directly. Used internally to determine if [member next_pass] should be shown in the editor or not.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_can_use_render_priority" qualifiers="virtual const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Only exposed for the purpose of overriding. You cannot call this function directly. Used internally to determine if [member render_priority] should be shown in the editor or not.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_shader_mode" qualifiers="virtual const">
|
||||
<return type="int" enum="Shader.Mode" />
|
||||
<description>
|
||||
Only exposed for the purpose of overriding. You cannot call this function directly. Used internally by various editor tools.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_shader_rid" qualifiers="virtual const">
|
||||
<return type="RID" />
|
||||
<description>
|
||||
Only exposed for the purpose of overriding. You cannot call this function directly. Used internally by various editor tools. Used to access the RID of the [Material]'s [Shader].
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_placeholder" qualifiers="const">
|
||||
|
@ -40,18 +45,20 @@
|
|||
<method name="inspect_native_shader_code">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Only available when running in the editor. Opens a popup that visualizes the generated shader code, including all variants and internal shader code.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="next_pass" type="Material" setter="set_next_pass" getter="get_next_pass">
|
||||
Sets the [Material] to be used for the next pass. This renders the object again using a different material.
|
||||
[b]Note:[/b] [member next_pass] materials are not necessarily drawn immediately after the source [Material]. Draw order is determined by material properties, [member render_priority], and distance to camera.
|
||||
[b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial".
|
||||
</member>
|
||||
<member name="render_priority" type="int" setter="set_render_priority" getter="get_render_priority">
|
||||
Sets the render priority for transparent objects in 3D scenes. Higher priority objects will be sorted in front of lower priority objects.
|
||||
Sets the render priority for objects in 3D scenes. Higher priority objects will be sorted in front of lower priority objects. In other words, all objects with [member render_priority] [code]1[/code] will render before all objects with [member render_priority] [code]0[/code]).
|
||||
[b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial".
|
||||
[b]Note:[/b] This only applies to sorting of transparent objects. This will not impact how transparent objects are sorted relative to opaque objects. This is because opaque objects are not sorted, while transparent objects are sorted from back to front (subject to priority).
|
||||
[b]Note:[/b] This will not impact how transparent objects are sorted relative to opaque objects or how dynamic meshes will be sorted relative to other opaque meshes. This is because all transparent objects are drawn after all opaque objects and all dynamic opaque meshes are drawn before other opaque meshes.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
|
|
|
@ -445,7 +445,7 @@
|
|||
<method name="get_tree" qualifiers="const">
|
||||
<return type="SceneTree" />
|
||||
<description>
|
||||
Returns the [SceneTree] that contains this node.
|
||||
Returns the [SceneTree] that contains this node. Returns [code]null[/code] and prints an error if this node is not inside the scene tree. See also [method is_inside_tree].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_viewport" qualifiers="const">
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
<param index="1" name="submenu" type="String" />
|
||||
<param index="2" name="id" type="int" default="-1" />
|
||||
<description>
|
||||
Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. The [param submenu] argument is the name of the child [PopupMenu] node that will be shown when the item is clicked.
|
||||
Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. The [param submenu] argument must be the name of an existing [PopupMenu] that has been added as a child to this node. This submenu will be shown when the item is clicked, hovered for long enough, or activated using the [code]ui_select[/code] or [code]ui_right[/code] input actions.
|
||||
An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
|
||||
</description>
|
||||
</method>
|
||||
|
|
|
@ -324,7 +324,8 @@
|
|||
Changes to this setting will only be applied upon restarting the application.
|
||||
</member>
|
||||
<member name="application/run/frame_delay_msec" type="int" setter="" getter="" default="0">
|
||||
Forces a delay between frames in the main loop (in milliseconds). This may be useful if you plan to disable vertical synchronization.
|
||||
Forces a [i]constant[/i] delay between frames in the main loop (in milliseconds). In most situations, [member application/run/max_fps] should be preferred as an FPS limiter as it's more precise.
|
||||
This setting can be overridden using the [code]--frame-delay <ms;>[/code] command line argument.
|
||||
</member>
|
||||
<member name="application/run/low_processor_mode" type="bool" setter="" getter="" default="false">
|
||||
If [code]true[/code], enables low-processor usage mode. This setting only works on desktop platforms. The screen is not redrawn if nothing changes visually. This is meant for writing applications and editors, but is pretty useless (and can hurt performance) in most games.
|
||||
|
|
|
@ -4416,9 +4416,10 @@
|
|||
Draw particles in the order that they appear in the particles array.
|
||||
</constant>
|
||||
<constant name="PARTICLES_DRAW_ORDER_LIFETIME" value="1" enum="ParticlesDrawOrder">
|
||||
Sort particles based on their lifetime.
|
||||
Sort particles based on their lifetime. In other words, the particle with the highest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="PARTICLES_DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="ParticlesDrawOrder">
|
||||
Sort particles based on the inverse of their lifetime. In other words, the particle with the lowest lifetime is drawn at the front.
|
||||
</constant>
|
||||
<constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="3" enum="ParticlesDrawOrder">
|
||||
Sort particles based on their distance to the camera.
|
||||
|
@ -5032,22 +5033,26 @@
|
|||
Uses the default filter mode for this [Viewport].
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="1" enum="CanvasItemTextureFilter">
|
||||
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
|
||||
The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="2" enum="CanvasItemTextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels. Use this when you want to avoid a pixelated style, but do not want mipmaps.
|
||||
The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="CanvasItemTextureFilter">
|
||||
The texture filter reads from the nearest pixel in the nearest mipmap. The fastest way to read from textures with mipmaps.
|
||||
The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="4" enum="CanvasItemTextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps.
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="CanvasItemTextureFilter">
|
||||
The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera.
|
||||
The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate in this case.
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="CanvasItemTextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing.
|
||||
The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate in this case.
|
||||
</constant>
|
||||
<constant name="CANVAS_ITEM_TEXTURE_FILTER_MAX" value="7" enum="CanvasItemTextureFilter">
|
||||
Max value for [enum CanvasItemTextureFilter] enum.
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
<description>
|
||||
A control used for playback of [VideoStream] resources.
|
||||
Supported video formats are [url=https://www.theora.org/]Ogg Theora[/url] ([code].ogv[/code], [VideoStreamTheora]) and any format exposed via a GDExtension plugin.
|
||||
[b]Note:[/b] Due to a bug, VideoStreamPlayer does not support localization remapping yet.
|
||||
[b]Warning:[/b] On Web, video playback [i]will[/i] perform poorly due to missing architecture-specific assembly optimizations.
|
||||
</description>
|
||||
<tutorials>
|
||||
|
|
|
@ -543,16 +543,18 @@
|
|||
<constant name="DEBUG_DRAW_MOTION_VECTORS" value="25" enum="DebugDraw">
|
||||
</constant>
|
||||
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="0" enum="DefaultCanvasItemTextureFilter">
|
||||
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
|
||||
The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="1" enum="DefaultCanvasItemTextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels. Use this when you want to avoid a pixelated style, but do not want mipmaps.
|
||||
The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="2" enum="DefaultCanvasItemTextureFilter">
|
||||
The texture filter reads from the nearest pixel in the nearest mipmap. The fastest way to read from textures with mipmaps.
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="DefaultCanvasItemTextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps.
|
||||
The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX" value="4" enum="DefaultCanvasItemTextureFilter">
|
||||
Max value for [enum DefaultCanvasItemTextureFilter] enum.
|
||||
|
|
|
@ -57,24 +57,26 @@
|
|||
Sample the texture using the filter determined by the node this shader is attached to.
|
||||
</constant>
|
||||
<constant name="FILTER_NEAREST" value="1" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
|
||||
The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="FILTER_LINEAR" value="2" enum="TextureFilter">
|
||||
The texture filter blends between the nearest four pixels. Use this for most cases where you want to avoid a pixelated style.
|
||||
The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
|
||||
</constant>
|
||||
<constant name="FILTER_NEAREST_MIPMAP" value="3" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel in the nearest mipmap. This is the fastest way to read from textures with mipmaps.
|
||||
The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="FILTER_LINEAR_MIPMAP" value="4" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
|
||||
Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
|
||||
</constant>
|
||||
<constant name="FILTER_NEAREST_MIPMAP_ANISOTROPIC" value="5" enum="TextureFilter">
|
||||
The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_LINEAR_MIPMAP] is usually more appropriate.
|
||||
The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_NEAREST_MIPMAP] is usually more appropriate in this case.
|
||||
</constant>
|
||||
<constant name="FILTER_LINEAR_MIPMAP_ANISOTROPIC" value="6" enum="TextureFilter">
|
||||
The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_LINEAR_MIPMAP] is usually more appropriate.
|
||||
The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
|
||||
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_LINEAR_MIPMAP] is usually more appropriate in this case.
|
||||
</constant>
|
||||
<constant name="FILTER_MAX" value="7" enum="TextureFilter">
|
||||
Represents the size of the [enum TextureFilter] enum.
|
||||
|
|
|
@ -660,6 +660,11 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
|||
state.current_tex = RID();
|
||||
|
||||
for (uint32_t i = 0; i <= state.current_batch_index; i++) {
|
||||
// Skipping when there is no instances.
|
||||
if (state.canvas_instance_batches[i].instance_count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//setup clip
|
||||
if (current_clip != state.canvas_instance_batches[i].clip) {
|
||||
current_clip = state.canvas_instance_batches[i].clip;
|
||||
|
|
|
@ -1734,7 +1734,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
RenderDataGLES3 render_data;
|
||||
{
|
||||
render_data.render_buffers = rb;
|
||||
render_data.transparent_bg = rb.is_valid() ? rb->is_transparent : false;
|
||||
render_data.transparent_bg = rb.is_valid() ? rt->is_transparent : false;
|
||||
// Our first camera is used by default
|
||||
render_data.cam_transform = p_camera_data->main_transform;
|
||||
render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
|
||||
|
@ -1980,6 +1980,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
}
|
||||
|
||||
if (!keep_color) {
|
||||
clear_color.a = render_data.transparent_bg ? 0.0f : 1.0f;
|
||||
glClearBufferfv(GL_COLOR, 0, clear_color.components);
|
||||
}
|
||||
RENDER_TIMESTAMP("Render Opaque Pass");
|
||||
|
|
|
@ -38,8 +38,6 @@ RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
|
|||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
|
||||
//internal_size.x = p_internal_size.x; // ignore for now
|
||||
//internal_size.y = p_internal_size.y;
|
||||
width = p_target_size.x;
|
||||
|
@ -54,10 +52,6 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
|
|||
view_count = p_view_count;
|
||||
|
||||
free_render_buffer_data();
|
||||
|
||||
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
|
||||
|
||||
is_transparent = rt->is_transparent;
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::free_render_buffer_data() {
|
||||
|
|
|
@ -58,8 +58,6 @@ public:
|
|||
//bool use_debanding = false;
|
||||
uint32_t view_count = 1;
|
||||
|
||||
bool is_transparent = false;
|
||||
|
||||
RID render_target;
|
||||
|
||||
//built-in textures used for ping pong image processing and blurring
|
||||
|
|
|
@ -59,8 +59,6 @@ static const GLenum _cube_side_enum[6] = {
|
|||
TextureStorage::TextureStorage() {
|
||||
singleton = this;
|
||||
|
||||
system_fbo = 0;
|
||||
|
||||
{ //create default textures
|
||||
{ // White Textures
|
||||
|
||||
|
@ -709,18 +707,20 @@ void TextureStorage::texture_free(RID p_texture) {
|
|||
memdelete(t->canvas_texture);
|
||||
}
|
||||
|
||||
if (t->tex_id != 0) {
|
||||
if (!t->is_external) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id);
|
||||
bool must_free_data = false;
|
||||
if (t->is_proxy) {
|
||||
if (t->proxy_to.is_valid()) {
|
||||
Texture *proxy_to = texture_owner.get_or_null(t->proxy_to);
|
||||
if (proxy_to) {
|
||||
proxy_to->proxies.erase(p_texture);
|
||||
}
|
||||
}
|
||||
t->tex_id = 0;
|
||||
} else {
|
||||
must_free_data = t->tex_id != 0 && !t->is_external;
|
||||
}
|
||||
|
||||
if (t->is_proxy && t->proxy_to.is_valid()) {
|
||||
Texture *proxy_to = texture_owner.get_or_null(t->proxy_to);
|
||||
if (proxy_to) {
|
||||
proxy_to->proxies.erase(p_texture);
|
||||
}
|
||||
if (must_free_data) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(t->tex_id);
|
||||
t->tex_id = 0;
|
||||
}
|
||||
|
||||
texture_atlas_remove_texture(p_texture);
|
||||
|
|
|
@ -2694,14 +2694,21 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
AnimationPlayer *ap = ape->get_player();
|
||||
if (ap) {
|
||||
NodePath npath = animation->track_get_path(track);
|
||||
Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(npath.get_concatenated_names()));
|
||||
StringName prop = npath.get_concatenated_subnames();
|
||||
PropertyInfo prop_info;
|
||||
ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
|
||||
bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
|
||||
if (is_angle) {
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
|
||||
Node *a_ap_root_node = ap->get_node(ap->get_root());
|
||||
Node *nd = nullptr;
|
||||
// We must test that we have a valid a_ap_root_node before trying to access its content to init the nd Node.
|
||||
if (a_ap_root_node) {
|
||||
nd = a_ap_root_node->get_node(NodePath(npath.get_concatenated_names()));
|
||||
}
|
||||
if (nd) {
|
||||
StringName prop = npath.get_concatenated_subnames();
|
||||
PropertyInfo prop_info;
|
||||
ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
|
||||
bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
|
||||
if (is_angle) {
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -367,6 +367,9 @@ void FindReplaceBar::_update_results_count() {
|
|||
|
||||
int col_pos = 0;
|
||||
|
||||
bool searched_start_is_symbol = is_symbol(searched[0]);
|
||||
bool searched_end_is_symbol = is_symbol(searched[searched.length() - 1]);
|
||||
|
||||
while (true) {
|
||||
col_pos = is_case_sensitive() ? line_text.find(searched, col_pos) : line_text.findn(searched, col_pos);
|
||||
|
||||
|
@ -375,11 +378,11 @@ void FindReplaceBar::_update_results_count() {
|
|||
}
|
||||
|
||||
if (is_whole_words()) {
|
||||
if (col_pos > 0 && !is_symbol(line_text[col_pos - 1])) {
|
||||
if (!searched_start_is_symbol && col_pos > 0 && !is_symbol(line_text[col_pos - 1])) {
|
||||
col_pos += searched.length();
|
||||
continue;
|
||||
}
|
||||
if (col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) {
|
||||
if (!searched_end_is_symbol && col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) {
|
||||
col_pos += searched.length();
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -338,8 +338,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
|
|||
undo_redo->add_do_property(ProjectSettings::get_singleton(), name, Variant());
|
||||
|
||||
undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, GLOBAL_GET(name));
|
||||
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_persisting", name, true);
|
||||
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", order);
|
||||
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", name, order);
|
||||
|
||||
undo_redo->add_do_method(this, "update_autoload");
|
||||
undo_redo->add_undo_method(this, "update_autoload");
|
||||
|
@ -795,8 +794,7 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) {
|
|||
undo_redo->add_do_property(ProjectSettings::get_singleton(), name, Variant());
|
||||
|
||||
undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, GLOBAL_GET(name));
|
||||
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_persisting", name, true);
|
||||
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", order);
|
||||
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", name, order);
|
||||
|
||||
undo_redo->add_do_method(this, "update_autoload");
|
||||
undo_redo->add_undo_method(this, "update_autoload");
|
||||
|
|
|
@ -854,12 +854,12 @@ void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_nam
|
|||
if (scr.is_null()) {
|
||||
return;
|
||||
}
|
||||
if (p_activate_name.length()) {
|
||||
set_addon_plugin_enabled(p_activate_name, true);
|
||||
}
|
||||
project_settings_editor->update_plugins();
|
||||
project_settings_editor->hide();
|
||||
push_item(scr.operator->());
|
||||
if (p_activate_name.length()) {
|
||||
set_addon_plugin_enabled(p_activate_name, true);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNode::_remove_plugin_from_enabled(const String &p_name) {
|
||||
|
@ -6690,7 +6690,7 @@ static void _execute_thread(void *p_ud) {
|
|||
eta->done.set();
|
||||
}
|
||||
|
||||
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
|
||||
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors, String *r_output) {
|
||||
if (execute_output_dialog) {
|
||||
execute_output_dialog->set_title(p_title);
|
||||
execute_output_dialog->get_ok_button()->set_disabled(true);
|
||||
|
@ -6736,6 +6736,9 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
|
|||
execute_output_dialog->get_ok_button()->set_disabled(false);
|
||||
}
|
||||
|
||||
if (r_output) {
|
||||
*r_output = eta.output;
|
||||
}
|
||||
return eta.exitcode;
|
||||
}
|
||||
|
||||
|
@ -7443,10 +7446,6 @@ EditorNode::EditorNode() {
|
|||
project_menu->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER);
|
||||
project_menu->add_separator();
|
||||
|
||||
plugin_config_dialog = memnew(PluginConfigDialog);
|
||||
plugin_config_dialog->connect("plugin_ready", callable_mp(this, &EditorNode::_on_plugin_ready));
|
||||
gui_base->add_child(plugin_config_dialog);
|
||||
|
||||
tool_menu = memnew(PopupMenu);
|
||||
tool_menu->set_name("Tools");
|
||||
tool_menu->connect("index_pressed", callable_mp(this, &EditorNode::_tool_menu_option));
|
||||
|
|
|
@ -357,8 +357,6 @@ private:
|
|||
|
||||
Timer *screenshot_timer = nullptr;
|
||||
|
||||
PluginConfigDialog *plugin_config_dialog = nullptr;
|
||||
|
||||
RichTextLabel *load_errors = nullptr;
|
||||
AcceptDialog *load_error_dialog = nullptr;
|
||||
|
||||
|
@ -934,7 +932,7 @@ public:
|
|||
|
||||
bool has_scenes_in_session();
|
||||
|
||||
int execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok = true, bool p_close_on_errors = false);
|
||||
int execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok = true, bool p_close_on_errors = false, String *r_output = nullptr);
|
||||
|
||||
EditorNode();
|
||||
~EditorNode();
|
||||
|
|
|
@ -3664,7 +3664,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
|
|||
case Variant::VECTOR2I: {
|
||||
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide));
|
||||
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
|
||||
editor->setup(hint.min, hint.max, 1, true, p_hint == PROPERTY_HINT_LINK, hint.suffix);
|
||||
editor->setup(hint.min, hint.max, 1, false, p_hint == PROPERTY_HINT_LINK, hint.suffix);
|
||||
return editor;
|
||||
|
||||
} break;
|
||||
|
@ -3691,7 +3691,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
|
|||
case Variant::VECTOR3I: {
|
||||
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide));
|
||||
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
|
||||
editor->setup(hint.min, hint.max, 1, true, p_hint == PROPERTY_HINT_LINK, hint.suffix);
|
||||
editor->setup(hint.min, hint.max, 1, false, p_hint == PROPERTY_HINT_LINK, hint.suffix);
|
||||
return editor;
|
||||
|
||||
} break;
|
||||
|
@ -3705,7 +3705,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
|
|||
case Variant::VECTOR4I: {
|
||||
EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
|
||||
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
|
||||
editor->setup(hint.min, hint.max, 1, true, p_hint == PROPERTY_HINT_LINK, hint.suffix);
|
||||
editor->setup(hint.min, hint.max, 1, false, p_hint == PROPERTY_HINT_LINK, hint.suffix);
|
||||
return editor;
|
||||
|
||||
} break;
|
||||
|
|
|
@ -1631,7 +1631,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
|||
if (increase_scrollbar_touch_area) {
|
||||
theme->set_stylebox("scroll", "HScrollBar", make_line_stylebox(separator_color, 50));
|
||||
} else {
|
||||
theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1));
|
||||
theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, -5, 1, -5, 1));
|
||||
}
|
||||
theme->set_stylebox("scroll_focus", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1));
|
||||
theme->set_stylebox("grabber", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), SNAME("EditorIcons")), 6, 6, 6, 6, 1, 1, 1, 1));
|
||||
|
@ -1649,7 +1649,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
|||
if (increase_scrollbar_touch_area) {
|
||||
theme->set_stylebox("scroll", "VScrollBar", make_line_stylebox(separator_color, 50, 1, 1, true));
|
||||
} else {
|
||||
theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1));
|
||||
theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, -5, 1, -5));
|
||||
}
|
||||
theme->set_stylebox("scroll_focus", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1));
|
||||
theme->set_stylebox("grabber", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), SNAME("EditorIcons")), 6, 6, 6, 6, 1, 1, 1, 1));
|
||||
|
|
|
@ -1421,7 +1421,7 @@ void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_
|
|||
nullptr,
|
||||
0,
|
||||
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
|
||||
0);
|
||||
1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
|
||||
|
||||
String target = da->read_link(f);
|
||||
zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
|
||||
|
@ -1465,7 +1465,7 @@ void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_
|
|||
nullptr,
|
||||
0,
|
||||
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
|
||||
0);
|
||||
1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
|
||||
|
||||
Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
|
||||
if (fa.is_null()) {
|
||||
|
|
|
@ -242,7 +242,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
|
|||
|
||||
export_filter->select(current->get_export_filter());
|
||||
include_filters->set_text(current->get_include_filter());
|
||||
include_label->set_text(current->get_export_filter() == EditorExportPreset::EXCLUDE_SELECTED_RESOURCES ? TTR("Resources to exclude:") : TTR("Resources to export:"));
|
||||
include_label->set_text(_get_resource_export_header(current->get_export_filter()));
|
||||
exclude_filters->set_text(current->get_exclude_filter());
|
||||
server_strip_message->set_visible(current->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED);
|
||||
|
||||
|
@ -703,13 +703,24 @@ void ProjectExportDialog::_export_type_changed(int p_which) {
|
|||
if (filter_type == EditorExportPreset::EXPORT_CUSTOMIZED && current->get_customized_files_count() == 0) {
|
||||
current->set_file_export_mode("res://", EditorExportPreset::MODE_FILE_STRIP);
|
||||
}
|
||||
include_label->set_text(current->get_export_filter() == EditorExportPreset::EXCLUDE_SELECTED_RESOURCES ? TTR("Resources to exclude:") : TTR("Resources to export:"));
|
||||
include_label->set_text(_get_resource_export_header(current->get_export_filter()));
|
||||
|
||||
updating = true;
|
||||
_fill_resource_tree();
|
||||
updating = false;
|
||||
}
|
||||
|
||||
String ProjectExportDialog::_get_resource_export_header(EditorExportPreset::ExportFilter p_filter) const {
|
||||
switch (p_filter) {
|
||||
case EditorExportPreset::EXCLUDE_SELECTED_RESOURCES:
|
||||
return TTR("Resources to exclude:");
|
||||
case EditorExportPreset::EXPORT_CUSTOMIZED:
|
||||
return TTR("Resources to override export behavior:");
|
||||
default:
|
||||
return TTR("Resources to export:");
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_filter_changed(const String &p_filter) {
|
||||
if (updating) {
|
||||
return;
|
||||
|
|
|
@ -115,6 +115,7 @@ private:
|
|||
|
||||
void _export_type_changed(int p_which);
|
||||
void _filter_changed(const String &p_filter);
|
||||
String _get_resource_export_header(EditorExportPreset::ExportFilter p_filter) const;
|
||||
void _fill_resource_tree();
|
||||
void _setup_item_for_file_mode(TreeItem *p_item, EditorExportPreset::FileExportMode p_mode);
|
||||
bool _fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref<EditorExportPreset> ¤t, EditorExportPreset::ExportFilter p_export_filter);
|
||||
|
|
|
@ -1507,6 +1507,10 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
|
|||
int base = 1;
|
||||
String name = base_name;
|
||||
while (state_machine->has_node(name)) {
|
||||
if (name == prev_name) {
|
||||
name_edit_popup->hide(); // The old name wins, the name doesn't change, just hide the popup.
|
||||
return;
|
||||
}
|
||||
base++;
|
||||
name = base_name + " " + itos(base);
|
||||
}
|
||||
|
|
|
@ -533,6 +533,11 @@ void BoneMapper::_clear_mapping_current_group() {
|
|||
}
|
||||
|
||||
#ifdef MODULE_REGEX_ENABLED
|
||||
bool BoneMapper::is_match_with_bone_name(String p_bone_name, String p_word) {
|
||||
RegEx re = RegEx(p_word);
|
||||
return !re.search(p_bone_name.to_lower()).is_null();
|
||||
}
|
||||
|
||||
int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation, int p_parent, int p_child, int p_children_count) {
|
||||
// There may be multiple candidates hit by existing the subsidiary bone.
|
||||
// The one with the shortest name is probably the original.
|
||||
|
@ -540,7 +545,6 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic
|
|||
String shortest = "";
|
||||
|
||||
for (int word_idx = 0; word_idx < p_picklist.size(); word_idx++) {
|
||||
RegEx re = RegEx(p_picklist[word_idx]);
|
||||
if (p_child == -1) {
|
||||
Vector<int> bones_to_process = p_parent == -1 ? p_skeleton->get_parentless_bones() : p_skeleton->get_bone_children(p_parent);
|
||||
while (bones_to_process.size() > 0) {
|
||||
|
@ -559,7 +563,7 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic
|
|||
}
|
||||
|
||||
String bn = skeleton->get_bone_name(idx);
|
||||
if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) {
|
||||
if (is_match_with_bone_name(bn, p_picklist[word_idx]) && guess_bone_segregation(bn) == p_segregation) {
|
||||
hit_list.push_back(bn);
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +588,7 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic
|
|||
}
|
||||
|
||||
String bn = skeleton->get_bone_name(idx);
|
||||
if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) {
|
||||
if (is_match_with_bone_name(bn, p_picklist[word_idx]) && guess_bone_segregation(bn) == p_segregation) {
|
||||
hit_list.push_back(bn);
|
||||
}
|
||||
idx = skeleton->get_bone_parent(idx);
|
||||
|
@ -654,6 +658,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
picklist.push_back("pelvis");
|
||||
picklist.push_back("waist");
|
||||
picklist.push_back("torso");
|
||||
picklist.push_back("spine");
|
||||
int hips = search_bone_by_name(skeleton, picklist);
|
||||
if (hips == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess Hips. Abort auto mapping.");
|
||||
|
@ -704,70 +709,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
bone_idx = -1;
|
||||
search_path.clear();
|
||||
|
||||
// 3. Guess Neck
|
||||
picklist.push_back("neck");
|
||||
picklist.push_back("head"); // For no neck model.
|
||||
picklist.push_back("face"); // Same above.
|
||||
int neck = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, hips);
|
||||
picklist.clear();
|
||||
|
||||
// 4. Guess Head
|
||||
picklist.push_back("head");
|
||||
picklist.push_back("face");
|
||||
int head = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck);
|
||||
if (head == -1) {
|
||||
search_path = skeleton->get_bone_children(neck);
|
||||
if (search_path.size() == 1) {
|
||||
head = search_path[0]; // Maybe only one child of the Neck is Head.
|
||||
}
|
||||
}
|
||||
if (head == -1) {
|
||||
if (neck != -1) {
|
||||
head = neck; // The head animation should have more movement.
|
||||
neck = -1;
|
||||
p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
|
||||
} else {
|
||||
WARN_PRINT("Auto Mapping couldn't guess Neck or Head."); // Continued for guessing on the other bones. But abort when guessing spines step.
|
||||
}
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("Neck", skeleton->get_bone_name(neck));
|
||||
p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
|
||||
}
|
||||
picklist.clear();
|
||||
search_path.clear();
|
||||
|
||||
int neck_or_head = neck != -1 ? neck : (head != -1 ? head : -1);
|
||||
if (neck_or_head != -1) {
|
||||
// 4-1. Guess Eyes
|
||||
picklist.push_back("eye(?!.*(brow|lash|lid))");
|
||||
bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, neck_or_head);
|
||||
if (bone_idx == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess LeftEye.");
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("LeftEye", skeleton->get_bone_name(bone_idx));
|
||||
}
|
||||
|
||||
bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, neck_or_head);
|
||||
if (bone_idx == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess RightEye.");
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("RightEye", skeleton->get_bone_name(bone_idx));
|
||||
}
|
||||
picklist.clear();
|
||||
|
||||
// 4-2. Guess Jaw
|
||||
picklist.push_back("jaw");
|
||||
bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck_or_head);
|
||||
if (bone_idx == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess Jaw.");
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("Jaw", skeleton->get_bone_name(bone_idx));
|
||||
}
|
||||
bone_idx = -1;
|
||||
picklist.clear();
|
||||
}
|
||||
|
||||
// 5. Guess Foots
|
||||
// 3. Guess Foots
|
||||
picklist.push_back("foot");
|
||||
picklist.push_back("ankle");
|
||||
int left_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
|
||||
|
@ -784,7 +726,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
}
|
||||
picklist.clear();
|
||||
|
||||
// 5-1. Guess LowerLegs
|
||||
// 3-1. Guess LowerLegs
|
||||
picklist.push_back("(low|under).*leg");
|
||||
picklist.push_back("knee");
|
||||
picklist.push_back("shin");
|
||||
|
@ -810,7 +752,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
}
|
||||
picklist.clear();
|
||||
|
||||
// 5-2. Guess UpperLegs
|
||||
// 3-2. Guess UpperLegs
|
||||
picklist.push_back("up.*leg");
|
||||
picklist.push_back("thigh");
|
||||
picklist.push_back("leg");
|
||||
|
@ -834,7 +776,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
bone_idx = -1;
|
||||
picklist.clear();
|
||||
|
||||
// 5-3. Guess Toes
|
||||
// 3-3. Guess Toes
|
||||
picklist.push_back("toe");
|
||||
picklist.push_back("ball");
|
||||
if (left_foot != -1) {
|
||||
|
@ -871,7 +813,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
bone_idx = -1;
|
||||
picklist.clear();
|
||||
|
||||
// 6. Guess Hands
|
||||
// 4. Guess Hands
|
||||
picklist.push_back("hand");
|
||||
picklist.push_back("wrist");
|
||||
picklist.push_back("palm");
|
||||
|
@ -916,7 +858,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
bone_idx = -1;
|
||||
picklist.clear();
|
||||
|
||||
// 6-1. Guess Finger
|
||||
// 4-1. Guess Finger
|
||||
bool named_finger_is_found = false;
|
||||
LocalVector<String> fingers;
|
||||
fingers.push_back("thumb|pollex");
|
||||
|
@ -1106,7 +1048,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
}
|
||||
}
|
||||
|
||||
// 7. Guess Arms
|
||||
// 5. Guess Arms
|
||||
picklist.push_back("shoulder");
|
||||
picklist.push_back("clavicle");
|
||||
picklist.push_back("collar");
|
||||
|
@ -1124,7 +1066,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
}
|
||||
picklist.clear();
|
||||
|
||||
// 7-1. Guess LowerArms
|
||||
// 5-1. Guess LowerArms
|
||||
picklist.push_back("(low|fore).*arm");
|
||||
picklist.push_back("elbow");
|
||||
picklist.push_back("arm");
|
||||
|
@ -1148,7 +1090,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
}
|
||||
picklist.clear();
|
||||
|
||||
// 7-2. Guess UpperArms
|
||||
// 5-2. Guess UpperArms
|
||||
picklist.push_back("up.*arm");
|
||||
picklist.push_back("arm");
|
||||
if (left_shoulder != -1 && left_lower_arm != -1) {
|
||||
|
@ -1171,6 +1113,99 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
|
|||
bone_idx = -1;
|
||||
picklist.clear();
|
||||
|
||||
// 6. Guess Neck
|
||||
picklist.push_back("neck");
|
||||
picklist.push_back("head"); // For no neck model.
|
||||
picklist.push_back("face"); // Same above.
|
||||
int neck = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, hips);
|
||||
picklist.clear();
|
||||
if (neck == -1) {
|
||||
// If it can't expect by name, search child spine of where the right and left shoulders (or hands) cross.
|
||||
int ls_idx = left_shoulder != -1 ? left_shoulder : (left_hand_or_palm != -1 ? left_hand_or_palm : -1);
|
||||
int rs_idx = right_shoulder != -1 ? right_shoulder : (right_hand_or_palm != -1 ? right_hand_or_palm : -1);
|
||||
if (ls_idx != -1 && rs_idx != -1) {
|
||||
bool detect = false;
|
||||
while (ls_idx != hips && ls_idx >= 0 && rs_idx != hips && rs_idx >= 0) {
|
||||
ls_idx = skeleton->get_bone_parent(ls_idx);
|
||||
rs_idx = skeleton->get_bone_parent(rs_idx);
|
||||
if (ls_idx == rs_idx) {
|
||||
detect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (detect) {
|
||||
Vector<int> children = skeleton->get_bone_children(ls_idx);
|
||||
children.erase(ls_idx);
|
||||
children.erase(rs_idx);
|
||||
String word = "spine"; // It would be better to limit the search with "spine" because it could be mistaken with breast, wing and etc...
|
||||
for (int i = 0; children.size(); i++) {
|
||||
bone_idx = children[i];
|
||||
if (is_match_with_bone_name(skeleton->get_bone_name(bone_idx), word)) {
|
||||
neck = bone_idx;
|
||||
break;
|
||||
};
|
||||
}
|
||||
bone_idx = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Guess Head
|
||||
picklist.push_back("head");
|
||||
picklist.push_back("face");
|
||||
int head = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck);
|
||||
if (head == -1) {
|
||||
search_path = skeleton->get_bone_children(neck);
|
||||
if (search_path.size() == 1) {
|
||||
head = search_path[0]; // Maybe only one child of the Neck is Head.
|
||||
}
|
||||
}
|
||||
if (head == -1) {
|
||||
if (neck != -1) {
|
||||
head = neck; // The head animation should have more movement.
|
||||
neck = -1;
|
||||
p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
|
||||
} else {
|
||||
WARN_PRINT("Auto Mapping couldn't guess Neck or Head."); // Continued for guessing on the other bones. But abort when guessing spines step.
|
||||
}
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("Neck", skeleton->get_bone_name(neck));
|
||||
p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
|
||||
}
|
||||
picklist.clear();
|
||||
search_path.clear();
|
||||
|
||||
int neck_or_head = neck != -1 ? neck : (head != -1 ? head : -1);
|
||||
if (neck_or_head != -1) {
|
||||
// 7-1. Guess Eyes
|
||||
picklist.push_back("eye(?!.*(brow|lash|lid))");
|
||||
bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, neck_or_head);
|
||||
if (bone_idx == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess LeftEye.");
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("LeftEye", skeleton->get_bone_name(bone_idx));
|
||||
}
|
||||
|
||||
bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, neck_or_head);
|
||||
if (bone_idx == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess RightEye.");
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("RightEye", skeleton->get_bone_name(bone_idx));
|
||||
}
|
||||
picklist.clear();
|
||||
|
||||
// 7-2. Guess Jaw
|
||||
picklist.push_back("jaw");
|
||||
bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck_or_head);
|
||||
if (bone_idx == -1) {
|
||||
WARN_PRINT("Auto Mapping couldn't guess Jaw.");
|
||||
} else {
|
||||
p_bone_map->_set_skeleton_bone_name("Jaw", skeleton->get_bone_name(bone_idx));
|
||||
}
|
||||
bone_idx = -1;
|
||||
picklist.clear();
|
||||
}
|
||||
|
||||
// 8. Guess UpperChest or Chest
|
||||
if (neck_or_head == -1) {
|
||||
return; // Abort.
|
||||
|
|
|
@ -179,6 +179,7 @@ class BoneMapper : public VBoxContainer {
|
|||
BONE_SEGREGATION_LEFT,
|
||||
BONE_SEGREGATION_RIGHT
|
||||
};
|
||||
bool is_match_with_bone_name(String p_bone_name, String p_word);
|
||||
int search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1);
|
||||
BoneSegregation guess_bone_segregation(String p_bone_name);
|
||||
void auto_mapping_process(Ref<BoneMap> &p_bone_map);
|
||||
|
|
|
@ -456,6 +456,7 @@ void Polygon2DEditor::_uv_mode(int p_mode) {
|
|||
for (int i = 0; i < UV_MODE_MAX; i++) {
|
||||
uv_button[i]->set_pressed(p_mode == i);
|
||||
}
|
||||
uv_edit_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
|
||||
|
@ -980,9 +981,36 @@ void Polygon2DEditor::_uv_draw() {
|
|||
mtx.columns[2] = -uv_draw_ofs;
|
||||
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
|
||||
|
||||
RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx);
|
||||
uv_edit_draw->draw_texture(base_tex, Point2());
|
||||
RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
|
||||
// Draw texture as a background if editing uvs or no uv mapping exist.
|
||||
if (uv_edit_mode[0]->is_pressed() || uv_mode == UV_MODE_CREATE || node->get_polygon().is_empty() || node->get_uv().size() != node->get_polygon().size()) {
|
||||
Transform2D texture_transform = Transform2D(node->get_texture_rotation(), node->get_texture_offset());
|
||||
texture_transform.scale(node->get_texture_scale());
|
||||
texture_transform.affine_invert();
|
||||
RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx * texture_transform);
|
||||
uv_edit_draw->draw_texture(base_tex, Point2());
|
||||
RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
|
||||
preview_polygon->hide();
|
||||
} else {
|
||||
preview_polygon->set_transform(mtx);
|
||||
// Keep in sync with newly added Polygon2D properties (when relevant).
|
||||
preview_polygon->set_texture(node->get_texture());
|
||||
preview_polygon->set_texture_offset(node->get_texture_offset());
|
||||
preview_polygon->set_texture_rotation(node->get_texture_rotation());
|
||||
preview_polygon->set_texture_scale(node->get_texture_scale());
|
||||
preview_polygon->set_texture_filter(node->get_texture_filter_in_tree());
|
||||
preview_polygon->set_texture_repeat(node->get_texture_repeat_in_tree());
|
||||
preview_polygon->set_polygon(node->get_polygon());
|
||||
preview_polygon->set_uv(node->get_uv());
|
||||
preview_polygon->set_invert(node->get_invert());
|
||||
preview_polygon->set_invert_border(node->get_invert_border());
|
||||
preview_polygon->set_internal_vertex_count(node->get_internal_vertex_count());
|
||||
if (uv_mode == UV_MODE_ADD_POLYGON) {
|
||||
preview_polygon->set_polygons(Array());
|
||||
} else {
|
||||
preview_polygon->set_polygons(node->get_polygons());
|
||||
}
|
||||
preview_polygon->show();
|
||||
}
|
||||
|
||||
if (snap_show_grid) {
|
||||
Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
|
||||
|
@ -1347,10 +1375,19 @@ Polygon2DEditor::Polygon2DEditor() {
|
|||
HSplitContainer *uv_main_hsc = memnew(HSplitContainer);
|
||||
uv_main_vb->add_child(uv_main_hsc);
|
||||
uv_main_hsc->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
uv_edit_draw = memnew(Panel);
|
||||
uv_main_hsc->add_child(uv_edit_draw);
|
||||
uv_edit_draw->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
uv_edit_draw->set_custom_minimum_size(Size2(200, 200) * EDSCALE);
|
||||
|
||||
uv_edit_background = memnew(Panel);
|
||||
uv_main_hsc->add_child(uv_edit_background);
|
||||
uv_edit_background->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
uv_edit_background->set_custom_minimum_size(Size2(200, 200) * EDSCALE);
|
||||
uv_edit_background->set_clip_contents(true);
|
||||
|
||||
preview_polygon = memnew(Polygon2D);
|
||||
uv_edit_background->add_child(preview_polygon);
|
||||
|
||||
uv_edit_draw = memnew(Control);
|
||||
uv_edit_background->add_child(uv_edit_draw);
|
||||
uv_edit_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
|
||||
|
||||
Control *space = memnew(Control);
|
||||
uv_mode_hb->add_child(space);
|
||||
|
@ -1491,8 +1528,6 @@ Polygon2DEditor::Polygon2DEditor() {
|
|||
|
||||
error = memnew(AcceptDialog);
|
||||
add_child(error);
|
||||
|
||||
uv_edit_draw->set_clip_contents(true);
|
||||
}
|
||||
|
||||
Polygon2DEditorPlugin::Polygon2DEditorPlugin() :
|
||||
|
|
|
@ -82,7 +82,9 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
|
|||
Button *uv_button[UV_MODE_MAX];
|
||||
Button *b_snap_enable = nullptr;
|
||||
Button *b_snap_grid = nullptr;
|
||||
Panel *uv_edit_draw = nullptr;
|
||||
Panel *uv_edit_background = nullptr;
|
||||
Polygon2D *preview_polygon = nullptr;
|
||||
Control *uv_edit_draw = nullptr;
|
||||
HSlider *uv_zoom = nullptr;
|
||||
SpinBox *uv_zoom_value = nullptr;
|
||||
HScrollBar *uv_hscroll = nullptr;
|
||||
|
|
|
@ -421,7 +421,11 @@ ScriptEditor *ScriptEditor::script_editor = nullptr;
|
|||
|
||||
String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
|
||||
String val = EditorDebuggerNode::get_singleton()->get_var_value(p_text);
|
||||
const int display_limit = 300;
|
||||
if (!val.is_empty()) {
|
||||
if (val.size() > display_limit) {
|
||||
val = val.left(display_limit) + " [...] truncated!";
|
||||
}
|
||||
return p_text + ": " + val;
|
||||
} else {
|
||||
return String();
|
||||
|
|
|
@ -948,13 +948,16 @@ void SpriteFramesEditor::_animation_name_edited() {
|
|||
String name = new_name;
|
||||
int counter = 0;
|
||||
while (frames->has_animation(name)) {
|
||||
if (name == String(edited_anim)) {
|
||||
edited->set_text(0, name); // The name didn't change, just updated the column text to name.
|
||||
return;
|
||||
}
|
||||
counter++;
|
||||
name = new_name + "_" + itos(counter);
|
||||
}
|
||||
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Rename Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
|
||||
_rename_node_animation(undo_redo, false, edited_anim, "", "");
|
||||
undo_redo->add_do_method(frames.ptr(), "rename_animation", edited_anim, name);
|
||||
undo_redo->add_undo_method(frames.ptr(), "rename_animation", name, edited_anim);
|
||||
_rename_node_animation(undo_redo, false, edited_anim, name, name);
|
||||
|
|
|
@ -1099,7 +1099,7 @@ TextureRegionEditor::TextureRegionEditor() {
|
|||
snap_mode_button->add_item(TTR("Pixel Snap"), 1);
|
||||
snap_mode_button->add_item(TTR("Grid Snap"), 2);
|
||||
snap_mode_button->add_item(TTR("Auto Slice"), 3);
|
||||
snap_mode_button->select(0);
|
||||
snap_mode_button->select(snap_mode);
|
||||
snap_mode_button->connect("item_selected", callable_mp(this, &TextureRegionEditor::_set_snap_mode));
|
||||
|
||||
hb_grid = memnew(HBoxContainer);
|
||||
|
|
|
@ -1451,7 +1451,7 @@ const char *RenamesMap3To4::shaders_renames[][2] = {
|
|||
{ "NORMALMAP_DEPTH", "NORMAL_MAP_DEPTH" },
|
||||
{ "TRANSMISSION", "BACKLIGHT" },
|
||||
{ "WORLD_MATRIX", "MODEL_MATRIX" },
|
||||
{ "depth_draw_alpha_prepass", "depth_draw_opaque" },
|
||||
{ "depth_draw_alpha_prepass", "depth_prepass_alpha" },
|
||||
{ "hint_albedo", "source_color" },
|
||||
{ "hint_aniso", "hint_anisotropy" },
|
||||
{ "hint_black", "hint_default_black" },
|
||||
|
|
|
@ -1962,6 +1962,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
if (frame_delay == 0) {
|
||||
frame_delay = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), 0);
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
frame_delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
|
||||
|
|
13
methods.py
13
methods.py
|
@ -907,9 +907,16 @@ def generate_vs_project(env, original_args, project_name="godot"):
|
|||
defines=mono_defines,
|
||||
)
|
||||
|
||||
env["MSVSBUILDCOM"] = module_configs.build_commandline("scons")
|
||||
env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes")
|
||||
env["MSVSCLEANCOM"] = module_configs.build_commandline("scons --clean")
|
||||
scons_cmd = "scons"
|
||||
|
||||
path_to_venv = os.getenv("VIRTUAL_ENV")
|
||||
path_to_scons_exe = Path(str(path_to_venv)) / "Scripts" / "scons.exe"
|
||||
if path_to_venv and path_to_scons_exe.exists():
|
||||
scons_cmd = str(path_to_scons_exe)
|
||||
|
||||
env["MSVSBUILDCOM"] = module_configs.build_commandline(scons_cmd)
|
||||
env["MSVSREBUILDCOM"] = module_configs.build_commandline(f"{scons_cmd} vsproj=yes")
|
||||
env["MSVSCLEANCOM"] = module_configs.build_commandline(f"{scons_cmd} --clean")
|
||||
if not env.get("MSVS"):
|
||||
env["MSVS"]["PROJECTSUFFIX"] = ".vcxproj"
|
||||
env["MSVS"]["SOLUTIONSUFFIX"] = ".sln"
|
||||
|
|
|
@ -573,6 +573,11 @@ void CSGShape3D::_notification(int p_what) {
|
|||
// Update this node's parent only if its own visibility has changed, not the visibility of parent nodes
|
||||
parent_shape->_make_dirty();
|
||||
}
|
||||
if (is_visible()) {
|
||||
_update_debug_collision_shape();
|
||||
} else {
|
||||
_clear_debug_collision_shape();
|
||||
}
|
||||
last_visible = is_visible();
|
||||
} break;
|
||||
|
||||
|
|
|
@ -190,6 +190,9 @@ namespace GodotTools
|
|||
case ExternalEditorId.CustomEditor:
|
||||
{
|
||||
string file = ProjectSettings.GlobalizePath(script.ResourcePath);
|
||||
string project = ProjectSettings.GlobalizePath("res://");
|
||||
// Since ProjectSettings.GlobalizePath replaces only "res:/", leaving a trailing slash, it is removed here.
|
||||
project = project[..^1];
|
||||
var execCommand = _editorSettings.GetSetting(Settings.CustomExecPath).As<string>();
|
||||
var execArgs = _editorSettings.GetSetting(Settings.CustomExecPathArgs).As<string>();
|
||||
var args = new List<string>();
|
||||
|
@ -226,6 +229,7 @@ namespace GodotTools
|
|||
hasFileFlag = true;
|
||||
}
|
||||
|
||||
arg = arg.ReplaceN("{project}", project);
|
||||
arg = arg.ReplaceN("{file}", file);
|
||||
args.Add(arg);
|
||||
|
||||
|
|
|
@ -1116,6 +1116,7 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
|
|||
rvo_2d_vertices.reserve(_obstacle_vertices.size());
|
||||
|
||||
uint32_t _obstacle_avoidance_layers = obstacle->get_avoidance_layers();
|
||||
real_t _obstacle_height = obstacle->get_height();
|
||||
|
||||
for (const Vector3 &_obstacle_vertex : _obstacle_vertices) {
|
||||
rvo_2d_vertices.push_back(RVO2D::Vector2(_obstacle_vertex.x + _obstacle_position.x, _obstacle_vertex.z + _obstacle_position.z));
|
||||
|
@ -1126,6 +1127,9 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
|
|||
for (size_t i = 0; i < rvo_2d_vertices.size(); i++) {
|
||||
RVO2D::Obstacle2D *rvo_2d_obstacle = new RVO2D::Obstacle2D();
|
||||
rvo_2d_obstacle->point_ = rvo_2d_vertices[i];
|
||||
rvo_2d_obstacle->height_ = _obstacle_height;
|
||||
rvo_2d_obstacle->elevation_ = _obstacle_position.y;
|
||||
|
||||
rvo_2d_obstacle->avoidance_layers_ = _obstacle_avoidance_layers;
|
||||
|
||||
if (i != 0) {
|
||||
|
|
|
@ -28,6 +28,11 @@ elif env["platform"] == "linuxbsd":
|
|||
env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
|
||||
elif env["platform"] == "windows":
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
|
||||
elif env["platform"] == "macos":
|
||||
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_APPLE"])
|
||||
|
||||
# There does not seem to be a XR_USE_PLATFORM_XYZ for Apple
|
||||
|
||||
|
||||
# may need to check and set:
|
||||
# - XR_USE_TIMESPEC
|
||||
|
@ -96,7 +101,7 @@ if env["platform"] == "android":
|
|||
env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
|
||||
if env["vulkan"]:
|
||||
env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
|
||||
if env["opengl3"]:
|
||||
if env["opengl3"] and env["platform"] != "macos":
|
||||
env_openxr.add_source_files(module_obj, "extensions/openxr_opengl_extension.cpp")
|
||||
|
||||
env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
def can_build(env, platform):
|
||||
if platform in ("linuxbsd", "windows", "android"):
|
||||
if platform in ("linuxbsd", "windows", "android", "macos"):
|
||||
return env["openxr"] and not env["disable_3d"]
|
||||
else:
|
||||
# not supported on these platforms
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
#ifdef VULKAN_ENABLED
|
||||
#define XR_USE_GRAPHICS_API_VULKAN
|
||||
#endif
|
||||
#ifdef GLES3_ENABLED
|
||||
#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
|
||||
#ifdef ANDROID_ENABLED
|
||||
#define XR_USE_GRAPHICS_API_OPENGL_ES
|
||||
#include <EGL/egl.h>
|
||||
|
@ -72,7 +72,7 @@
|
|||
#include "extensions/openxr_vulkan_extension.h"
|
||||
#endif
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
|
||||
#include "extensions/openxr_opengl_extension.h"
|
||||
#endif
|
||||
|
||||
|
@ -1306,7 +1306,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
|
|||
ERR_FAIL_V(false);
|
||||
#endif
|
||||
} else if (p_rendering_driver == "opengl3") {
|
||||
#ifdef GLES3_ENABLED
|
||||
#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
|
||||
graphics_extension = memnew(OpenXROpenGLExtension);
|
||||
register_extension_wrapper(graphics_extension);
|
||||
#else
|
||||
|
|
|
@ -327,9 +327,9 @@ void AudioStreamPlaybackOggVorbis::seek(double p_time) {
|
|||
int64_t samples_to_burn = samples_in_page - (granule_pos - desired_sample);
|
||||
|
||||
if (samples_to_burn > samples_in_page) {
|
||||
WARN_PRINT("Burning more samples than we have in this page. Check seek algorithm.");
|
||||
WARN_PRINT_ONCE("Burning more samples than we have in this page. Check seek algorithm.");
|
||||
} else if (samples_to_burn < 0) {
|
||||
WARN_PRINT("Burning negative samples doesn't make sense. Check seek algorithm.");
|
||||
WARN_PRINT_ONCE("Burning negative samples doesn't make sense. Check seek algorithm.");
|
||||
}
|
||||
|
||||
// Seek again, this time we'll burn a specific number of samples instead of all of them.
|
||||
|
|
|
@ -72,7 +72,24 @@ Error ZIPPacker::start_file(String p_path) {
|
|||
zipfi.internal_fa = 0;
|
||||
zipfi.external_fa = 0;
|
||||
|
||||
int err = zipOpenNewFileInZip(zf, p_path.utf8().get_data(), &zipfi, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
|
||||
int err = zipOpenNewFileInZip4(zf,
|
||||
p_path.utf8().get_data(),
|
||||
&zipfi,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
Z_DEFLATED,
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
0,
|
||||
-MAX_WBITS,
|
||||
DEF_MEM_LEVEL,
|
||||
Z_DEFAULT_STRATEGY,
|
||||
nullptr,
|
||||
0,
|
||||
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions.
|
||||
1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
|
||||
return err == ZIP_OK ? OK : FAILED;
|
||||
}
|
||||
|
||||
|
|
|
@ -1531,18 +1531,32 @@ void EditorExportPlatformAndroid::_process_launcher_icons(const String &p_file_n
|
|||
String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
|
||||
bool scale_splash = GLOBAL_GET("application/boot_splash/fullsize");
|
||||
bool apply_filter = GLOBAL_GET("application/boot_splash/use_filter");
|
||||
bool show_splash_image = GLOBAL_GET("application/boot_splash/show_image");
|
||||
String project_splash_path = GLOBAL_GET("application/boot_splash/image");
|
||||
|
||||
if (!project_splash_path.is_empty()) {
|
||||
splash_image.instantiate();
|
||||
print_verbose("Loading splash image: " + project_splash_path);
|
||||
const Error err = ImageLoader::load_image(project_splash_path, splash_image);
|
||||
if (err) {
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
print_error("- unable to load splash image from " + project_splash_path + " (" + itos(err) + ")");
|
||||
// Setup the splash bg color.
|
||||
bool bg_color_valid = false;
|
||||
Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
|
||||
if (!bg_color_valid) {
|
||||
bg_color = boot_splash_bg_color;
|
||||
}
|
||||
|
||||
if (show_splash_image) {
|
||||
if (!project_splash_path.is_empty()) {
|
||||
splash_image.instantiate();
|
||||
print_verbose("Loading splash image: " + project_splash_path);
|
||||
const Error err = ImageLoader::load_image(project_splash_path, splash_image);
|
||||
if (err) {
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
print_error("- unable to load splash image from " + project_splash_path + " (" + itos(err) + ")");
|
||||
}
|
||||
splash_image.unref();
|
||||
}
|
||||
splash_image.unref();
|
||||
}
|
||||
} else {
|
||||
splash_image.instantiate();
|
||||
splash_image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
|
||||
splash_image->set_pixel(0, 0, bg_color);
|
||||
}
|
||||
|
||||
if (splash_image.is_null()) {
|
||||
|
@ -1566,13 +1580,6 @@ String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, R
|
|||
splash_image->resize(width, height);
|
||||
}
|
||||
|
||||
// Setup the splash bg color
|
||||
bool bg_color_valid;
|
||||
Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
|
||||
if (!bg_color_valid) {
|
||||
bg_color = boot_splash_bg_color;
|
||||
}
|
||||
|
||||
print_verbose("Creating splash background color image.");
|
||||
splash_bg_color_image.instantiate();
|
||||
splash_bg_color_image->initialize_data(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
|
||||
|
@ -1699,7 +1706,6 @@ void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPres
|
|||
Vector<ABI> abis = get_enabled_abis(p_preset);
|
||||
for (int i = 0; i < abis.size(); ++i) {
|
||||
r_features->push_back(abis[i].arch);
|
||||
r_features->push_back(abis[i].abi);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2933,10 +2939,13 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||
}
|
||||
}
|
||||
|
||||
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
|
||||
String build_project_output;
|
||||
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline, true, false, &build_project_output);
|
||||
if (result != 0) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Building of Android project failed, check output for the error. Alternatively visit docs.godotengine.org for Android build documentation."));
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Building of Android project failed, check output for the error:") + "\n\n" + build_project_output);
|
||||
return ERR_CANT_CREATE;
|
||||
} else {
|
||||
print_verbose(build_project_output);
|
||||
}
|
||||
|
||||
List<String> copy_args;
|
||||
|
@ -2963,10 +2972,13 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||
copy_args.push_back("-Pexport_filename=" + export_filename);
|
||||
|
||||
print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
|
||||
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
|
||||
String copy_binary_output;
|
||||
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args, true, false, ©_binary_output);
|
||||
if (copy_result != 0) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to copy and rename export file:") + "\n\n" + copy_binary_output);
|
||||
return ERR_CANT_CREATE;
|
||||
} else {
|
||||
print_verbose(copy_binary_output);
|
||||
}
|
||||
|
||||
print_verbose("Successfully completed Android gradle build.");
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
!/debug
|
|
@ -35,7 +35,7 @@
|
|||
<activity
|
||||
android:name=".GodotProjectManager"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:launchMode="singleInstance"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="userLandscape"
|
||||
android:exported="true"
|
||||
android:process=":GodotProjectManager">
|
||||
|
@ -53,7 +53,7 @@
|
|||
android:name=".GodotEditor"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:process=":GodotEditor"
|
||||
android:launchMode="singleInstance"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="userLandscape"
|
||||
android:exported="false">
|
||||
<layout android:defaultHeight="@dimen/editor_default_window_height"
|
||||
|
@ -65,7 +65,7 @@
|
|||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:process=":GodotGame"
|
||||
android:launchMode="singleInstance"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="false"
|
||||
android:screenOrientation="userLandscape">
|
||||
<layout android:defaultHeight="@dimen/editor_default_window_height"
|
||||
|
|
|
@ -82,11 +82,11 @@ void TTS_Linux::speech_init_thread_func(void *p_userdata) {
|
|||
void TTS_Linux::speech_event_index_mark(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type, char *p_index_mark) {
|
||||
TTS_Linux *tts = TTS_Linux::get_singleton();
|
||||
if (tts) {
|
||||
callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred(p_msg_id, p_client_id, (int)p_type, String::utf8(p_index_mark));
|
||||
callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred((int)p_msg_id, (int)p_type, String::utf8(p_index_mark));
|
||||
}
|
||||
}
|
||||
|
||||
void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark) {
|
||||
void TTS_Linux::_speech_index_mark(int p_msg_id, int p_type, const String &p_index_mark) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (ids.has(p_msg_id)) {
|
||||
|
@ -97,7 +97,7 @@ void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_ty
|
|||
void TTS_Linux::speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type) {
|
||||
TTS_Linux *tts = TTS_Linux::get_singleton();
|
||||
if (tts) {
|
||||
callable_mp(tts, &TTS_Linux::_speech_event).call_deferred(p_msg_id, p_client_id, (int)p_type);
|
||||
callable_mp(tts, &TTS_Linux::_speech_event).call_deferred((int)p_msg_id, (int)p_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ void TTS_Linux::_load_voices() {
|
|||
}
|
||||
}
|
||||
|
||||
void TTS_Linux::_speech_event(size_t p_msg_id, size_t p_client_id, int p_type) {
|
||||
void TTS_Linux::_speech_event(int p_msg_id, int p_type) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (!paused && ids.has(p_msg_id)) {
|
||||
|
@ -226,7 +226,7 @@ void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume,
|
|||
if (is_paused()) {
|
||||
resume();
|
||||
} else {
|
||||
_speech_event(0, 0, (int)SPD_EVENT_BEGIN);
|
||||
_speech_event(0, (int)SPD_EVENT_BEGIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ class TTS_Linux : public Object {
|
|||
|
||||
protected:
|
||||
void _load_voices();
|
||||
void _speech_event(size_t p_msg_id, size_t p_client_id, int p_type);
|
||||
void _speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark);
|
||||
void _speech_event(int p_msg_id, int p_type);
|
||||
void _speech_index_mark(int p_msg_id, int p_type, const String &p_index_mark);
|
||||
|
||||
public:
|
||||
static TTS_Linux *get_singleton();
|
||||
|
|
|
@ -1401,7 +1401,9 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
|
|||
SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
|
||||
restore_mouse_trails = 0;
|
||||
}
|
||||
} else if (p_mode == WINDOW_MODE_WINDOWED) {
|
||||
}
|
||||
|
||||
if (p_mode == WINDOW_MODE_WINDOWED) {
|
||||
ShowWindow(wd.hWnd, SW_RESTORE);
|
||||
wd.maximized = false;
|
||||
wd.minimized = false;
|
||||
|
|
|
@ -100,8 +100,8 @@ static bool nvapi_err_check(const char *msg, int status) {
|
|||
}
|
||||
|
||||
// On windows we have to disable threaded optimization when using NVIDIA graphics cards
|
||||
// to avoid stuttering, see https://github.com/microsoft/vscode-cpptools/issues/6592
|
||||
// also see https://github.com/Ryujinx/Ryujinx/blob/master/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
|
||||
// to avoid stuttering, see https://stackoverflow.com/questions/36959508/nvidia-graphics-driver-causing-noticeable-frame-stuttering/37632948
|
||||
// also see https://github.com/Ryujinx/Ryujinx/blob/master/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
|
||||
void GLManager_Windows::_nvapi_disable_threaded_optimization() {
|
||||
HMODULE nvapi = 0;
|
||||
#ifdef _WIN64
|
||||
|
@ -145,6 +145,10 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
|
|||
|
||||
NvDRSSessionHandle session_handle;
|
||||
|
||||
if (NvAPI_DRS_CreateSession == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nvapi_err_check("NVAPI: Error creating DRS session", NvAPI_DRS_CreateSession(&session_handle))) {
|
||||
NvAPI_Unload();
|
||||
return;
|
||||
|
|
|
@ -48,12 +48,14 @@ bool Bone2D::_set(const StringName &p_path, const Variant &p_value) {
|
|||
} else if (path.begins_with("default_length")) {
|
||||
set_length(p_value);
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (path.begins_with("editor_settings/show_bone_gizmo")) {
|
||||
else if (path.begins_with("editor_settings/show_bone_gizmo")) {
|
||||
_editor_set_show_bone_gizmo(p_value);
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -70,12 +72,14 @@ bool Bone2D::_get(const StringName &p_path, Variant &r_ret) const {
|
|||
} else if (path.begins_with("default_length")) {
|
||||
r_ret = get_length();
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (path.begins_with("editor_settings/show_bone_gizmo")) {
|
||||
else if (path.begins_with("editor_settings/show_bone_gizmo")) {
|
||||
r_ret = _editor_get_show_bone_gizmo();
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,26 @@ Ref<MultiMesh> MultiMeshInstance3D::get_multimesh() const {
|
|||
return multimesh;
|
||||
}
|
||||
|
||||
Array MultiMeshInstance3D::get_meshes() const {
|
||||
if (multimesh.is_null() || multimesh->get_mesh().is_null() || multimesh->get_transform_format() != MultiMesh::TransformFormat::TRANSFORM_3D) {
|
||||
return Array();
|
||||
}
|
||||
|
||||
int count = multimesh->get_visible_instance_count();
|
||||
if (count == -1) {
|
||||
count = multimesh->get_instance_count();
|
||||
}
|
||||
|
||||
Ref<Mesh> mesh = multimesh->get_mesh();
|
||||
|
||||
Array results;
|
||||
for (int i = 0; i < count; i++) {
|
||||
results.push_back(multimesh->get_instance_transform(i));
|
||||
results.push_back(mesh);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
AABB MultiMeshInstance3D::get_aabb() const {
|
||||
if (multimesh.is_null()) {
|
||||
return AABB();
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
void set_multimesh(const Ref<MultiMesh> &p_multimesh);
|
||||
Ref<MultiMesh> get_multimesh() const;
|
||||
|
||||
Array get_meshes() const;
|
||||
|
||||
virtual AABB get_aabb() const override;
|
||||
|
||||
MultiMeshInstance3D();
|
||||
|
|
|
@ -68,8 +68,9 @@ Color ReflectionProbe::get_ambient_color() const {
|
|||
}
|
||||
|
||||
void ReflectionProbe::set_max_distance(float p_distance) {
|
||||
max_distance = p_distance;
|
||||
RS::get_singleton()->reflection_probe_set_max_distance(probe, p_distance);
|
||||
max_distance = CLAMP(p_distance, 0.0, 262'144.0);
|
||||
// Reflection rendering breaks if distance exceeds 262,144 units (due to floating-point precision with the near plane being 0.01).
|
||||
RS::get_singleton()->reflection_probe_set_max_distance(probe, max_distance);
|
||||
}
|
||||
|
||||
float ReflectionProbe::get_max_distance() const {
|
||||
|
|
|
@ -314,9 +314,21 @@ Ref<CameraAttributes> VoxelGI::get_camera_attributes() const {
|
|||
return camera_attributes;
|
||||
}
|
||||
|
||||
static bool is_node_voxel_bakeable(Node3D *p_node) {
|
||||
if (!p_node->is_visible_in_tree()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeometryInstance3D *geometry = Object::cast_to<GeometryInstance3D>(p_node);
|
||||
if (geometry != nullptr && geometry->get_gi_mode() != GeometryInstance3D::GI_MODE_STATIC) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
|
||||
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
|
||||
if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) {
|
||||
if (mi && is_node_voxel_bakeable(mi)) {
|
||||
Ref<Mesh> mesh = mi->get_mesh();
|
||||
if (mesh.is_valid()) {
|
||||
AABB aabb = mesh->get_aabb();
|
||||
|
@ -338,8 +350,15 @@ void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
|
|||
|
||||
Node3D *s = Object::cast_to<Node3D>(p_at_node);
|
||||
if (s) {
|
||||
if (s->is_visible_in_tree()) {
|
||||
Array meshes = p_at_node->call("get_meshes");
|
||||
if (is_node_voxel_bakeable(s)) {
|
||||
Array meshes;
|
||||
MultiMeshInstance3D *multi_mesh = Object::cast_to<MultiMeshInstance3D>(p_at_node);
|
||||
if (multi_mesh) {
|
||||
meshes = multi_mesh->get_meshes();
|
||||
} else {
|
||||
meshes = p_at_node->call("get_meshes");
|
||||
}
|
||||
|
||||
for (int i = 0; i < meshes.size(); i += 2) {
|
||||
Transform3D mxf = meshes[i];
|
||||
Ref<Mesh> mesh = meshes[i + 1];
|
||||
|
|
|
@ -383,6 +383,8 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
|
|||
}
|
||||
|
||||
void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) {
|
||||
ERR_FAIL_COND_MSG(!p_xform.is_finite(), "Invalid mesh bake transform.");
|
||||
|
||||
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
||||
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
|
||||
continue; //only triangles
|
||||
|
|
|
@ -1443,11 +1443,11 @@ void ItemList::_check_shape_changed() {
|
|||
}
|
||||
}
|
||||
|
||||
for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) {
|
||||
items.write[j].rect_cache.size.y = max_h;
|
||||
}
|
||||
|
||||
if (all_fit) {
|
||||
for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) {
|
||||
items.write[j].rect_cache.size.y = max_h;
|
||||
}
|
||||
|
||||
float page = MAX(0, size.height - theme_cache.panel_style->get_minimum_size().height);
|
||||
float max = MAX(page, ofs.y + max_h);
|
||||
if (auto_height) {
|
||||
|
|
|
@ -1812,6 +1812,7 @@ void PopupMenu::scroll_to_item(int p_idx) {
|
|||
}
|
||||
|
||||
bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only) {
|
||||
ERR_FAIL_COND_V(p_event.is_null(), false);
|
||||
Key code = Key::NONE;
|
||||
Ref<InputEventKey> k = p_event;
|
||||
|
||||
|
|
|
@ -1659,7 +1659,7 @@ void RichTextLabel::_scroll_changed(double) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - vscroll->get_page())) {
|
||||
if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - Math::round(vscroll->get_page()))) {
|
||||
scroll_following = true;
|
||||
} else {
|
||||
scroll_following = false;
|
||||
|
|
|
@ -2939,15 +2939,17 @@ void TextEdit::_update_placeholder() {
|
|||
return; // Not in tree?
|
||||
}
|
||||
|
||||
const String placeholder_translated = atr(placeholder_text);
|
||||
|
||||
// Placeholder is generally smaller then text documents, and updates less so this should be fast enough for now.
|
||||
placeholder_data_buf->clear();
|
||||
placeholder_data_buf->set_width(text.get_width());
|
||||
placeholder_data_buf->set_break_flags(text.get_brk_flags());
|
||||
placeholder_data_buf->set_direction((TextServer::Direction)text_direction);
|
||||
placeholder_data_buf->set_preserve_control(draw_control_chars);
|
||||
placeholder_data_buf->add_string(placeholder_text, theme_cache.font, theme_cache.font_size, language);
|
||||
placeholder_data_buf->add_string(placeholder_translated, theme_cache.font, theme_cache.font_size, language);
|
||||
|
||||
placeholder_bidi_override = structured_text_parser(st_parser, st_args, placeholder_text);
|
||||
placeholder_bidi_override = structured_text_parser(st_parser, st_args, placeholder_translated);
|
||||
if (placeholder_bidi_override.is_empty()) {
|
||||
TS->shaped_text_set_bidi_override(placeholder_data_buf->get_rid(), placeholder_bidi_override);
|
||||
}
|
||||
|
@ -2972,7 +2974,7 @@ void TextEdit::_update_placeholder() {
|
|||
placeholder_wraped_rows.clear();
|
||||
for (int i = 0; i <= wrap_amount; i++) {
|
||||
Vector2i line_range = placeholder_data_buf->get_line_range(i);
|
||||
placeholder_wraped_rows.push_back(placeholder_text.substr(line_range.x, line_range.y - line_range.x));
|
||||
placeholder_wraped_rows.push_back(placeholder_translated.substr(line_range.x, line_range.y - line_range.x));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4131,6 +4133,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro
|
|||
int line = p_from_line;
|
||||
int pos = -1;
|
||||
|
||||
bool key_start_is_symbol = is_symbol(p_key[0]);
|
||||
bool key_end_is_symbol = is_symbol(p_key[p_key.length() - 1]);
|
||||
|
||||
for (int i = 0; i < text.size() + 1; i++) {
|
||||
if (line < 0) {
|
||||
line = text.size() - 1;
|
||||
|
@ -4194,9 +4199,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro
|
|||
|
||||
if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) {
|
||||
// Validate for whole words.
|
||||
if (pos > 0 && !is_symbol(text_line[pos - 1])) {
|
||||
if (!key_start_is_symbol && pos > 0 && !is_symbol(text_line[pos - 1])) {
|
||||
is_match = false;
|
||||
} else if (pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) {
|
||||
} else if (!key_end_is_symbol && pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) {
|
||||
is_match = false;
|
||||
}
|
||||
}
|
||||
|
@ -6990,6 +6995,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc
|
|||
p_from_column = 0;
|
||||
}
|
||||
|
||||
bool key_start_is_symbol = is_symbol(p_key[0]);
|
||||
bool key_end_is_symbol = is_symbol(p_key[p_key.length() - 1]);
|
||||
|
||||
while (col == -1 && p_from_column <= p_search.length()) {
|
||||
if (p_search_flags & SEARCH_MATCH_CASE) {
|
||||
col = p_search.find(p_key, p_from_column);
|
||||
|
@ -7001,9 +7009,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc
|
|||
if (col != -1 && p_search_flags & SEARCH_WHOLE_WORDS) {
|
||||
p_from_column = col;
|
||||
|
||||
if (col > 0 && !is_symbol(p_search[col - 1])) {
|
||||
if (!key_start_is_symbol && col > 0 && !is_symbol(p_search[col - 1])) {
|
||||
col = -1;
|
||||
} else if ((col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) {
|
||||
} else if (!key_end_is_symbol && (col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) {
|
||||
col = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,6 +224,12 @@ bool VideoStreamPlayer::has_expand() const {
|
|||
void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
|
||||
stop();
|
||||
|
||||
// Make sure to handle stream changes seamlessly, e.g. when done via
|
||||
// translation remapping.
|
||||
if (stream.is_valid()) {
|
||||
stream->disconnect("changed", callable_mp(this, &VideoStreamPlayer::set_stream));
|
||||
}
|
||||
|
||||
AudioServer::get_singleton()->lock();
|
||||
mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
|
||||
stream = p_stream;
|
||||
|
@ -235,6 +241,10 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
|
|||
}
|
||||
AudioServer::get_singleton()->unlock();
|
||||
|
||||
if (stream.is_valid()) {
|
||||
stream->connect("changed", callable_mp(this, &VideoStreamPlayer::set_stream).bind(stream));
|
||||
}
|
||||
|
||||
if (!playback.is_null()) {
|
||||
playback->set_paused(paused);
|
||||
texture = playback->get_texture();
|
||||
|
|
|
@ -2727,9 +2727,15 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
|
|||
copytarget = p_copy->get_node(ptarget);
|
||||
}
|
||||
|
||||
if (copy && copytarget) {
|
||||
const Callable copy_callable = Callable(copytarget, E.callable.get_method());
|
||||
if (copy && copytarget && E.callable.get_method() != StringName()) {
|
||||
Callable copy_callable = Callable(copytarget, E.callable.get_method());
|
||||
if (!copy->is_connected(E.signal.get_name(), copy_callable)) {
|
||||
int arg_count = E.callable.get_bound_arguments_count();
|
||||
if (arg_count > 0) {
|
||||
copy_callable = copy_callable.bindv(E.callable.get_bound_arguments());
|
||||
} else if (arg_count < 0) {
|
||||
copy_callable = copy_callable.unbind(-arg_count);
|
||||
}
|
||||
copy->connect(E.signal.get_name(), copy_callable, E.flags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ bool BoneMap::_set(const StringName &p_path, const Variant &p_value) {
|
|||
set_skeleton_bone_name(which, p_value);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const {
|
||||
|
@ -47,7 +47,7 @@ bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const {
|
|||
r_ret = get_skeleton_bone_name(which);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void BoneMap::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
|
|
|
@ -82,7 +82,7 @@ float FogMaterial::get_edge_fade() const {
|
|||
|
||||
void FogMaterial::set_density_texture(const Ref<Texture3D> &p_texture) {
|
||||
density_texture = p_texture;
|
||||
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
|
||||
Variant tex_rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
|
||||
RS::get_singleton()->material_set_param(_get_material(), "density_texture", tex_rid);
|
||||
}
|
||||
|
||||
|
|
|
@ -2973,14 +2973,19 @@ void SystemFont::_update_base_font() {
|
|||
continue;
|
||||
}
|
||||
|
||||
// If it's a font collection check all faces to match requested style.
|
||||
// If it's a font collection check all faces to match requested style and name.
|
||||
int best_score = 0;
|
||||
for (int i = 0; i < file->get_face_count(); i++) {
|
||||
int score = 0;
|
||||
file->set_face_index(0, i);
|
||||
const String n = file->get_font_name();
|
||||
if (n.to_upper() == E.to_upper()) {
|
||||
score += 80;
|
||||
}
|
||||
BitField<TextServer::FontStyle> style = file->get_font_style();
|
||||
int font_weight = file->get_font_weight();
|
||||
int font_stretch = file->get_font_stretch();
|
||||
int score = (20 - Math::abs(font_weight - weight) / 50);
|
||||
score += (20 - Math::abs(font_weight - weight) / 50);
|
||||
score += (20 - Math::abs(font_stretch - stretch) / 10);
|
||||
if (bool(style & TextServer::FONT_ITALIC) == italic) {
|
||||
score += 30;
|
||||
|
@ -2999,7 +3004,7 @@ void SystemFont::_update_base_font() {
|
|||
file->set_face_index(0, face_indeces[0]);
|
||||
|
||||
// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
|
||||
if (best_score != 50) {
|
||||
if (best_score != 150) {
|
||||
Dictionary ftr = file->get_supported_variation_list();
|
||||
if (ftr.has(TS->name_to_tag("width"))) {
|
||||
ftr_stretch = stretch;
|
||||
|
|
|
@ -971,7 +971,7 @@ Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Ref<MeshConvexDecompos
|
|||
if (found_vertex) {
|
||||
index = found_vertex->value;
|
||||
} else {
|
||||
index = ++vertex_count;
|
||||
index = vertex_count++;
|
||||
vertex_map[vertex] = index;
|
||||
vertex_w[index] = vertex;
|
||||
}
|
||||
|
|
|
@ -1914,7 +1914,7 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t
|
|||
ERR_FAIL_INDEX(p_param, TEXTURE_MAX);
|
||||
|
||||
textures[p_param] = p_texture;
|
||||
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
|
||||
Variant rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
|
||||
RS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid);
|
||||
|
||||
if (p_texture.is_valid() && p_param == TEXTURE_ALBEDO) {
|
||||
|
@ -3147,7 +3147,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
|
|||
{ "flags_use_shadow_to_opacity", "shadow_to_opacity" },
|
||||
{ "flags_no_depth_test", "no_depth_test" },
|
||||
{ "flags_use_point_size", "use_point_size" },
|
||||
{ "flags_fixed_size", "fixed_Size" },
|
||||
{ "flags_fixed_size", "fixed_size" },
|
||||
{ "flags_albedo_tex_force_srgb", "albedo_texture_force_srgb" },
|
||||
{ "flags_do_not_receive_shadows", "disable_receive_shadows" },
|
||||
{ "flags_disable_ambient_light", "disable_ambient_light" },
|
||||
|
|
|
@ -1684,7 +1684,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ArrayMesh::reset_state() {
|
||||
|
|
|
@ -89,7 +89,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
|||
}
|
||||
|
||||
int nc = nodes.size();
|
||||
ERR_FAIL_COND_V(nc == 0, nullptr);
|
||||
ERR_FAIL_COND_V_MSG(nc == 0, nullptr, vformat("Failed to instantiate scene state of \"%s\", node count is 0. Make sure the PackedScene resource is valid.", path));
|
||||
|
||||
const StringName *snames = nullptr;
|
||||
int sname_count = names.size();
|
||||
|
@ -170,7 +170,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
|||
Ref<PackedScene> sdata = props[n.instance & FLAG_MASK];
|
||||
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_NULL_V(node, nullptr);
|
||||
ERR_FAIL_NULL_V_MSG(node, nullptr, vformat("Failed to load scene dependency: \"%s\". Make sure the required scene is valid.", sdata->get_path()));
|
||||
}
|
||||
|
||||
} else if (n.type == TYPE_INSTANTIATED) {
|
||||
|
|
|
@ -1118,7 +1118,7 @@ void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref<Tex
|
|||
|
||||
tex_parameters[p_param] = p_texture;
|
||||
|
||||
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
|
||||
Variant tex_rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
|
||||
|
||||
switch (p_param) {
|
||||
case PARAM_INITIAL_LINEAR_VELOCITY: {
|
||||
|
@ -1201,7 +1201,7 @@ Color ParticleProcessMaterial::get_color() const {
|
|||
|
||||
void ParticleProcessMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
|
||||
color_ramp = p_texture;
|
||||
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
|
||||
Variant tex_rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
|
||||
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid);
|
||||
_queue_shader_change();
|
||||
notify_property_list_changed();
|
||||
|
@ -1213,7 +1213,7 @@ Ref<Texture2D> ParticleProcessMaterial::get_color_ramp() const {
|
|||
|
||||
void ParticleProcessMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) {
|
||||
color_initial_ramp = p_texture;
|
||||
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
|
||||
Variant tex_rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
|
||||
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, tex_rid);
|
||||
_queue_shader_change();
|
||||
notify_property_list_changed();
|
||||
|
@ -1256,19 +1256,19 @@ void ParticleProcessMaterial::set_emission_box_extents(Vector3 p_extents) {
|
|||
|
||||
void ParticleProcessMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) {
|
||||
emission_point_texture = p_points;
|
||||
RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID();
|
||||
Variant tex_rid = p_points.is_valid() ? Variant(p_points->get_rid()) : Variant();
|
||||
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid);
|
||||
}
|
||||
|
||||
void ParticleProcessMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) {
|
||||
emission_normal_texture = p_normals;
|
||||
RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID();
|
||||
Variant tex_rid = p_normals.is_valid() ? Variant(p_normals->get_rid()) : Variant();
|
||||
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid);
|
||||
}
|
||||
|
||||
void ParticleProcessMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) {
|
||||
emission_color_texture = p_colors;
|
||||
RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID();
|
||||
Variant tex_rid = p_colors.is_valid() ? Variant(p_colors->get_rid()) : Variant();
|
||||
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid);
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
|
|
@ -1301,7 +1301,11 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const {
|
|||
points.push_back(Vector3(-x, z, 0.0) + center_offset);
|
||||
}
|
||||
normals.push_back(normal);
|
||||
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
|
||||
if (orientation == FACE_X) {
|
||||
ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
|
||||
} else {
|
||||
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */
|
||||
point++;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue