diff options
148 files changed, 1523 insertions, 592 deletions
diff --git a/SConstruct b/SConstruct index 3734268cae..55b061a6f7 100644 --- a/SConstruct +++ b/SConstruct @@ -141,6 +141,7 @@ opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'releas opts.Add(EnumVariable('optimize', "Optimization type", 'speed', ('speed', 'size'))) opts.Add(BoolVariable('tools', "Build the tools (a.k.a. the Godot editor)", True)) opts.Add(BoolVariable('use_lto', 'Use link-time optimization', False)) +opts.Add(BoolVariable('use_precise_math_checks', 'Math checks use very precise epsilon (useful to debug the engine)', False)) # Components opts.Add(BoolVariable('deprecated', "Enable deprecated features", True)) @@ -224,6 +225,9 @@ env_base.Append(CPPPATH=['#editor', '#']) env_base.platform_exporters = platform_exporters env_base.platform_apis = platform_apis +if (env_base["use_precise_math_checks"]): + env_base.Append(CPPDEFINES=['PRECISE_MATH_CHECKS']) + if (env_base['target'] == 'debug'): env_base.Append(CPPDEFINES=['DEBUG_MEMORY_ALLOC','DISABLE_FORCED_INLINE']) @@ -335,19 +339,19 @@ if selected_platform in platform_list: if (env["werror"]): env.Append(CCFLAGS=['/WX']) else: # Rest of the world - disable_nonessential_warnings = ['-Wno-sign-compare'] shadow_local_warning = [] + all_plus_warnings = ['-Wwrite-strings'] - if 'gcc' in os.path.basename(env["CC"]): + if methods.use_gcc(env): version = methods.get_compiler_version(env) if version != None and version[0] >= '7': shadow_local_warning = ['-Wshadow-local'] if (env["warnings"] == 'extra'): - env.Append(CCFLAGS=['-Wall', '-Wextra'] + shadow_local_warning) + env.Append(CCFLAGS=['-Wall', '-Wextra'] + all_plus_warnings + shadow_local_warning) elif (env["warnings"] == 'all'): - env.Append(CCFLAGS=['-Wall'] + shadow_local_warning + disable_nonessential_warnings) + env.Append(CCFLAGS=['-Wall'] + shadow_local_warning) elif (env["warnings"] == 'moderate'): - env.Append(CCFLAGS=['-Wall', '-Wno-unused'] + shadow_local_warning + disable_nonessential_warnings) + env.Append(CCFLAGS=['-Wall', '-Wno-unused'] + shadow_local_warning) else: # 'no' env.Append(CCFLAGS=['-w']) if (env["werror"]): diff --git a/core/io/logger.h b/core/io/logger.h index 0b871a13de..ff5b8ce489 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -49,11 +49,11 @@ public: ERR_SHADER }; - virtual void logv(const char *p_format, va_list p_list, bool p_err) = 0; + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0; virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); - void logf(const char *p_format, ...); - void logf_error(const char *p_format, ...); + void logf(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; + void logf_error(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; virtual ~Logger(); }; @@ -64,7 +64,7 @@ public: class StdLogger : public Logger { public: - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual ~StdLogger(); }; @@ -88,7 +88,7 @@ class RotatedFileLogger : public Logger { public: RotatedFileLogger(const String &p_base_path, int p_max_files = 10); - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual ~RotatedFileLogger(); }; @@ -99,7 +99,7 @@ class CompositeLogger : public Logger { public: CompositeLogger(Vector<Logger *> p_loggers); - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); void add_logger(Logger *p_logger); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 3aa1fcfd8f..d7bfdbbb37 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -224,7 +224,7 @@ Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) uint32_t len = decode_uint32(lbuf); ERR_FAIL_COND_V(remaining < (int)len, ERR_UNAVAILABLE); - ERR_FAIL_COND_V(input_buffer.size() < len, ERR_UNAVAILABLE); + ERR_FAIL_COND_V(input_buffer.size() < (int)len, ERR_UNAVAILABLE); ring_buffer.read(lbuf, 4); //get rid of first 4 bytes ring_buffer.read(input_buffer.ptrw(), len); // read packet diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 6c48942d72..42070cd132 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -106,7 +106,7 @@ StringName ResourceInteractiveLoaderBinary::_get_string() { uint32_t id = f->get_32(); if (id & 0x80000000) { uint32_t len = id & 0x7FFFFFFF; - if (len > str_buf.size()) { + if ((int)len > str_buf.size()) { str_buf.resize(len); } if (len == 0) diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 9327e000f5..69907a710a 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -33,6 +33,10 @@ #include "core/os/os.h" #include "core/variant_parser.h" +bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const { + return p_a->get_importer_name() < p_b->get_importer_name(); +} + Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const { Error err; @@ -90,6 +94,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy r_path_and_type.type = value; } else if (assign == "importer") { r_path_and_type.importer = value; + } else if (assign == "metadata") { + r_path_and_type.metadata = value; } else if (assign == "valid") { if (r_valid) { *r_valid = value; @@ -304,6 +310,18 @@ String ResourceFormatImporter::get_resource_type(const String &p_path) const { return pat.type; } +Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) const { + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + return Variant(); + } + + return pat.metadata; +} + void ResourceFormatImporter::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { PathAndType pat; @@ -366,6 +384,40 @@ String ResourceFormatImporter::get_import_base_path(const String &p_for_file) co return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text(); } +bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const { + + bool valid = true; + PathAndType pat; + _get_path_and_type(p_path, pat, &valid); + + if (!valid) { + return false; + } + + for (int i = 0; i < importers.size(); i++) { + if (importers[i]->get_importer_name() == pat.importer) { + if (!importers[i]->are_import_settings_valid(p_path)) { //importer thinks this is not valid + return false; + } + } + } + + return true; +} + +String ResourceFormatImporter::get_import_settings_hash() const { + + Vector<Ref<ResourceImporter> > sorted_importers = importers; + + sorted_importers.sort_custom<SortImporterByName>(); + + String hash; + for (int i = 0; i < sorted_importers.size(); i++) { + hash += ":" + sorted_importers[i]->get_importer_name() + ":" + sorted_importers[i]->get_import_settings_string(); + } + return hash.md5_text(); +} + ResourceFormatImporter *ResourceFormatImporter::singleton = NULL; ResourceFormatImporter::ResourceFormatImporter() { diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 32c39a8085..1d27d4dec3 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -43,12 +43,18 @@ class ResourceFormatImporter : public ResourceFormatLoader { String path; String type; String importer; + Variant metadata; }; Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = NULL) const; static ResourceFormatImporter *singleton; + //need them to stay in order to compute the settings hash + struct SortImporterByName { + bool operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const; + }; + Vector<Ref<ResourceImporter> > importers; public: @@ -59,6 +65,7 @@ public: virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; + virtual Variant get_resource_metadata(const String &p_path) const; virtual bool is_import_valid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); @@ -68,12 +75,17 @@ public: String get_internal_resource_path(const String &p_path) const; void get_internal_resource_path_list(const String &p_path, List<String> *r_paths); - void add_importer(const Ref<ResourceImporter> &p_importer) { importers.push_back(p_importer); } + void add_importer(const Ref<ResourceImporter> &p_importer) { + importers.push_back(p_importer); + } void remove_importer(const Ref<ResourceImporter> &p_importer) { importers.erase(p_importer); } Ref<ResourceImporter> get_importer_by_name(const String &p_name) const; Ref<ResourceImporter> get_importer_by_extension(const String &p_extension) const; void get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter> > *r_importers); + bool are_import_settings_valid(const String &p_path) const; + String get_import_settings_hash() const; + String get_import_base_path(const String &p_for_file) const; ResourceFormatImporter(); }; @@ -107,7 +119,9 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const = 0; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const = 0; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL) = 0; + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL) = 0; + virtual bool are_import_settings_valid(const String &p_path) const { return true; } + virtual String get_import_settings_string() const { return String(); } }; #endif // RESOURCE_IMPORTER_H diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 7f60b7962c..8816e3639a 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -76,9 +76,11 @@ void Basis::invert() { } void Basis::orthonormalize() { + #ifdef MATH_CHECKS ERR_FAIL_COND(determinant() == 0); #endif + // Gram-Schmidt Process Vector3 x = get_axis(0); @@ -118,16 +120,16 @@ bool Basis::is_diagonal() const { } bool Basis::is_rotation() const { - return Math::is_equal_approx(determinant(), 1) && is_orthogonal(); + return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal(); } bool Basis::is_symmetric() const { - if (!Math::is_equal_approx(elements[0][1], elements[1][0])) + if (!Math::is_equal_approx_ratio(elements[0][1], elements[1][0], UNIT_EPSILON)) return false; - if (!Math::is_equal_approx(elements[0][2], elements[2][0])) + if (!Math::is_equal_approx_ratio(elements[0][2], elements[2][0], UNIT_EPSILON)) return false; - if (!Math::is_equal_approx(elements[1][2], elements[2][1])) + if (!Math::is_equal_approx_ratio(elements[1][2], elements[2][1], UNIT_EPSILON)) return false; return true; @@ -488,6 +490,11 @@ void Basis::set_euler_xyz(const Vector3 &p_euler) { // as the x, y, and z components of a Vector3 respectively. Vector3 Basis::get_euler_yxz() const { + /* checking this is a bad idea, because obtaining from scaled transform is a valid use case +#ifdef MATH_CHECKS + ERR_FAIL_COND(!is_rotation()); +#endif +*/ // Euler angles in YXZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -496,9 +503,7 @@ Vector3 Basis::get_euler_yxz() const { // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx Vector3 euler; -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), euler); -#endif + real_t m12 = elements[1][2]; if (m12 < 1) { @@ -556,7 +561,7 @@ bool Basis::is_equal_approx(const Basis &a, const Basis &b) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j])) + if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], UNIT_EPSILON)) return false; } } @@ -599,10 +604,14 @@ Basis::operator String() const { } Quat Basis::get_quat() const { -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), Quat()); -#endif - real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; + + /* Allow getting a quaternion from an unnormalized transform */ + Basis m = *this; + m.elements[0].normalize(); + m.elements[1].normalize(); + m.elements[2].normalize(); + + real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2]; real_t temp[4]; if (trace > 0.0) { @@ -610,23 +619,23 @@ Quat Basis::get_quat() const { temp[3] = (s * 0.5); s = 0.5 / s; - temp[0] = ((elements[2][1] - elements[1][2]) * s); - temp[1] = ((elements[0][2] - elements[2][0]) * s); - temp[2] = ((elements[1][0] - elements[0][1]) * s); + temp[0] = ((m.elements[2][1] - m.elements[1][2]) * s); + temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s); + temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s); } else { - int i = elements[0][0] < elements[1][1] ? - (elements[1][1] < elements[2][2] ? 2 : 1) : - (elements[0][0] < elements[2][2] ? 2 : 0); + int i = m.elements[0][0] < m.elements[1][1] ? + (m.elements[1][1] < m.elements[2][2] ? 2 : 1) : + (m.elements[0][0] < m.elements[2][2] ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; - real_t s = Math::sqrt(elements[i][i] - elements[j][j] - elements[k][k] + 1.0); + real_t s = Math::sqrt(m.elements[i][i] - m.elements[j][j] - m.elements[k][k] + 1.0); temp[i] = s * 0.5; s = 0.5 / s; - temp[3] = (elements[k][j] - elements[j][k]) * s; - temp[j] = (elements[j][i] + elements[i][j]) * s; - temp[k] = (elements[k][i] + elements[i][k]) * s; + temp[3] = (m.elements[k][j] - m.elements[j][k]) * s; + temp[j] = (m.elements[j][i] + m.elements[i][j]) * s; + temp[k] = (m.elements[k][i] + m.elements[i][k]) * s; } return Quat(temp[0], temp[1], temp[2], temp[3]); @@ -696,9 +705,11 @@ void Basis::set_orthogonal_index(int p_index) { } void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { + /* checking this is a bad idea, because obtaining from scaled transform is a valid use case #ifdef MATH_CHECKS ERR_FAIL_COND(!is_rotation()); #endif +*/ real_t angle, x, y, z; // variables for result real_t epsilon = 0.01; // margin to allow for rounding errors real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees @@ -835,14 +846,15 @@ void Basis::set_diagonal(const Vector3 p_diag) { } Basis Basis::slerp(const Basis &target, const real_t &t) const { -// TODO: implement this directly without using quaternions to make it more efficient -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), Basis()); - ERR_FAIL_COND_V(!target.is_rotation(), Basis()); -#endif + //consider scale Quat from(*this); Quat to(target); - return Basis(from.slerp(to, t)); + Basis b(from.slerp(to, t)); + b.elements[0] *= Math::lerp(elements[0].length(), target.elements[0].length(), t); + b.elements[1] *= Math::lerp(elements[1].length(), target.elements[1].length(), t); + b.elements[2] *= Math::lerp(elements[2].length(), target.elements[2].length(), t); + + return b; } diff --git a/core/math/math_defs.h b/core/math/math_defs.h index 48533ba659..c54d3cc96f 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -33,6 +33,7 @@ #define CMP_EPSILON 0.00001 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON) + #define CMP_NORMALIZE_TOLERANCE 0.000001 #define CMP_POINT_IN_PLANE_EPSILON 0.00001 @@ -49,6 +50,14 @@ #define MATH_CHECKS #endif +//this epsilon is for values related to a unit size (scalar or vector len) +#ifdef PRECISE_MATH_CHECKS +#define UNIT_EPSILON 0.00001 +#else +//tolerate some more floating point error normally +#define UNIT_EPSILON 0.001 +#endif + #define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0) enum ClockDirection { diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index f8f5ddfeaa..17112d8940 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -217,8 +217,8 @@ public: static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } - static _ALWAYS_INLINE_ int wrapi(int value, int min, int max) { - int rng = max - min; + static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) { + int64_t rng = max - min; return (rng != 0) ? min + ((((value - min) % rng) + rng) % rng) : min; } static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { @@ -249,13 +249,25 @@ public: static float random(float from, float to); static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); } - static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) { + static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON) { + // this is an approximate way to check that numbers are close, as a ratio of their average size + // helps compare approximate numbers that may be very big or very small + real_t diff = abs(a - b); + if (diff == 0.0) { + return true; + } + real_t avg_size = (abs(a) + abs(b)) / 2.0; + diff /= avg_size; + return diff < epsilon; + } + + static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) { // TODO: Comparing floats for approximate-equality is non-trivial. // Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators. // A proper implementation in terms of ULPs should eventually replace the contents of this function. // See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details. - return abs(a - b) < CMP_EPSILON; + return abs(a - b) < epsilon; } static _ALWAYS_INLINE_ float absf(float g) { diff --git a/core/math/quat.cpp b/core/math/quat.cpp index 6833d5de55..1a67be7384 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -135,7 +135,7 @@ Quat Quat::normalized() const { } bool Quat::is_normalized() const { - return Math::is_equal_approx(length_squared(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon } Quat Quat::inverse() const { diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index e580057950..5c1ea5943d 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -65,7 +65,7 @@ Vector2 Vector2::normalized() const { bool Vector2::is_normalized() const { // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); } real_t Vector2::distance_to(const Vector2 &p_vector2) const { diff --git a/core/math/vector3.h b/core/math/vector3.h index 8d6e093c4c..b11838d16e 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -414,7 +414,7 @@ Vector3 Vector3::normalized() const { bool Vector3::is_normalized() const { // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0); + return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); } Vector3 Vector3::inverse() const { diff --git a/core/os/os.cpp b/core/os/os.cpp index d2d39d253a..03e63f636e 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -569,6 +569,11 @@ int OS::get_power_percent_left() { return -1; } +void OS::set_has_server_feature_callback(HasServerFeatureCallback p_callback) { + + has_server_feature_callback = p_callback; +} + bool OS::has_feature(const String &p_feature) { if (p_feature == get_name()) @@ -625,6 +630,10 @@ bool OS::has_feature(const String &p_feature) { if (_check_internal_feature_support(p_feature)) return true; + if (has_server_feature_callback && has_server_feature_callback(p_feature)) { + return true; + } + if (ProjectSettings::get_singleton()->has_custom_feature(p_feature)) return true; @@ -729,6 +738,8 @@ OS::OS() { _logger = NULL; + has_server_feature_callback = NULL; + Vector<Logger *> loggers; loggers.push_back(memnew(StdLogger)); _set_logger(memnew(CompositeLogger(loggers))); diff --git a/core/os/os.h b/core/os/os.h index 396555970a..d6541034fd 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -77,6 +77,7 @@ protected: public: typedef void (*ImeCallback)(void *p_inp, String p_text, Point2 p_selection); + typedef bool (*HasServerFeatureCallback)(const String &p_feature); enum PowerState { POWERSTATE_UNKNOWN, /**< cannot determine power status */ @@ -121,6 +122,7 @@ public: protected: friend class Main; + HasServerFeatureCallback has_server_feature_callback; RenderThreadMode _render_thread_mode; // functions used by main to initialize/deinitialize the OS @@ -146,8 +148,8 @@ public: static OS *get_singleton(); void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR); - void print(const char *p_format, ...); - void printerr(const char *p_format, ...); + void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; + void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0; virtual String get_stdin_string(bool p_block = true) = 0; @@ -507,6 +509,8 @@ public: virtual void force_process_input(){}; bool has_feature(const String &p_feature); + void set_has_server_feature_callback(HasServerFeatureCallback p_callback); + bool is_layered_allowed() const { return _allow_layered; } bool is_hidpi_allowed() const { return _allow_hidpi; } diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 9780cc48ea..3ed25f118d 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -1054,7 +1054,6 @@ void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p physics_frame_time = p_physics_frame_time; } - ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func = NULL; ScriptDebuggerRemote::ScriptDebuggerRemote() : diff --git a/core/typedefs.h b/core/typedefs.h index e01e1c00b9..966360d4f2 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -307,4 +307,12 @@ struct _GlobalLock { #define unlikely(x) x #endif +#if defined(__GNUC__) +#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0))) +#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3))) +#else +#define _PRINTF_FORMAT_ATTRIBUTE_2_0 +#define _PRINTF_FORMAT_ATTRIBUTE_2_3 +#endif + #endif // TYPEDEFS_H diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 40ccd95758..00894b41d8 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -63,37 +63,43 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { _discard_redo(); // Check if the merge operation is valid - if (p_mode == MERGE_ENDS && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].last_tick + 800 > ticks) { + if (p_mode != MERGE_DISABLE && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].last_tick + 800 > ticks) { current_action = actions.size() - 2; - // Clear all do ops from last action, and delete all object references - List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); + if (p_mode == MERGE_ENDS) { - while (E) { + // Clear all do ops from last action, and delete all object references + List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); - if (E->get().type == Operation::TYPE_REFERENCE) { + while (E) { - Object *obj = ObjectDB::get_instance(E->get().object); + if (E->get().type == Operation::TYPE_REFERENCE) { - if (obj) - memdelete(obj); - } + Object *obj = ObjectDB::get_instance(E->get().object); + + if (obj) + memdelete(obj); + } - E = E->next(); - actions.write[current_action + 1].do_ops.pop_front(); + E = E->next(); + actions.write[current_action + 1].do_ops.pop_front(); + } } actions.write[actions.size() - 1].last_tick = ticks; + + merge_mode = p_mode; + } else { Action new_action; new_action.name = p_name; new_action.last_tick = ticks; actions.push_back(new_action); - } - merge_mode = p_mode; + merge_mode = MERGE_DISABLE; + } } action_level++; diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 9d68102952..21aba282ee 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -30,7 +30,7 @@ <argument index="0" name="delta" type="float"> </argument> <description> - Shifts position in the animation timeline. Delta is the time in seconds to shift. + Shifts position in the animation timeline. Delta is the time in seconds to shift. Events between the current frame and [code]delta[/code] are handled. </description> </method> <method name="animation_get_next" qualifiers="const"> @@ -197,7 +197,7 @@ <argument index="1" name="update" type="bool" default="false"> </argument> <description> - Seek the animation to the [code]seconds[/code] point in time (in seconds). If [code]update[/code] is [code]true[/code], the animation updates too, otherwise it updates at process time. + Seek the animation to the [code]seconds[/code] point in time (in seconds). If [code]update[/code] is [code]true[/code], the animation updates too, otherwise it updates at process time. Events between the current frame and [code]seconds[/code] are skipped. </description> </method> <method name="set_blend_time"> diff --git a/doc/classes/AnimationTreePlayer.xml b/doc/classes/AnimationTreePlayer.xml index b0b58fc7bd..cfec75bc3a 100644 --- a/doc/classes/AnimationTreePlayer.xml +++ b/doc/classes/AnimationTreePlayer.xml @@ -29,7 +29,7 @@ <argument index="0" name="delta" type="float"> </argument> <description> - Shifts position in the animation timeline. Delta is the time in seconds to shift. + Shifts position in the animation timeline. Delta is the time in seconds to shift. Events between the current frame and [code]delta[/code] are handled. </description> </method> <method name="animation_node_get_animation" qualifiers="const"> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 6bd0ef3421..0b5c0eb0b3 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -4,7 +4,7 @@ Generic array datatype. </brief_description> <description> - Generic array, contains several elements of any type, accessible by a numerical index starting at 0. Negative indices can be used to count from the back, like in Python (-1 is the last element, -2 the second to last, etc.). Example: + Generic array which can contain several elements of any type, accessible by a numerical index starting at 0. Negative indices can be used to count from the back, like in Python (-1 is the last element, -2 the second to last, etc.). Example: [codeblock] var array = ["One", 2, 3, "Four"] print(array[0]) # One @@ -26,7 +26,7 @@ <argument index="0" name="from" type="PoolColorArray"> </argument> <description> - Construct an array from a [PoolColorArray]. + Constructs an array from a [PoolColorArray]. </description> </method> <method name="Array"> @@ -35,7 +35,7 @@ <argument index="0" name="from" type="PoolVector3Array"> </argument> <description> - Construct an array from a [PoolVector3Array]. + Constructs an array from a [PoolVector3Array]. </description> </method> <method name="Array"> @@ -44,7 +44,7 @@ <argument index="0" name="from" type="PoolVector2Array"> </argument> <description> - Construct an array from a [PoolVector2Array]. + Constructs an array from a [PoolVector2Array]. </description> </method> <method name="Array"> @@ -53,7 +53,7 @@ <argument index="0" name="from" type="PoolStringArray"> </argument> <description> - Construct an array from a [PoolStringArray]. + Constructs an array from a [PoolStringArray]. </description> </method> <method name="Array"> @@ -62,7 +62,7 @@ <argument index="0" name="from" type="PoolRealArray"> </argument> <description> - Construct an array from a [PoolRealArray]. + Constructs an array from a [PoolRealArray]. </description> </method> <method name="Array"> @@ -71,7 +71,7 @@ <argument index="0" name="from" type="PoolIntArray"> </argument> <description> - Construct an array from a [PoolIntArray]. + Constructs an array from a [PoolIntArray]. </description> </method> <method name="Array"> @@ -80,21 +80,21 @@ <argument index="0" name="from" type="PoolByteArray"> </argument> <description> - Construct an array from a [PoolByteArray]. + Constructs an array from a [PoolByteArray]. </description> </method> <method name="append"> <argument index="0" name="value" type="Variant"> </argument> <description> - Append an element at the end of the array (alias of [method push_back]). + Appends an element at the end of the array (alias of [method push_back]). </description> </method> <method name="back"> <return type="Variant"> </return> <description> - Returns the last element of the array if the array is not empty (size>0). + Returns the last element of the array if the array is not empty. </description> </method> <method name="bsearch"> @@ -125,7 +125,7 @@ </method> <method name="clear"> <description> - Clear the array (resize to 0). + Clears the array (resizes to 0). </description> </method> <method name="count"> @@ -134,7 +134,7 @@ <argument index="0" name="value" type="Variant"> </argument> <description> - Return the amount of times an element is in the array. + Returns the number of times an element is in the array. </description> </method> <method name="duplicate"> @@ -144,21 +144,21 @@ </argument> <description> Returns a copy of the array. - If [code]deep[/code] is [code]true[/code], a deep copy is be performed: all nested arrays and dictionaries are duplicated and will not be shared with the original array. If [code]false[/code], a shallow copy is made and references to the original nested arrays and dictionaries are kept, so that modifying a sub-array or dictionary in the copy will also impact those referenced in the source array. + If [code]deep[/code] is [code]true[/code], a deep copy is performed: all nested arrays and dictionaries are duplicated and will not be shared with the original array. If [code]false[/code], a shallow copy is made and references to the original nested arrays and dictionaries are kept, so that modifying a sub-array or dictionary in the copy will also impact those referenced in the source array. </description> </method> <method name="empty"> <return type="bool"> </return> <description> - Return true if the array is empty (size==0). + Returns [code]true[/code] if the array is empty. </description> </method> <method name="erase"> <argument index="0" name="value" type="Variant"> </argument> <description> - Remove the first occurrence of a value from the array. + Removes the first occurrence of a value from the array. </description> </method> <method name="find"> @@ -185,7 +185,7 @@ <return type="Variant"> </return> <description> - Returns the first element of the array if the array is not empty (size>0). + Returns the first element of the array if the array is not empty. </description> </method> <method name="has"> @@ -194,7 +194,7 @@ <argument index="0" name="value" type="Variant"> </argument> <description> - Return true if the array contains given value. + Returns [code]true[/code] if the array contains the given value. [codeblock] ["inside", 7].has("inside") == true ["inside", 7].has("outside") == false @@ -207,7 +207,7 @@ <return type="int"> </return> <description> - Return a hashed integer value representing the array contents. + Returns a hashed integer value representing the array contents. </description> </method> <method name="insert"> @@ -216,68 +216,68 @@ <argument index="1" name="value" type="Variant"> </argument> <description> - Insert a new element at a given position in the array. The position must be valid, or at the end of the array ([code]pos == size()[/code]). + Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]pos == size()[/code]). </description> </method> <method name="invert"> <description> - Reverse the order of the elements in the array. + Reverses the order of the elements in the array. </description> </method> <method name="max"> <return type="Variant"> </return> <description> - Return maximum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned. + Returns the maximum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned. </description> </method> <method name="min"> <return type="Variant"> </return> <description> - Return minimum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned. + Returns the minimum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned. </description> </method> <method name="pop_back"> <return type="Variant"> </return> <description> - Remove the last element of the array. + Removes the last element of the array. </description> </method> <method name="pop_front"> <return type="Variant"> </return> <description> - Remove the first element of the array. + Removes the first element of the array. </description> </method> <method name="push_back"> <argument index="0" name="value" type="Variant"> </argument> <description> - Append an element at the end of the array. + Appends an element at the end of the array. </description> </method> <method name="push_front"> <argument index="0" name="value" type="Variant"> </argument> <description> - Add an element at the beginning of the array. + Adds an element at the beginning of the array. </description> </method> <method name="remove"> <argument index="0" name="position" type="int"> </argument> <description> - Remove an element from the array by index. + Removes an element from the array by index. </description> </method> <method name="resize"> <argument index="0" name="size" type="int"> </argument> <description> - Resize the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are Null. + Resizes the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are Null. </description> </method> <method name="rfind"> @@ -293,19 +293,19 @@ </method> <method name="shuffle"> <description> - Shuffle the array such that the items will have a random order. + Shuffles the array such that the items will have a random order. </description> </method> <method name="size"> <return type="int"> </return> <description> - Return the amount of elements in the array. + Returns the number of elements in the array. </description> </method> <method name="sort"> <description> - Sort the array using natural order. + Sorts the array. Note: strings are sorted in alphabetical, not natural order. </description> </method> <method name="sort_custom"> @@ -314,7 +314,7 @@ <argument index="1" name="func" type="String"> </argument> <description> - Sort the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return true if the first argument is less than the second, and return false otherwise. + Sorts the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return true if the first argument is less than the second, and return false otherwise. [b]Note:[/b] you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior. [codeblock] class MyCustomSorter: diff --git a/doc/classes/EditorSpatialGizmo.xml b/doc/classes/EditorSpatialGizmo.xml index 45b92276f1..0bec11e183 100644 --- a/doc/classes/EditorSpatialGizmo.xml +++ b/doc/classes/EditorSpatialGizmo.xml @@ -66,6 +66,8 @@ </argument> <argument index="2" name="skeleton" type="RID"> </argument> + <argument index="3" name="material" type="Material" default="null"> + </argument> <description> </description> </method> diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index b8808b8b53..d947784676 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -96,7 +96,7 @@ "string" - major + minor + patch + status + build in a single String The "hex" value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. Note that it's still an int internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for easy version comparisons from code: [codeblock] - if Engine.get_version_info().hex >= 0x030200: + if Engine.get_version_info().hex >= 0x030200: # do things specific to version 3.2 or later else: # do things specific to versions before 3.2 diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 565e19c229..0cc9764e36 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -65,6 +65,7 @@ </argument> <description> Set the color of a specific instance. + For the color to take effect, ensure that [member color_format] is non-[code]null[/code] on the [code]MultiMesh[/code] and [member SpatialMaterial.vertex_color_use_as_albedo] is [code]true[/code] on the material. </description> </method> <method name="set_instance_custom_data"> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index f39d221d89..7e696badb2 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -64,6 +64,13 @@ </argument> <description> Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this SceneTree. If [code]pause_mode_process[/code] is set to false, pausing the SceneTree will also pause the timer. + Commonly used to create a one-shot delay timer as in the following example: + [codeblock] + func some_function(): + print("start") + yield(get_tree().create_timer(1.0), "timeout") + print("end") + [/codeblock] </description> </method> <method name="get_frame" qualifiers="const"> diff --git a/doc/classes/SceneTreeTimer.xml b/doc/classes/SceneTreeTimer.xml index e1234ce88a..f58c531ed5 100644 --- a/doc/classes/SceneTreeTimer.xml +++ b/doc/classes/SceneTreeTimer.xml @@ -1,8 +1,17 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="SceneTreeTimer" inherits="Reference" category="Core" version="3.1"> <brief_description> + One-shot timer. </brief_description> <description> + A one-shot timer managed by the scene tree, which emits [signal timeout] on completion. See also [method SceneTree.create_timer]. + As opposed to [Timer], it does not require the instantiation of a node. Commonly used to create a one-shot delay timer as in the following example: + [codeblock] + func some_function(): + print("start") + yield(get_tree().create_timer(1.0), "timeout") + print("end") + [/codeblock] </description> <tutorials> </tutorials> @@ -12,11 +21,13 @@ </methods> <members> <member name="time_left" type="float" setter="set_time_left" getter="get_time_left"> + The time remaining. </member> </members> <signals> <signal name="timeout"> <description> + Emitted when the timer reaches 0. </description> </signal> </signals> diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml index 0b427fc089..c8c7fa1d01 100644 --- a/doc/classes/ScrollContainer.xml +++ b/doc/classes/ScrollContainer.xml @@ -4,7 +4,7 @@ A helper node for displaying scrollable elements (e.g. lists). </brief_description> <description> - A ScrollContainer node with a [Control] child and scrollbar child ([HScrollBar], [VScrollBar], or both) will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the minimum_size of the Control relative to the ScrollContainer. Works great with a [Panel] control. You can set EXPAND on children size flags, so they will upscale to ScrollContainer size if ScrollContainer size is bigger (scroll is invisible for chosen dimension). + A ScrollContainer node meant to contain a [Control] child. ScrollContainers will automatically create a scrollbar child ([HScrollBar], [VScrollBar], or both) when needed and will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the minimum_size of the Control relative to the ScrollContainer. Works great with a [Panel] control. You can set EXPAND on children size flags, so they will upscale to ScrollContainer size if ScrollContainer size is bigger (scroll is invisible for chosen dimension). </description> <tutorials> </tutorials> diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 9a49d5a7e4..5d336d2a25 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -499,6 +499,23 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur glDisableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components); + bool can_tile = true; + if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) { + // workaround for when setting tiling does not work due to hardware limitation + + RasterizerStorageGLES2::Texture *texture = storage->texture_owner.getornull(r->texture); + + if (texture) { + + texture = texture->get_ptr(); + + if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, true); + can_tile = false; + } + } + } + // On some widespread Nvidia cards, the normal draw method can produce some // flickering in draw_rect and especially TileMap rendering (tiles randomly flicker). // See GH-9913. @@ -559,7 +576,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur bool untile = false; - if (r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) { + if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); untile = true; @@ -616,7 +633,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur bool untile = false; - if (r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) { + if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); untile = true; @@ -664,6 +681,9 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, false); + } break; case Item::Command::TYPE_NINEPATCH: { @@ -1999,6 +2019,7 @@ void RasterizerCanvasGLES2::initialize() { state.canvas_shader.init(); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); state.canvas_shader.bind(); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index a7becdde24..0fd36cfb9c 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -42,8 +42,6 @@ #define glClearDepth glClearDepthf #endif -#define _DEPTH_COMPONENT24_OES 0x81A6 - static const GLenum _cube_side_enum[6] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -62,6 +60,7 @@ RID RasterizerSceneGLES2::shadow_atlas_create() { ShadowAtlas *shadow_atlas = memnew(ShadowAtlas); shadow_atlas->fbo = 0; shadow_atlas->depth = 0; + shadow_atlas->color = 0; shadow_atlas->size = 0; shadow_atlas->smallest_subdiv = 0; @@ -86,9 +85,13 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { if (shadow_atlas->fbo) { glDeleteTextures(1, &shadow_atlas->depth); glDeleteFramebuffers(1, &shadow_atlas->fbo); + if (shadow_atlas->color) { + glDeleteTextures(1, &shadow_atlas->color); + } shadow_atlas->fbo = 0; shadow_atlas->depth = 0; + shadow_atlas->color = 0; } // erase shadow atlast references from lights @@ -119,6 +122,16 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0); + if (storage->config.use_rgba_3d_shadows) { + glGenTextures(1, &shadow_atlas->color); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadow_atlas->size, shadow_atlas->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shadow_atlas->color, 0); + } glViewport(0, 0, shadow_atlas->size, shadow_atlas->size); glDepthMask(GL_TRUE); @@ -143,7 +156,7 @@ void RasterizerSceneGLES2::shadow_atlas_set_quadrant_subdivision(RID p_atlas, in subdiv = int(Math::sqrt((float)subdiv)); - if (shadow_atlas->quadrants[p_quadrant].shadows.size() == subdiv) + if (shadow_atlas->quadrants[p_quadrant].shadows.size() == (int)subdiv) return; // erase all data from the quadrant @@ -459,10 +472,10 @@ RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) { for (int i = 0; i < 6; i++) { glGenFramebuffers(1, &rpi->fbo[i]); + glGenTextures(1, &rpi->color[i]); } - glGenFramebuffers(1, &rpi->fbo_blur); - glGenRenderbuffers(1, &rpi->depth); + glGenTextures(1, &rpi->depth); rpi->cubemap = 0; //glGenTextures(1, &rpi->cubemap); @@ -510,9 +523,14 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance GLenum type = GL_UNSIGNED_BYTE; glActiveTexture(GL_TEXTURE0); + + glBindTexture(GL_TEXTURE_2D, rpi->depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size, size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + if (rpi->cubemap != 0) { glDeleteTextures(1, &rpi->cubemap); } + glGenTextures(1, &rpi->cubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); #if 1 @@ -523,17 +541,15 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); //resize depth buffer -#ifdef JAVASCRIPT_ENABLED - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size); -#else - glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size); -#endif - + //Generate framebuffers for rendering for (int i = 0; i < 6; i++) { glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); + glBindTexture(GL_TEXTURE_2D, rpi->color[i]); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size, 0, format, type, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rpi->color[i], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rpi->depth, 0); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); } #else @@ -551,7 +567,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0); glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); - glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size, size); // Note: used to be _DEPTH_COMPONENT24_OES. GL_DEPTH_COMPONENT untested. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); #ifdef DEBUG_ENABLED @@ -570,6 +586,8 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); } return true; @@ -579,6 +597,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); + ERR_FAIL_COND_V(rpi->current_resolution == 0, false); int size = rpi->probe_ptr->resolution; @@ -596,16 +615,23 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst } } + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to + + //first of all, copy rendered textures to cubemap + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glViewport(0, 0, size, size); + glCopyTexImage2D(_cube_side_enum[i], 0, GL_RGB, 0, 0, size, size, 0); + } + //do filtering //vdc cache glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex); - glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo_blur); // now render to the framebuffer, mipmap level for mipmap level int lod = 1; - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to size >>= 1; int mipmaps = 6; @@ -613,13 +639,20 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); storage->shaders.cubemap_filter.bind(); + glBindFramebuffer(GL_FRAMEBUFFER, storage->resources.mipmap_blur_fbo); + //blur while (size >= 1) { + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, storage->resources.mipmap_blur_color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, storage->resources.mipmap_blur_color, 0); + glViewport(0, 0, size, size); + glActiveTexture(GL_TEXTURE0); + for (int i = 0; i < 6; i++) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod); - glViewport(0, 0, size, size); storage->bind_quad_array(); storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1); @@ -627,6 +660,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glCopyTexImage2D(_cube_side_enum[i], lod, GL_RGB, 0, 0, size, size, 0); } size >>= 1; @@ -635,9 +669,14 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst } // restore ranges - + glActiveTexture(GL_TEXTURE0); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); //back to panorama + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); return true; } @@ -1751,7 +1790,11 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas if (!state.render_no_shadows && p_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + if (storage->config.use_rgba_3d_shadows) { + glBindTexture(GL_TEXTURE_2D, directional_shadow.color); + } else { + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + } state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); } @@ -1763,7 +1806,11 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + if (storage->config.use_rgba_3d_shadows) { + glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); + } else { + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + } state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); } @@ -1774,7 +1821,11 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + if (storage->config.use_rgba_3d_shadows) { + glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); + } else { + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + } state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); } @@ -2041,7 +2092,7 @@ void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1 state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection); state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents); state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, !p_refprobe2->probe_ptr->interior); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, p_refprobe2->probe_ptr->interior); state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity); Color ambient; @@ -2737,6 +2788,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const if (probe_interior) { env_radiance_tex = 0; //do not use radiance texture on interiors + state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior } // render opaque things first @@ -2994,7 +3046,9 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDepthMask(GL_TRUE); - glColorMask(0, 0, 0, 0); + if (!storage->config.use_rgba_3d_shadows) { + glColorMask(0, 0, 0, 0); + } if (custom_vp_size) { glViewport(0, 0, custom_vp_size, custom_vp_size); @@ -3070,7 +3124,9 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ if (storage->frame.current_rt) { glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); } - glColorMask(1, 1, 1, 1); + if (!storage->config.use_rgba_3d_shadows) { + glColorMask(1, 1, 1, 1); + } } void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { @@ -3108,6 +3164,16 @@ bool RasterizerSceneGLES2::free(RID p_rid) { ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); + for (int i = 0; i < 6; i++) { + glDeleteFramebuffers(1, &reflection_instance->fbo[i]); + glDeleteTextures(1, &reflection_instance->color[i]); + } + + if (reflection_instance->cubemap != 0) { + glDeleteTextures(1, &reflection_instance->cubemap); + } + glDeleteTextures(1, &reflection_instance->depth); + reflection_probe_release_atlas_index(p_rid); reflection_probe_instance_owner.free(p_rid); memdelete(reflection_instance); @@ -3124,6 +3190,8 @@ void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_dra void RasterizerSceneGLES2::initialize() { state.scene_shader.init(); + + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_3d_shadows); state.cube_to_dp_shader.init(); render_list.init(); @@ -3202,6 +3270,7 @@ void RasterizerSceneGLES2::initialize() { glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap); for (int i = 0; i < 6; i++) { + glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } @@ -3245,6 +3314,17 @@ void RasterizerSceneGLES2::initialize() { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); + if (storage->config.use_rgba_3d_shadows) { + glGenTextures(1, &directional_shadow.color); + glBindTexture(GL_TEXTURE_2D, directional_shadow.color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, directional_shadow.color, 0); + } + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { ERR_PRINT("Directional shadow framebuffer status invalid"); diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index aab9ae0fdc..fbb8b7e9e5 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -256,6 +256,7 @@ public: GLuint fbo; GLuint depth; + GLuint color; Map<RID, uint32_t> shadow_owners; }; @@ -279,6 +280,7 @@ public: struct DirectionalShadow { GLuint fbo; GLuint depth; + GLuint color; int light_count; int size; @@ -311,10 +313,9 @@ public: int reflection_index; GLuint fbo[6]; - GLuint cubemap; + GLuint color[6]; GLuint depth; - - GLuint fbo_blur; + GLuint cubemap; int current_resolution; mutable bool dirty; diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index c02eeaa0ee..9d2e609e5e 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -54,8 +54,6 @@ GLuint RasterizerStorageGLES2::system_fbo = 0; #define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define _DEPTH_COMPONENT24_OES 0x81A6 - #define _RED_OES 0x1903 void RasterizerStorageGLES2::bind_quad_array() const { @@ -67,7 +65,7 @@ void RasterizerStorageGLES2::bind_quad_array() const { glEnableVertexAttribArray(VS::ARRAY_TEX_UV); } -Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const { +Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_will_need_resize) const { r_gl_format = 0; Ref<Image> image = p_image; @@ -195,7 +193,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_DXT1: { - if (config.s3tc_supported) { + if (config.s3tc_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -207,7 +205,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_DXT3: { - if (config.s3tc_supported) { + if (config.s3tc_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -219,7 +217,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_DXT5: { - if (config.s3tc_supported) { + if (config.s3tc_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -269,7 +267,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_ETC: { - if (config.etc1_supported) { + if (config.etc1_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_ETC1_RGB8_OES; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -315,17 +313,38 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ if (need_decompress) { if (!image.is_null()) { + image = image->duplicate(); + print_line("decompressing..."); image->decompress(); ERR_FAIL_COND_V(image->is_compressed(), image); - image->convert(Image::FORMAT_RGBA8); + switch (image->get_format()) { + case Image::FORMAT_RGB8: { + r_gl_format = GL_RGB; + r_gl_internal_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGB8; + r_compressed = false; + } break; + case Image::FORMAT_RGBA8: { + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + } break; + default: { + image->convert(Image::FORMAT_RGBA8); + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + + } break; + } } - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGBA8; - return image; } @@ -395,11 +414,31 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ } } - Image::Format real_format; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed); - texture->alloc_width = texture->width; texture->alloc_height = texture->height; + texture->resize_to_po2 = false; + if (!config.support_npot_repeat_mipmap) { + int po2_width = next_power_of_2(p_width); + int po2_height = next_power_of_2(p_height); + + bool is_po2 = p_width == po2_width && p_height == po2_height; + + if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) { + + if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + //not supported + ERR_PRINTS("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); + texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS); + } else { + texture->alloc_height = po2_height; + texture->alloc_width = po2_width; + texture->resize_to_po2 = true; + } + } + } + + Image::Format real_format; + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); texture->gl_format_cache = format; texture->gl_type_cache = type; @@ -414,7 +453,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { //prealloc if video - glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL); + glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL); } texture->active = true; @@ -439,7 +478,18 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p } Image::Format real_format; - Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed); + Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); + + if (texture->resize_to_po2) { + if (p_image->is_compressed()) { + ERR_PRINTS("Texture '" + texture->path + "' was required to be a power of 2 (because it uses either mipmaps or repeat), so it was decompressed. This will hurt performance and memory usage."); + } + + if (img == p_image) { + img = img->duplicate(); + } + img->resize_to_po2(false); + } if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { @@ -575,7 +625,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) GLenum gl_internal_format; GLenum gl_type; bool compressed; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed); + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false); PoolVector<uint8_t> data; @@ -620,7 +670,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) GLenum gl_internal_format; GLenum gl_type; bool compressed; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed); + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2); PoolVector<uint8_t> data; @@ -974,18 +1024,8 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra glGenTextures(1, &sky->radiance); glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); - // Now we create a new framebuffer. The new cubemap images will be used as - // attachements for it, so we can fill them by issuing draw calls. - GLuint tmp_fb; - int size = p_radiance_size / 4; //divide by four because its a cubemap (this is an approximation because GLES3 uses a dual paraboloid) - int lod = 0; - - int mipmaps = 6; - - int mm_level = mipmaps; - GLenum internal_format = GL_RGB; GLenum format = GL_RGB; GLenum type = GL_UNSIGNED_BYTE; @@ -998,6 +1038,12 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra } glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + //no filters for now + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + #else while (size >= 1) { @@ -1011,39 +1057,50 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra } #endif //framebuffer - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D); - - shaders.cubemap_filter.bind(); - lod = 0; - mm_level = mipmaps; + glBindFramebuffer(GL_FRAMEBUFFER, resources.mipmap_blur_fbo); + int mipmaps = 6; + int lod = 0; + int mm_level = mipmaps; size = p_radiance_size; + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, true); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, true); + shaders.cubemap_filter.bind(); - // now render to the framebuffer, mipmap level for mipmap level + // third, render to the framebuffer using separate textures, then copy to mipmaps while (size >= 1) { + //make framebuffer size the texture size, need to use a separate texture for compatibility + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0); + if (lod == 1) { + //bind panorama for smaller lods + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false); + shaders.cubemap_filter.bind(); + } + glViewport(0, 0, size, size); + bind_quad_array(); - for (int i = 0; i < 6; i++) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], sky->radiance, lod); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - break; //may be too small - } - - glViewport(0, 0, size, size); + glActiveTexture(GL_TEXTURE2); //back to panorama - bind_quad_array(); + for (int i = 0; i < 6; i++) { shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); - float roughness = mm_level ? lod / (float)(mipmaps - 1) : 1; + float roughness = mm_level >= 0 ? lod / (float)(mipmaps - 1) : 1; roughness = MIN(1.0, roughness); //keep max at 1 shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glCopyTexImage2D(_cube_side_enum[i], lod, GL_RGB, 0, 0, size, size, 0); } size >>= 1; @@ -1053,16 +1110,28 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra lod++; } + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false); + // restore ranges + glActiveTexture(GL_TEXTURE2); //back to panorama glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); //back to panorama + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + // Framebuffer did its job. thank mr framebuffer + glActiveTexture(GL_TEXTURE0); //back to panorama glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - glDeleteFramebuffers(1, &tmp_fb); } /* SHADER API */ @@ -2386,7 +2455,6 @@ AABB RasterizerStorageGLES2::mesh_surface_get_aabb(RID p_mesh, int p_surface) co } Vector<PoolVector<uint8_t> > RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const { - WARN_PRINT("GLES2 mesh_surface_get_blend_shapes is not implemented"); return Vector<PoolVector<uint8_t> >(); } Vector<AABB> RasterizerStorageGLES2::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { @@ -3610,6 +3678,7 @@ RID RasterizerStorageGLES2::reflection_probe_create() { reflection_probe->intensity = 1.0; reflection_probe->interior_ambient = Color(); reflection_probe->interior_ambient_energy = 1.0; + reflection_probe->interior_ambient_probe_contrib = 0.0; reflection_probe->max_distance = 0; reflection_probe->extents = Vector3(1, 1, 1); reflection_probe->origin_offset = Vector3(0, 0, 0); @@ -3695,6 +3764,7 @@ void RasterizerStorageGLES2::reflection_probe_set_as_interior(RID p_probe, bool ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { @@ -4237,11 +4307,8 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { glGenTextures(1, &rt->depth); glBindTexture(GL_TEXTURE_2D, rt->depth); -#ifdef JAVASCRIPT_ENABLED glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); -#else - glTexImage2D(GL_TEXTURE_2D, 0, _DEPTH_COMPONENT24_OES, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); -#endif + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -4464,15 +4531,17 @@ RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) { glGenFramebuffers(1, &cls->fbo); glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - glGenRenderbuffers(1, &cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); -#ifdef JAVASCRIPT_ENABLED - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); -#else - glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, cls->size, cls->height); -#endif - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, 0); + glGenTextures(1, &cls->depth); + glBindTexture(GL_TEXTURE_2D, cls->depth); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cls->size, cls->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, cls->depth, 0); glGenTextures(1, &cls->distance); glBindTexture(GL_TEXTURE_2D, cls->distance); @@ -4837,7 +4906,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid); glDeleteFramebuffers(1, &cls->fbo); - glDeleteRenderbuffers(1, &cls->depth); + glDeleteTextures(1, &cls->depth); glDeleteTextures(1, &cls->distance); canvas_light_shadow_owner.free(p_rid); memdelete(cls); @@ -4850,6 +4919,9 @@ bool RasterizerStorageGLES2::free(RID p_rid) { bool RasterizerStorageGLES2::has_os_feature(const String &p_feature) const { + if (p_feature == "pvrtc") + return config.pvrtc_supported; + if (p_feature == "s3tc") return config.s3tc_supported; @@ -4899,16 +4971,23 @@ void RasterizerStorageGLES2::initialize() { #ifdef GLES_OVER_GL config.float_texture_supported = true; config.s3tc_supported = true; + config.pvrtc_supported = false; config.etc1_supported = false; + config.support_npot_repeat_mipmap = true; #else config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); + config.pvrtc_supported = config.extensions.has("IMG_texture_compression_pvrtc"); + config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot"); + #endif #ifdef GLES_OVER_GL config.use_rgba_2d_shadows = false; + config.use_rgba_3d_shadows = false; #else config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg")); + config.use_rgba_3d_shadows = config.extensions.has("GL_OES_depth_texture"); #endif #ifdef GLES_OVER_GL @@ -4919,6 +4998,8 @@ void RasterizerStorageGLES2::initialize() { #ifdef GLES_OVER_GL config.support_write_depth = true; +#elif defined(JAVASCRIPT_ENABLED) + config.support_write_depth = false; #else config.support_write_depth = config.extensions.has("GL_EXT_frag_depth"); #endif @@ -4940,7 +5021,7 @@ void RasterizerStorageGLES2::initialize() { shaders.copy.init(); shaders.cubemap_filter.init(); - bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx.mobile"); + bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::LOW_QUALITY, !ggx_hq); { @@ -5060,10 +5141,20 @@ void RasterizerStorageGLES2::initialize() { } glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling glBindTexture(GL_TEXTURE_2D, 0); } + { + + glGenFramebuffers(1, &resources.mipmap_blur_fbo); + glGenTextures(1, &resources.mipmap_blur_color); + } + #ifdef GLES_OVER_GL //this needs to be enabled manually in OpenGL 2.1 diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index a0fa2aacc5..f6c8faa497 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -72,16 +72,19 @@ public: bool float_texture_supported; bool s3tc_supported; bool etc1_supported; + bool pvrtc_supported; bool keep_original_textures; bool force_vertex_shading; bool use_rgba_2d_shadows; + bool use_rgba_3d_shadows; bool support_32_bits_indices; bool support_write_depth; bool support_half_float_vertices; + bool support_npot_repeat_mipmap; } config; struct Resources { @@ -91,6 +94,9 @@ public: GLuint normal_tex; GLuint aniso_tex; + GLuint mipmap_blur_fbo; + GLuint mipmap_blur_color; + GLuint radical_inverse_vdc_cache_tex; bool use_rgba_2d_shadows; @@ -240,6 +246,8 @@ public: int mipmaps; + bool resize_to_po2; + bool active; GLenum tex_id; @@ -275,6 +283,7 @@ public: ignore_mipmaps(false), compressed(false), mipmaps(0), + resize_to_po2(false), active(false), tex_id(0), stored_cube_sides(0), @@ -313,7 +322,7 @@ public: mutable RID_Owner<Texture> texture_owner; - Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const; + Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_will_need_resize) const; virtual RID texture_create(); virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index fdd905458b..d00b03fb8a 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -770,7 +770,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { /** CANVAS ITEM SHADER **/ actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp"; + actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "gl_PointSize"; actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index e74c7d7166..b13801946f 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -107,6 +107,7 @@ vec2 select(vec2 a, vec2 b, bvec2 c) { void main() { vec4 color = color_attrib; + vec2 uv; #ifdef USE_INSTANCING mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); @@ -121,9 +122,9 @@ void main() { #ifdef USE_TEXTURE_RECT if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx; + uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; } else { - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; + uv = src_rect.xy + abs(src_rect.zw) * vertex; } vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); @@ -140,7 +141,7 @@ void main() { #else vec4 outvec = vec4(vertex.xy, 0.0, 1.0); - uv_interp = uv_attrib; + uv = uv_attrib; #endif { @@ -189,6 +190,7 @@ VERTEX_SHADER_CODE #endif + uv_interp = uv; gl_Position = projection_matrix * outvec; #ifdef USE_LIGHTING @@ -345,10 +347,14 @@ void main() { vec4 color = color_interp; vec2 uv = uv_interp; +#ifdef USE_FORCE_REPEAT + //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that dont support it + uv = mod(uv, vec2(1.0, 1.0)); +#endif #if !defined(COLOR_USED) //default behavior, texture by color - color *= texture2D(color_texture, uv_interp); + color *= texture2D(color_texture, uv); #endif #ifdef SCREEN_UV_USED @@ -365,7 +371,7 @@ void main() { #endif if (use_default_normal) { - normal.xy = texture2D(normal_texture, uv_interp).xy * 2.0 - 1.0; + normal.xy = texture2D(normal_texture, uv).xy * 2.0 - 1.0; normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; } else { @@ -480,7 +486,7 @@ FRAGMENT_SHADER_CODE #ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture2D((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1)) +#define SHADOW_DEPTH(m_tex, m_uv) dot(texture2D((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) #else diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl index d39212826e..01b2c59325 100644 --- a/drivers/gles2/shaders/canvas_shadow.glsl +++ b/drivers/gles2/shaders/canvas_shadow.glsl @@ -48,7 +48,7 @@ void main() { #ifdef USE_RGBA_SHADOWS highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); - comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + comp -= comp.xxyz * vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); gl_FragColor = comp; #else diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl index 7643297a14..a6902836ed 100644 --- a/drivers/gles2/shaders/cubemap_filter.glsl +++ b/drivers/gles2/shaders/cubemap_filter.glsl @@ -187,6 +187,18 @@ void main() { vec2 uv = (uv_interp * 2.0) - 1.0; vec3 N = texelCoordToVec(uv, face_id); +#ifdef USE_DIRECT_WRITE + +#ifdef USE_SOURCE_PANORAMA + + gl_FragColor = vec4(texturePanorama(source_panorama, N).rgb, 1.0); +#else + + gl_FragColor = vec4(textureCube(source_cube, N).rgb, 1.0); +#endif //USE_SOURCE_PANORAMA + +#else + vec4 sum = vec4(0.0); for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) { @@ -221,4 +233,5 @@ void main() { sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); gl_FragColor = vec4(sum.rgb, 1.0); +#endif } diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index faf88cf33d..371ea8498a 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -96,6 +96,10 @@ uniform float light_normal_bias; // varyings // +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) +varying highp vec4 position_interp; +#endif + varying highp vec3 vertex_interp; varying vec3 normal_interp; @@ -355,7 +359,7 @@ void main() { uv2_interp = uv2_attrib; #endif -#ifdef OVERRIDE_POSITION +#if defined(OVERRIDE_POSITION) highp vec4 position; #endif @@ -647,11 +651,15 @@ VERTEX_SHADER_CODE #endif //use vertex lighting -#ifdef OVERRIDE_POSITION +#if defined(OVERRIDE_POSITION) gl_Position = position; #else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); #endif + +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) + position_interp = gl_Position; +#endif } /* clang-format off */ @@ -975,6 +983,10 @@ uniform vec4 light_clamp; // varyings // +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) +varying highp vec4 position_interp; +#endif + varying highp vec3 vertex_interp; varying vec3 normal_interp; @@ -1335,8 +1347,18 @@ LIGHT_SHADER_CODE #ifdef USE_SHADOW -#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r) -#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r) +#ifdef USE_RGBA_SHADOWS + +#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) + +#else + +#define SHADOW_DEPTH(m_val) (m_val).r + +#endif + +#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture2D(p_shadow, p_pos))) +#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(texture2DProj(p_shadow, p_pos))) float sample_shadow(highp sampler2D shadow, highp vec4 spos) { @@ -1598,14 +1620,14 @@ FRAGMENT_SHADER_CODE #ifdef USE_LIGHTMAP_CAPTURE { vec3 cone_dirs[12] = vec3[]( - vec3(0, 0, 1), - vec3(0.866025, 0, 0.5), + vec3(0.0, 0.0, 1.0), + vec3(0.866025, 0.0, 0.5), vec3(0.267617, 0.823639, 0.5), vec3(-0.700629, 0.509037, 0.5), vec3(-0.700629, -0.509037, 0.5), vec3(0.267617, -0.823639, 0.5), - vec3(0, 0, -1), - vec3(0.866025, 0, -0.5), + vec3(0.0, 0.0, -1.0), + vec3(0.866025, 0.0, -0.5), vec3(0.267617, 0.823639, -0.5), vec3(-0.700629, 0.509037, -0.5), vec3(-0.700629, -0.509037, -0.5), @@ -1812,7 +1834,7 @@ FRAGMENT_SHADER_CODE #if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - light_att *= sample_shadow(light_directional_shadow, shadow_coord); + light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord)); #endif //orthogonal #else //fragment version of pssm @@ -2105,5 +2127,15 @@ FRAGMENT_SHADER_CODE #endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) -#endif // not RENDER_DEPTH +#else // not RENDER_DEPTH +//depth render +#ifdef USE_RGBA_SHADOWS + + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias + highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); + comp -= comp.xxyz * vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + gl_FragColor = comp; + +#endif +#endif } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 4cf9054bf6..e645e39f3f 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -5053,7 +5053,7 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.add_custom_define("#define MAX_LIGHT_DATA_STRUCTS " + itos(state.max_ubo_lights) + "\n"); state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS " + itos(state.max_forward_lights_per_object) + "\n"); - state.max_ubo_reflections = MIN(RenderList::MAX_REFLECTIONS, max_ubo_size / sizeof(ReflectionProbeDataUBO)); + state.max_ubo_reflections = MIN((int)RenderList::MAX_REFLECTIONS, max_ubo_size / sizeof(ReflectionProbeDataUBO)); state.reflection_array_tmp = (uint8_t *)memalloc(sizeof(ReflectionProbeDataUBO) * state.max_ubo_reflections); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 99e594d242..ccd5fff99f 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5522,6 +5522,7 @@ void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 88368516c1..6c1806a657 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -495,7 +495,7 @@ FRAGMENT_SHADER_CODE #endif } #ifdef DEBUG_ENCODED_32 - highp float enc32 = dot(color, highp vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1)); + highp float enc32 = dot(color, highp vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)); color = vec4(vec3(enc32), 1.0); #endif @@ -589,7 +589,7 @@ FRAGMENT_SHADER_CODE #ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1)) +#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) #else diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl index 68d0713385..13fff7f4d1 100644 --- a/drivers/gles3/shaders/canvas_shadow.glsl +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -36,7 +36,7 @@ void main() { #ifdef USE_RGBA_SHADOWS highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); - comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + comp -= comp.xxyz * vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); distance_buf = comp; #else diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 125faa4eac..3b06b08dec 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -400,7 +400,7 @@ void main() { texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0,0.0,0.0,1.0)) * + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.x; tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 3); @@ -409,7 +409,7 @@ void main() { texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0,0.0,0.0,1.0)) * + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.y; tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 3); @@ -418,7 +418,7 @@ void main() { texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0,0.0,0.0,1.0)) * + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.z; tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 3); @@ -427,7 +427,7 @@ void main() { texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), - vec4(0.0,0.0,0.0,1.0)) * + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.w; world_matrix = transpose(m) * world_matrix; @@ -1521,8 +1521,8 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, ve #define MAX_CONE_DIRS 6 vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0, 0, 1), - vec3(0.866025, 0, 0.5), + vec3(0.0, 0.0, 1.0), + vec3(0.866025, 0.0, 0.5), vec3(0.267617, 0.823639, 0.5), vec3(-0.700629, 0.509037, 0.5), vec3(-0.700629, -0.509037, 0.5), @@ -1536,10 +1536,10 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, ve #define MAX_CONE_DIRS 4 vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0.707107, 0, 0.707107), - vec3(0, 0.707107, 0.707107), - vec3(-0.707107, 0, 0.707107), - vec3(0, -0.707107, 0.707107)); + vec3(0.707107, 0.0, 0.707107), + vec3(0.0, 0.707107, 0.707107), + vec3(-0.707107, 0.0, 0.707107), + vec3(0.0, -0.707107, 0.707107)); float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); float cone_angle_tan = 0.98269; @@ -1575,7 +1575,7 @@ void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_sp vec3 ref_vec = normalize(reflect(normalize(pos), normal)); //find arbitrary tangent and bitangent, then build a matrix - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0); + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, normal)); vec3 bitangent = normalize(cross(tangent, normal)); mat3 normal_mat = mat3(tangent, bitangent, normal); @@ -1963,14 +1963,14 @@ FRAGMENT_SHADER_CODE #ifdef USE_LIGHTMAP_CAPTURE { vec3 cone_dirs[12] = vec3[]( - vec3(0, 0, 1), - vec3(0.866025, 0, 0.5), + vec3(0.0, 0.0, 1.0), + vec3(0.866025, 0.0, 0.5), vec3(0.267617, 0.823639, 0.5), vec3(-0.700629, 0.509037, 0.5), vec3(-0.700629, -0.509037, 0.5), vec3(0.267617, -0.823639, 0.5), - vec3(0, 0, -1), - vec3(0.866025, 0, -0.5), + vec3(0.0, 0.0, -1.0), + vec3(0.866025, 0.0, -0.5), vec3(0.267617, 0.823639, -0.5), vec3(-0.700629, 0.509037, -0.5), vec3(-0.700629, -0.509037, -0.5), diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index 86546319a0..39f1ea6155 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -77,7 +77,7 @@ void main() { return; } //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0); - //ray_dir = normalize(vec3(1, 1, -1)); + //ray_dir = normalize(vec3(1.0, 1.0, -1.0)); //////////////// diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 072ffd96e7..6e045817bc 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -246,7 +246,7 @@ void FileAccessUnix::store_8(uint8_t p_dest) { void FileAccessUnix::store_buffer(const uint8_t *p_src, int p_length) { ERR_FAIL_COND(!f); - ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); + ERR_FAIL_COND((int)fwrite(p_src, 1, p_length, f) != p_length); } bool FileAccessUnix::file_exists(const String &p_path) { diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h index 5cfe3964f6..49a34dacc3 100644 --- a/drivers/unix/syslog_logger.h +++ b/drivers/unix/syslog_logger.h @@ -37,7 +37,7 @@ class SyslogLogger : public Logger { public: - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); virtual ~SyslogLogger(); diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 39e6df4450..2b9007de04 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -1160,6 +1160,17 @@ void EditorExport::add_export_preset(const Ref<EditorExportPreset> &p_preset, in export_presets.insert(p_at_pos, p_preset); } +String EditorExportPlatform::test_etc2() const { + + String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name"); + bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc"); + + if (driver == "GLES2" && !etc2_supported) { + return TTR("Target platform requires 'ETC' texture compression for GLES2. Enable support in Project Settings."); + } + return String(); +} + int EditorExport::get_export_preset_count() const { return export_presets.size(); diff --git a/editor/editor_export.h b/editor/editor_export.h index c7c2b76327..bd864c528c 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -258,6 +258,7 @@ public: virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { return OK; } virtual Ref<Texture> get_run_icon() const { return get_logo(); } + String test_etc2() const; //generic test for etc2 since most platforms use it virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index ea36410cc3..3d9d5e26be 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -42,6 +42,8 @@ #include "editor_settings.h" EditorFileSystem *EditorFileSystem::singleton = NULL; +//the name is the version, to keep compatibility with different versions of Godot +#define CACHE_FILE_NAME "filesystem_cache5" void EditorFileSystemDirectory::sort_files() { @@ -203,14 +205,30 @@ void EditorFileSystem::_scan_filesystem() { String project = ProjectSettings::get_singleton()->get_resource_path(); - String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache4"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); FileAccess *f = FileAccess::open(fscache, FileAccess::READ); + bool first = true; if (f) { //read the disk cache while (!f->eof_reached()) { String l = f->get_line().strip_edges(); + if (first) { + if (first_scan) { + // only use this on first scan, afterwards it gets ignored + // this is so on first reimport we synchronize versions, then + // we dont care until editor restart. This is for usability mainly so + // your workflow is not killed after changing a setting by forceful reimporting + // everything there is. + filesystem_settings_version_for_import = l.strip_edges(); + if (filesystem_settings_version_for_import != ResourceFormatImporter::get_singleton()->get_import_settings_hash()) { + revalidate_import_files = true; + } + } + first = false; + continue; + } if (l == String()) continue; @@ -291,25 +309,22 @@ void EditorFileSystem::_scan_filesystem() { memdelete(d); - f = FileAccess::open(fscache, FileAccess::WRITE); - if (f == NULL) { - ERR_PRINTS("Error writing fscache: " + fscache); - } else { - _save_filesystem_cache(new_filesystem, f); - f->close(); - memdelete(f); + if (!first_scan) { + //on the first scan this is done from the main thread after re-importing + _save_filesystem_cache(); } scanning = false; } void EditorFileSystem::_save_filesystem_cache() { - String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache4"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE); if (f == NULL) { ERR_PRINTS("Error writing fscache: " + fscache); } else { + f->store_line(filesystem_settings_version_for_import); _save_filesystem_cache(filesystem, f); f->close(); memdelete(f); @@ -327,6 +342,15 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo if (!reimport_on_missing_imported_files && p_only_imported_files) return false; + if (!FileAccess::exists(p_path + ".import")) { + return true; + } + + if (!ResourceFormatImporter::get_singleton()->are_import_settings_valid(p_path)) { + //reimport settings are not valid, reimport + return true; + } + Error err; FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); @@ -562,6 +586,13 @@ bool EditorFileSystem::_update_scan_actions() { reimport_files(reimports); } + if (first_scan) { + //only on first scan this is valid and updated, then settings changed. + revalidate_import_files = false; + filesystem_settings_version_for_import = ResourceFormatImporter::get_singleton()->get_import_settings_hash(); + _save_filesystem_cache(); + } + if (reloads.size()) { emit_signal("resources_reload", reloads); } @@ -595,7 +626,7 @@ void EditorFileSystem::scan() { emit_signal("filesystem_changed"); emit_signal("sources_changed", sources_changed.size() > 0); _queue_update_script_classes(); - + first_scan = false; } else { ERR_FAIL_COND(thread); @@ -737,11 +768,20 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess fi->deps = fc->deps; fi->modified_time = fc->modification_time; fi->import_modified_time = fc->import_modification_time; + fi->import_valid = fc->import_valid; fi->script_class_name = fc->script_class_name; fi->script_class_extends = fc->script_class_extends; fi->script_class_icon_path = fc->script_class_icon_path; + if (revalidate_import_files && !ResourceFormatImporter::get_singleton()->are_import_settings_valid(path)) { + ItemAction ia; + ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT; + ia.dir = p_dir; + ia.file = E->get(); + scan_actions.push_back(ia); + } + if (fc->type == String()) { fi->type = ResourceLoader::get_resource_type(path); //there is also the chance that file type changed due to reimport, must probably check this somehow here (or kind of note it for next time in another file?) @@ -1101,6 +1141,7 @@ void EditorFileSystem::_notification(int p_what) { emit_signal("filesystem_changed"); emit_signal("sources_changed", sources_changed.size() > 0); _queue_update_script_classes(); + first_scan = false; } } else if (!scanning) { @@ -1117,6 +1158,7 @@ void EditorFileSystem::_notification(int p_what) { emit_signal("filesystem_changed"); emit_signal("sources_changed", sources_changed.size() > 0); _queue_update_script_classes(); + first_scan = false; } } } break; @@ -1569,8 +1611,8 @@ void EditorFileSystem::_reimport_file(const String &p_file) { List<String> import_variants; List<String> gen_files; - - Error err = importer->import(p_file, base_path, params, &import_variants, &gen_files); + Variant metadata; + Error err = importer->import(p_file, base_path, params, &import_variants, &gen_files, &metadata); if (err != OK) { ERR_PRINTS("Error importing: " + p_file); @@ -1615,6 +1657,10 @@ void EditorFileSystem::_reimport_file(const String &p_file) { f->store_line("valid=false"); } + if (metadata != Variant()) { + f->store_line("metadata=" + metadata.get_construct_string()); + } + f->store_line(""); f->store_line("[deps]\n"); @@ -1815,6 +1861,8 @@ EditorFileSystem::EditorFileSystem() { scan_total = 0; update_script_classes_queued = false; + first_scan = true; + revalidate_import_files = false; } EditorFileSystem::~EditorFileSystem() { diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index bb892baf57..2a9e325454 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -143,7 +143,10 @@ class EditorFileSystem : public Node { bool abort_scan; bool scanning; bool importing; + bool first_scan; float scan_total; + String filesystem_settings_version_for_import; + bool revalidate_import_files; void _scan_filesystem(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8c9974404e..67fba4f278 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -291,6 +291,8 @@ void EditorNode::_notification(int p_what) { get_tree()->get_root()->set_as_audio_listener_2d(false); get_tree()->set_auto_accept_quit(false); get_tree()->connect("files_dropped", this, "_dropped_files"); + + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } if (p_what == NOTIFICATION_EXIT_TREE) { @@ -305,7 +307,8 @@ void EditorNode::_notification(int p_what) { _editor_select(EDITOR_3D); _update_debug_options(); - _load_docks(); + + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) { @@ -528,6 +531,10 @@ void EditorNode::_sources_changed(bool p_exist) { if (waiting_for_first_scan) { + EditorResourcePreview::get_singleton()->start(); //start previes now that it's safe + + _load_docks(); + if (defer_load_scene != "") { load_scene(defer_load_scene); @@ -1017,6 +1024,35 @@ bool EditorNode::_validate_scene_recursive(const String &p_filename, Node *p_nod return false; } +static bool _find_edited_resources(const Ref<Resource> &p_resource, Set<Ref<Resource> > &edited_resources) { + + if (p_resource->is_edited()) { + edited_resources.insert(p_resource); + return true; + } + + List<PropertyInfo> plist; + + p_resource->get_property_list(&plist); + + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + if (E->get().type == Variant::OBJECT && E->get().usage & PROPERTY_USAGE_STORAGE && !(E->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)) { + RES res = p_resource->get(E->get().name); + if (res.is_null()) { + continue; + } + if (res->get_path().is_resource_file()) { //not a subresource, continue + continue; + } + if (_find_edited_resources(res, edited_resources)) { + return true; + } + } + } + + return false; +} + void EditorNode::_save_scene(String p_file, int idx) { Node *scene = editor_data.get_edited_scene_root(idx); @@ -1080,16 +1116,28 @@ void EditorNode::_save_scene(String p_file, int idx) { //_save_edited_subresources(scene, processed, flg); { //instead, just find globally unsaved subresources and save them + Set<Ref<Resource> > edited_subresources; + List<Ref<Resource> > cached; ResourceCache::get_cached_resources(&cached); for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) { Ref<Resource> res = E->get(); - if (res->is_edited() && res->get_path().is_resource_file()) { + if (!res->get_path().is_resource_file()) + continue; + //not only check if this resourec is edited, check contained subresources too + if (_find_edited_resources(res, edited_subresources)) { ResourceSaver::save(res->get_path(), res, flg); - res->set_edited(false); } } + + // clear later, because user may have put the same subresource in two different resources, + // which will be shared until the next reload + + for (Set<Ref<Resource> >::Element *E = edited_subresources.front(); E; E = E->next()) { + Ref<Resource> res = E->get(); + res->set_edited(false); + } } editor_data.save_editor_external_data(); @@ -2542,6 +2590,7 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan singleton->editor_plugins_over->get_plugins_list().erase(p_editor); singleton->remove_child(p_editor); singleton->editor_data.remove_editor_plugin(p_editor); + singleton->get_editor_plugins_force_input_forwarding()->remove_plugin(p_editor); } void EditorNode::_update_addon_config() { @@ -3631,6 +3680,8 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p } p_layout->set_value(p_section, "dock_filesystem_split", filesystem_dock->get_split_offset()); + p_layout->set_value(p_section, "dock_filesystem_display_mode", filesystem_dock->get_display_mode()); + p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", filesystem_dock->get_file_list_display_mode()); for (int i = 0; i < vsplits.size(); i++) { @@ -3818,6 +3869,17 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String int fs_split_ofs = 0; if (p_layout->has_section_key(p_section, "dock_filesystem_split")) { fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); + filesystem_dock->set_split_offset(fs_split_ofs); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_display_mode")) { + FileSystemDock::DisplayMode dock_filesystem_display_mode = FileSystemDock::DisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_display_mode"))); + filesystem_dock->set_display_mode(dock_filesystem_display_mode); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_file_list_display_mode")) { + FileSystemDock::FileListDisplayMode dock_filesystem_file_list_display_mode = FileSystemDock::FileListDisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_file_list_display_mode"))); + filesystem_dock->set_file_list_display_mode(dock_filesystem_file_list_display_mode); } filesystem_dock->set_split_offset(fs_split_ofs); @@ -5579,9 +5641,10 @@ EditorNode::EditorNode() { node_dock = memnew(NodeDock); filesystem_dock = memnew(FileSystemDock(this)); - filesystem_dock->set_file_list_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/files_display_mode"))); filesystem_dock->connect("open", this, "open_request"); + filesystem_dock->set_file_list_display_mode(FileSystemDock::FILE_LIST_DISPLAY_LIST); filesystem_dock->connect("instance", this, "_instance_request"); + filesystem_dock->connect("display_mode_changed", this, "_save_docks"); // Scene: Top left dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scene_tree_dock); @@ -6059,6 +6122,10 @@ void EditorPluginList::add_plugin(EditorPlugin *p_plugin) { plugins_list.push_back(p_plugin); } +void EditorPluginList::remove_plugin(EditorPlugin *p_plugin) { + plugins_list.erase(p_plugin); +} + bool EditorPluginList::empty() { return plugins_list.empty(); } diff --git a/editor/editor_node.h b/editor/editor_node.h index 46a65b56fa..433441c29e 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -837,6 +837,7 @@ public: void forward_spatial_draw_over_viewport(Control *p_overlay); void forward_spatial_force_draw_over_viewport(Control *p_overlay); void add_plugin(EditorPlugin *p_plugin); + void remove_plugin(EditorPlugin *p_plugin); void clear(); bool empty(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 0851485208..0f6c6349ed 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -418,13 +418,14 @@ void EditorPropertyArray::_length_changed(double p_page) { return; Variant array = object->get_array(); + int previous_size = array.call("size"); + array.call("resize", int(p_page)); - emit_changed(get_edited_property(), array, "", false); if (array.get_type() == Variant::ARRAY) { if (subtype != Variant::NIL) { int size = array.call("size"); - for (int i = 0; i < size; i++) { + for (int i = previous_size; i < size; i++) { if (array.get(i).get_type() == Variant::NIL) { Variant::CallError ce; array.set(i, Variant::construct(subtype, NULL, 0, ce)); @@ -432,7 +433,16 @@ void EditorPropertyArray::_length_changed(double p_page) { } } array = array.call("duplicate"); //dupe, so undo/redo works better + } else { + int size = array.call("size"); + // Pool*Array don't initialize their elements, have to do it manually + for (int i = previous_size; i < size; i++) { + Variant::CallError ce; + array.set(i, Variant::construct(array.get(i).get_type(), NULL, 0, ce)); + } } + + emit_changed(get_edited_property(), array, "", false); object->set_array(array); update_property(); } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 1fa1fe9070..e0c292dc87 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -417,6 +417,10 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) { } } +void EditorResourcePreview::start() { + ERR_FAIL_COND(thread); + thread = Thread::create(_thread_func, this); +} void EditorResourcePreview::stop() { if (thread) { exit = true; @@ -428,13 +432,12 @@ void EditorResourcePreview::stop() { } EditorResourcePreview::EditorResourcePreview() { + thread = NULL; singleton = this; preview_mutex = Mutex::create(); preview_sem = Semaphore::create(); order = 0; exit = false; - - thread = Thread::create(_thread_func, this); } EditorResourcePreview::~EditorResourcePreview() { diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 85ac78d58f..c958bfbb74 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -126,6 +126,7 @@ public: void remove_preview_generator(const Ref<EditorResourcePreviewGenerator> &p_generator); void check_for_invalidation(const String &p_path); + void start(); void stop(); EditorResourcePreview(); diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 887a102aa4..06cadca1c0 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -32,6 +32,7 @@ #include "editor_export.h" #include "editor_node.h" +#include "editor_scale.h" void EditorRunNative::_notification(int p_what) { @@ -49,7 +50,7 @@ void EditorRunNative::_notification(int p_what) { im->clear_mipmaps(); if (!im->empty()) { - im->resize(16, 16); + im->resize(16 * EDSCALE, 16 * EDSCALE); Ref<ImageTexture> small_icon; small_icon.instance(); small_icon->create_from_image(im, 0); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index cbd8df315a..741a210950 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -389,12 +389,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("docks/scene_tree/relationship_line_color", Color::html("464646")); // FileSystem - _initial_set("docks/filesystem/display_mode", 0); - hints["docks/filesystem/display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/display_mode", PROPERTY_HINT_ENUM, "Tree only, Split"); _initial_set("docks/filesystem/thumbnail_size", 64); hints["docks/filesystem/thumbnail_size"] = PropertyInfo(Variant::INT, "docks/filesystem/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16"); - _initial_set("docks/filesystem/files_display_mode", 0); - hints["docks/filesystem/files_display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/files_display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"); _initial_set("docks/filesystem/always_show_folders", true); // Property editor diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index ce1d545510..ad3ce90afd 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -193,6 +193,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ int fc = 0; //count them and find version String version; + String contents_dir; while (ret == UNZ_OK) { @@ -225,6 +226,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ } version = data_str; + contents_dir = file.get_base_dir().trim_suffix("/").trim_suffix("\\"); } if (file.get_file().size() != 0) { @@ -268,7 +270,9 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ char fname[16384]; unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); - String file = String(fname).get_file(); + String file_path(fname); + + String file = file_path.get_file(); if (file.size() == 0) { ret = unzGoToNextFile(pkg); @@ -283,6 +287,23 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); + String base_dir = file_path.get_base_dir().trim_suffix("/").trim_suffix("\\"); + + if (base_dir != contents_dir && base_dir.begins_with(contents_dir)) { + base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/").trim_prefix("\\"); + file = base_dir.plus_file(file); + + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_CONTINUE(!da); + + String output_dir = template_path.plus_file(base_dir); + + if (!DirAccess::exists(output_dir)) { + Error mkdir_err = da->make_dir_recursive(output_dir); + ERR_CONTINUE(mkdir_err != OK); + } + } + if (p) { p->step(TTR("Importing:") + " " + file, fc); } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index b1aa75e124..0c3c222085 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -66,7 +66,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_selectable(0, true); String lpath = p_dir->get_path(); subdirectory_item->set_metadata(0, lpath); - if (!p_select_in_favorites && (path == lpath || ((display_mode_setting == DISPLAY_MODE_SETTING_SPLIT) && path.get_base_dir() == lpath))) { + if (!p_select_in_favorites && (path == lpath || ((display_mode == DISPLAY_MODE_SPLIT) && path.get_base_dir() == lpath))) { subdirectory_item->select(0); } @@ -84,7 +84,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory parent_should_expand = (_create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites) || parent_should_expand); // Create all items for the files in the subdirectory - if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) { + if (display_mode == DISPLAY_MODE_TREE_ONLY) { for (int i = 0; i < p_dir->get_file_count(); i++) { String file_name = p_dir->get_file(i); @@ -229,19 +229,21 @@ void FileSystemDock::_update_tree(const Vector<String> p_uncollapsed_paths, bool updating_tree = false; } +void FileSystemDock::set_display_mode(DisplayMode p_display_mode) { + display_mode = p_display_mode; + emit_signal("display_mode_changed"); + _update_display_mode(false); +} + void FileSystemDock::_update_display_mode(bool p_force) { // Compute the new display mode - DisplayMode new_display_mode = (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) ? DISPLAY_MODE_TREE_ONLY : DISPLAY_MODE_SPLIT; - - if (p_force || new_display_mode != display_mode || old_display_mode_setting != display_mode_setting) { - display_mode = new_display_mode; - old_display_mode_setting = display_mode_setting; - button_toggle_display_mode->set_pressed(display_mode_setting == DISPLAY_MODE_SETTING_SPLIT ? true : false); + if (p_force || old_display_mode != display_mode) { + button_toggle_display_mode->set_pressed(display_mode == DISPLAY_MODE_SPLIT ? true : false); switch (display_mode) { case DISPLAY_MODE_TREE_ONLY: tree->show(); tree->set_v_size_flags(SIZE_EXPAND_FILL); - if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) { + if (display_mode == DISPLAY_MODE_TREE_ONLY) { tree_search_box->show(); } else { tree_search_box->hide(); @@ -262,6 +264,7 @@ void FileSystemDock::_update_display_mode(bool p_force) { _update_file_list(true); break; } + old_display_mode = display_mode; } } @@ -269,9 +272,6 @@ void FileSystemDock::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_RESIZED: { - _update_display_mode(); - } break; case NOTIFICATION_ENTER_TREE: { if (initialized) @@ -302,7 +302,6 @@ void FileSystemDock::_notification(int p_what) { current_path->connect("text_entered", this, "_navigate_to_path"); - display_mode_setting = DisplayModeSetting(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"))); always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders")); _update_display_mode(); @@ -362,27 +361,10 @@ void FileSystemDock::_notification(int p_what) { file_list_search_box->set_right_icon(get_icon("Search", ei)); file_list_search_box->set_clear_button_enabled(true); - bool should_update_files = false; - - // Update file list display mode - int new_file_list_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/files_display_mode")); - if (new_file_list_mode != file_list_display_mode) { - set_file_list_display_mode(new_file_list_mode); - _update_file_list_display_mode_button(); - should_update_files = true; - } - - // Update display of files in tree - display_mode_setting = DisplayModeSetting(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"))); - // Update always showfolders bool new_always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders")); if (new_always_show_folders != always_show_folders) { always_show_folders = new_always_show_folders; - should_update_files = true; - } - - if (should_update_files) { _update_file_list(true); } @@ -530,6 +512,7 @@ void FileSystemDock::_update_file_list_display_mode_button() { button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons")); button_file_list_display_mode->set_tooltip(TTR("View items as a list.")); } + emit_signal("display_mode_changed"); } void FileSystemDock::_change_file_display() { @@ -1695,9 +1678,7 @@ void FileSystemDock::_rescan() { } void FileSystemDock::_toggle_split_mode(bool p_active) { - display_mode_setting = p_active ? DISPLAY_MODE_SETTING_SPLIT : DISPLAY_MODE_SETTING_TREE_ONLY; - EditorSettings::get_singleton()->set("docks/filesystem/display_mode", int(display_mode_setting)); - _update_display_mode(); + set_display_mode(p_active ? DISPLAY_MODE_SPLIT : DISPLAY_MODE_TREE_ONLY); } void FileSystemDock::fix_dependencies(const String &p_for_file) { @@ -1709,7 +1690,7 @@ void FileSystemDock::focus_on_filter() { file_list_search_box->grab_focus(); } -void FileSystemDock::set_file_list_display_mode(int p_mode) { +void FileSystemDock::set_file_list_display_mode(FileListDisplayMode p_mode) { if (p_mode == file_list_display_mode) return; @@ -2219,7 +2200,7 @@ void FileSystemDock::_update_import_dock() { // List selected Vector<String> selected; - if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) { + if (display_mode == DISPLAY_MODE_TREE_ONLY) { // Use the tree selected = _tree_get_selected(); @@ -2334,6 +2315,8 @@ void FileSystemDock::_bind_methods() { ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder"))); ADD_SIGNAL(MethodInfo("files_moved", PropertyInfo(Variant::STRING, "old_file"), PropertyInfo(Variant::STRING, "new_file"))); ADD_SIGNAL(MethodInfo("folder_moved", PropertyInfo(Variant::STRING, "old_folder"), PropertyInfo(Variant::STRING, "new_file"))); + + ADD_SIGNAL(MethodInfo("display_mode_changed")); } FileSystemDock::FileSystemDock(EditorNode *p_editor) { @@ -2564,11 +2547,10 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { history_max_size = 20; history.push_back("res://"); - display_mode = DISPLAY_MODE_SPLIT; + display_mode = DISPLAY_MODE_TREE_ONLY; + old_display_mode = DISPLAY_MODE_TREE_ONLY; file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS; - display_mode_setting = DISPLAY_MODE_SETTING_TREE_ONLY; - old_display_mode_setting = DISPLAY_MODE_SETTING_TREE_ONLY; always_show_folders = false; } diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 237413acc4..e31afee23e 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -65,17 +65,12 @@ public: FILE_LIST_DISPLAY_LIST }; -private: - enum DisplayModeSetting { - DISPLAY_MODE_SETTING_TREE_ONLY, - DISPLAY_MODE_SETTING_SPLIT, - }; - enum DisplayMode { DISPLAY_MODE_TREE_ONLY, DISPLAY_MODE_SPLIT, }; +private: enum FileMenu { FILE_OPEN, FILE_INSTANCE, @@ -123,8 +118,7 @@ private: FileListDisplayMode file_list_display_mode; DisplayMode display_mode; - DisplayModeSetting display_mode_setting; - DisplayModeSetting old_display_mode_setting; + DisplayMode old_display_mode; PopupMenu *file_list_popup; PopupMenu *tree_popup; @@ -287,12 +281,16 @@ public: void fix_dependencies(const String &p_for_file); - void set_file_list_display_mode(int p_mode); - int get_split_offset() { return split_box->get_split_offset(); } void set_split_offset(int p_offset) { split_box->set_split_offset(p_offset); } void select_file(const String &p_file); + void set_display_mode(DisplayMode p_display_mode); + DisplayMode get_display_mode() { return display_mode; } + + void set_file_list_display_mode(FileListDisplayMode p_mode); + FileListDisplayMode get_file_list_display_mode() { return file_list_display_mode; }; + FileSystemDock(EditorNode *p_editor); ~FileSystemDock(); }; diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp index e365471733..98f4947c2d 100644 --- a/editor/import/editor_import_plugin.cpp +++ b/editor/import/editor_import_plugin.cpp @@ -130,7 +130,7 @@ bool EditorImportPlugin::get_option_visibility(const String &p_option, const Map return get_script_instance()->call("get_option_visibility", p_option, d); } -Error EditorImportPlugin::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error EditorImportPlugin::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("import")), ERR_UNAVAILABLE); Dictionary options; diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h index 607d99e6e2..d396dd6d5b 100644 --- a/editor/import/editor_import_plugin.h +++ b/editor/import/editor_import_plugin.h @@ -51,7 +51,7 @@ public: virtual int get_import_order() const; virtual void get_import_options(List<ImportOption> *r_options, int p_preset) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata = NULL); }; #endif //EDITOR_IMPORT_PLUGIN_H diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp index b568cbda9b..18e53fc783 100644 --- a/editor/import/resource_importer_bitmask.cpp +++ b/editor/import/resource_importer_bitmask.cpp @@ -78,7 +78,7 @@ void ResourceImporterBitMap::get_import_options(List<ImportOption> *r_options, i r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.5)); } -Error ResourceImporterBitMap::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterBitMap::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { int create_from = p_options["create_from"]; float threshold = p_options["threshold"]; diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h index 7cfb0c4a98..166fa998e4 100644 --- a/editor/import/resource_importer_bitmask.h +++ b/editor/import/resource_importer_bitmask.h @@ -51,7 +51,7 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); ResourceImporterBitMap(); ~ResourceImporterBitMap(); diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index be5ce34c25..b4b3e0e551 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -77,7 +77,7 @@ void ResourceImporterCSVTranslation::get_import_options(List<ImportOption> *r_op r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "delimiter", PROPERTY_HINT_ENUM, "Comma,Semicolon,Tab"), 0)); } -Error ResourceImporterCSVTranslation::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterCSVTranslation::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { bool compress = p_options["compress"]; diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h index cf16826535..6785b68d87 100644 --- a/editor/import/resource_importer_csv_translation.h +++ b/editor/import/resource_importer_csv_translation.h @@ -48,7 +48,7 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); ResourceImporterCSVTranslation(); }; diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp index c3421466f2..1259e81be7 100644 --- a/editor/import/resource_importer_image.cpp +++ b/editor/import/resource_importer_image.cpp @@ -74,7 +74,7 @@ String ResourceImporterImage::get_preset_name(int p_idx) const { void ResourceImporterImage::get_import_options(List<ImportOption> *r_options, int p_preset) const { } -Error ResourceImporterImage::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterImage::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); if (!f) { diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h index ffe05bdf58..3d5b99db2c 100644 --- a/editor/import/resource_importer_image.h +++ b/editor/import/resource_importer_image.h @@ -49,7 +49,7 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); ResourceImporterImage(); }; diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index e38265b619..7e3c4cecf4 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -191,7 +191,7 @@ void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_imag memdelete(f); } -Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { int compress_mode = p_options["compress/mode"]; int no_bptc_if_rgb = p_options["compress/no_bptc_if_rgb"]; @@ -252,6 +252,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const } String extension = get_save_extension(); + Array formats_imported; if (compress_mode == COMPRESS_VIDEO_RAM) { //must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). @@ -270,6 +271,8 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const encode_bptc = false; } } + + formats_imported.push_back("bptc"); } if (encode_bptc) { @@ -284,23 +287,27 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, Image::COMPRESS_S3TC, mipmaps, tex_flags); r_platform_variants->push_back("s3tc"); ok_on_pc = true; + formats_imported.push_back("s3tc"); } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) { _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, Image::COMPRESS_ETC2, mipmaps, tex_flags); r_platform_variants->push_back("etc2"); + formats_imported.push_back("etc2"); } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) { _save_tex(slices, p_save_path + ".etc." + extension, compress_mode, Image::COMPRESS_ETC, mipmaps, tex_flags); r_platform_variants->push_back("etc"); + formats_imported.push_back("etc"); } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { _save_tex(slices, p_save_path + ".pvrtc." + extension, compress_mode, Image::COMPRESS_PVRTC4, mipmaps, tex_flags); r_platform_variants->push_back("pvrtc"); + formats_imported.push_back("pvrtc"); } if (!ok_on_pc) { @@ -311,9 +318,79 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const _save_tex(slices, p_save_path + "." + extension, compress_mode, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags); } + if (r_metadata) { + Dictionary metadata; + metadata["vram_texture"] = compress_mode == COMPRESS_VIDEO_RAM; + if (formats_imported.size()) { + metadata["imported_formats"] = formats_imported; + } + *r_metadata = metadata; + } + return OK; } +const char *ResourceImporterLayeredTexture::compression_formats[] = { + "bptc", + "s3tc", + "etc", + "etc2", + "pvrtc", + NULL +}; +String ResourceImporterLayeredTexture::get_import_settings_string() const { + + String s; + + int index = 0; + while (compression_formats[index]) { + String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]); + bool test = ProjectSettings::get_singleton()->get(setting_path); + if (test) { + s += String(compression_formats[index]); + } + index++; + } + + return s; +} + +bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_path) const { + + //will become invalid if formats are missing to import + Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path); + + if (!metadata.has("vram_texture")) { + return false; + } + + bool vram = metadata["vram_texture"]; + if (!vram) { + return true; //do not care about non vram + } + + Vector<String> formats_imported; + if (metadata.has("imported_formats")) { + formats_imported = metadata["imported_formats"]; + } + + int index = 0; + bool valid = true; + while (compression_formats[index]) { + String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]); + bool test = ProjectSettings::get_singleton()->get(setting_path); + if (test) { + if (formats_imported.find(compression_formats[index]) == -1) { + valid = false; + break; + } + } + index++; + } + + return valid; +} + ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL; ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() { diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h index 6a616e09d6..6b393886b7 100644 --- a/editor/import/resource_importer_layered_texture.h +++ b/editor/import/resource_importer_layered_texture.h @@ -40,6 +40,7 @@ class ResourceImporterLayeredTexture : public ResourceImporter { GDCLASS(ResourceImporterLayeredTexture, ResourceImporter) bool is_3d; + static const char *compression_formats[]; protected: static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex); @@ -76,10 +77,13 @@ public: void _save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags); - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); void update_imports(); + virtual bool are_import_settings_valid(const String &p_path) const; + virtual String get_import_settings_string() const; + void set_3d(bool p_3d) { is_3d = p_3d; } ResourceImporterLayeredTexture(); ~ResourceImporterLayeredTexture(); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 030b54a589..e950421476 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -499,7 +499,7 @@ bool ResourceImporterOBJ::get_option_visibility(const String &p_option, const Ma return true; } -Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { List<Ref<Mesh> > meshes; diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index effc56ad95..b2a53f582c 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -61,7 +61,7 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); ResourceImporterOBJ(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index ad436b2797..76552575da 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1183,7 +1183,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito return importer->import_animation(p_path, p_flags, p_bake_fps); } -Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { String src_path = p_source_file; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 9d06b411d6..99f8b1a8e0 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -153,7 +153,7 @@ public: void _filter_tracks(Node *scene, const String &p_text); void _optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle); - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index a3bc9d0ec9..631b2359c5 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -219,7 +219,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options, r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0)); } -void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal) { +void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal, bool p_force_po2_for_compressed) { FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE); f->store_8('G'); @@ -227,8 +227,20 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String f->store_8('S'); f->store_8('T'); //godot streamable texture - f->store_32(p_image->get_width()); - f->store_32(p_image->get_height()); + bool resize_to_po2 = false; + + if (p_compress_mode == COMPRESS_VIDEO_RAM && p_force_po2_for_compressed && (p_mipmaps || p_texture_flags & Texture::FLAG_REPEAT)) { + resize_to_po2 = true; + f->store_16(next_power_of_2(p_image->get_width())); + f->store_16(p_image->get_width()); + f->store_16(next_power_of_2(p_image->get_height())); + f->store_16(p_image->get_height()); + } else { + f->store_16(p_image->get_width()); + f->store_16(0); + f->store_16(p_image->get_height()); + f->store_16(0); + } f->store_32(p_texture_flags); uint32_t format = 0; @@ -310,6 +322,9 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String case COMPRESS_VIDEO_RAM: { Ref<Image> image = p_image->duplicate(); + if (resize_to_po2) { + image->resize_to_po2(); + } if (p_mipmaps) { image->generate_mipmaps(p_force_normal); } @@ -360,7 +375,7 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String memdelete(f); } -Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { int compress_mode = p_options["compress/mode"]; float lossy = p_options["compress/lossy_quality"]; @@ -386,6 +401,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String if (err != OK) return err; + Array formats_imported; + int tex_flags = 0; if (repeat > 0) tex_flags |= Texture::FLAG_REPEAT; @@ -470,6 +487,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String can_bptc = false; } } + + formats_imported.push_back("bptc"); } if (!can_bptc && is_hdr && !force_rgbe) { @@ -478,26 +497,30 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String } if (can_bptc || can_s3tc) { - _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); + _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false); r_platform_variants->push_back("s3tc"); + formats_imported.push_back("s3tc"); ok_on_pc = true; } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) { - _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); + _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false); r_platform_variants->push_back("etc2"); + formats_imported.push_back("etc2"); } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) { - _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); + _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true); r_platform_variants->push_back("etc"); + formats_imported.push_back("etc"); } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { - _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); + _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true); r_platform_variants->push_back("pvrtc"); + formats_imported.push_back("pvrtc"); } if (!ok_on_pc) { @@ -505,12 +528,81 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String } } else { //import normally - _save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); + _save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false); } + if (r_metadata) { + Dictionary metadata; + metadata["vram_texture"] = compress_mode == COMPRESS_VIDEO_RAM; + if (formats_imported.size()) { + metadata["imported_formats"] = formats_imported; + } + *r_metadata = metadata; + } return OK; } +const char *ResourceImporterTexture::compression_formats[] = { + "bptc", + "s3tc", + "etc", + "etc2", + "pvrtc", + NULL +}; +String ResourceImporterTexture::get_import_settings_string() const { + + String s; + + int index = 0; + while (compression_formats[index]) { + String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]); + bool test = ProjectSettings::get_singleton()->get(setting_path); + if (test) { + s += String(compression_formats[index]); + } + index++; + } + + return s; +} + +bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) const { + + //will become invalid if formats are missing to import + Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path); + + if (!metadata.has("vram_texture")) { + return false; + } + + bool vram = metadata["vram_texture"]; + if (!vram) { + return true; //do not care about non vram + } + + Vector<String> formats_imported; + if (metadata.has("imported_formats")) { + formats_imported = metadata["imported_formats"]; + } + + int index = 0; + bool valid = true; + while (compression_formats[index]) { + String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]); + bool test = ProjectSettings::get_singleton()->get(setting_path); + if (test) { + if (formats_imported.find(compression_formats[index]) == -1) { + valid = false; + break; + } + } + index++; + } + + return valid; +} + ResourceImporterTexture *ResourceImporterTexture::singleton = NULL; ResourceImporterTexture::ResourceImporterTexture() { diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index 408af1edcf..ef74e4e41e 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -54,6 +54,7 @@ protected: static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex); static ResourceImporterTexture *singleton; + static const char *compression_formats[]; public: static ResourceImporterTexture *get_singleton() { return singleton; } @@ -83,12 +84,15 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal); + void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal, bool p_force_po2_for_compressed); - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); void update_imports(); + virtual bool are_import_settings_valid(const String &p_path) const; + virtual String get_import_settings_string() const; + ResourceImporterTexture(); ~ResourceImporterTexture(); }; diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 76ab7a7037..857d8992fd 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -82,7 +82,7 @@ void ResourceImporterWAV::get_import_options(List<ImportOption> *r_options, int r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Disabled,RAM (Ima-ADPCM)"), 0)); } -Error ResourceImporterWAV::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterWAV::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { /* STEP 1, READ WAVE FILE */ diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h index 755dea3d84..f993f9e7bc 100644 --- a/editor/import/resource_importer_wav.h +++ b/editor/import/resource_importer_wav.h @@ -161,7 +161,7 @@ public: } } - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); ResourceImporterWAV(); }; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index eef3358260..afe2573898 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -231,6 +231,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { } pb->set_percent_visible(false); + pb->set_custom_minimum_size(Vector2(0, 14) * EDSCALE); animations[E->get()] = pb; node->add_child(pb); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 3cf46e5b91..58d7968723 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -92,7 +92,12 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 if (!tex.is_valid()) { return Ref<Texture>(); } + Ref<Image> atlas = tex->get_data(); + if (!atlas.is_valid()) { + return Ref<Texture>(); + } + img = atlas->get_rect(atex->get_region()); } else if (ltex.is_valid()) { img = ltex->to_image(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 1bcb7513e0..5f4c4a610a 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1425,6 +1425,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { workspace->update(); } else { creating_shape = true; + edited_collision_shape = Ref<ConvexPolygonShape2D>(); current_shape.resize(0); current_shape.push_back(snap_point(pos)); workspace->update(); @@ -1444,6 +1445,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) { if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + edited_collision_shape = Ref<ConvexPolygonShape2D>(); current_shape.resize(0); current_shape.push_back(snap_point(shape_anchor)); current_shape.push_back(snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0))); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index e27fa01a26..0a8e7ea779 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -730,7 +730,7 @@ void EditorSpatialGizmo::set_plugin(EditorSpatialGizmoPlugin *p_plugin) { void EditorSpatialGizmo::_bind_methods() { ClassDB::bind_method(D_METHOD("add_lines", "lines", "material", "billboard"), &EditorSpatialGizmo::add_lines, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "billboard", "skeleton"), &EditorSpatialGizmo::add_mesh, DEFVAL(false), DEFVAL(RID()), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "billboard", "skeleton", "material"), &EditorSpatialGizmo::add_mesh, DEFVAL(false), DEFVAL(RID()), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorSpatialGizmo::add_collision_segments); ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorSpatialGizmo::add_collision_triangles); ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale"), &EditorSpatialGizmo::add_unscaled_billboard, DEFVAL(1)); diff --git a/main/main.cpp b/main/main.cpp index b52e03add3..9b062d3951 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -757,7 +757,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph editor = false; #else String error_msg = "Error: Could not load game data at path '" + project_path + "'. Is the .pck file missing?\n"; - OS::get_singleton()->print(error_msg.ascii().get_data()); + OS::get_singleton()->print("%s", error_msg.ascii().get_data()); OS::get_singleton()->alert(error_msg); goto error; @@ -1612,7 +1612,7 @@ bool Main::start() { String stretch_mode = GLOBAL_DEF("display/window/stretch/mode", "disabled"); String stretch_aspect = GLOBAL_DEF("display/window/stretch/aspect", "ignore"); Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0)); - real_t stretch_shrink = GLOBAL_DEF("display/window/stretch/shrink", 1.0f); + real_t stretch_shrink = GLOBAL_DEF("display/window/stretch/shrink", 1.0); SceneTree::StretchMode sml_sm = SceneTree::STRETCH_MODE_DISABLED; if (stretch_mode == "2d") @@ -1664,8 +1664,8 @@ bool Main::start() { ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport")); GLOBAL_DEF("display/window/stretch/aspect", "ignore"); ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand")); - GLOBAL_DEF("display/window/stretch/shrink", 1); - ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::REAL, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1,8,1")); + GLOBAL_DEF("display/window/stretch/shrink", 1.0); + ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::REAL, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1.0,8.0,0.1")); sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true)); sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true)); GLOBAL_DEF("gui/common/snap_controls_to_pixels", true); diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp index edc4fb0c97..3465fd783e 100644 --- a/main/tests/test_string.cpp +++ b/main/tests/test_string.cpp @@ -457,7 +457,7 @@ bool test_27() { state = s.begins_with(sb) == tc[i].expected; } if (!state) { - OS::get_singleton()->print("\n\t Failure on:\n\t\tstring: ", tc[i].data, "\n\t\tbegin: ", tc[i].begin, "\n\t\texpected: ", tc[i].expected ? "true" : "false", "\n"); + OS::get_singleton()->print("\n\t Failure on:\n\t\tstring: %s\n\t\tbegin: %s\n\t\texpected: %s\n", tc[i].data, tc[i].begin, tc[i].expected ? "true" : "false"); break; } }; diff --git a/methods.py b/methods.py index d8e90a8da5..2d4dc4921f 100644 --- a/methods.py +++ b/methods.py @@ -667,3 +667,6 @@ def get_compiler_version(env): return match.group().split('.') else: return None + +def use_gcc(env): + return 'gcc' in os.path.basename(env["CC"]) diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index bdcd51085f..71e7eecd1d 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -6419,6 +6419,41 @@ ] } ] + }, + { + "name": "net", + "type": "NET", + "version": { + "major": 3, + "minor": 1 + }, + "next": null, + "api": [ + { + "name": "godot_net_bind_stream_peer", + "return_type": "void", + "arguments": [ + ["godot_object *", "p_obj"], + ["const godot_net_stream_peer *", "p_interface"] + ] + }, + { + "name": "godot_net_bind_packet_peer", + "return_type": "void", + "arguments": [ + ["godot_object *", "p_obj"], + ["const godot_net_packet_peer *", "p_interface"] + ] + }, + { + "name": "godot_net_bind_multiplayer_peer", + "return_type": "void", + "arguments": [ + ["godot_object *", "p_obj"], + ["const godot_net_multiplayer_peer *", "p_interface"] + ] + } + ] } ] } diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py index 5fd5971fd1..7ab0e01108 100644 --- a/modules/gdnative/gdnative_builders.py +++ b/modules/gdnative/gdnative_builders.py @@ -45,6 +45,7 @@ def _build_gdnative_api_struct_header(api): '#include <android/godot_android.h>', '#include <arvr/godot_arvr.h>', '#include <nativescript/godot_nativescript.h>', + '#include <net/godot_net.h>', '#include <pluginscript/godot_pluginscript.h>', '#include <videodecoder/godot_videodecoder.h>', '', diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h index 89e2771926..d7de04e725 100644 --- a/modules/gdnative/include/net/godot_net.h +++ b/modules/gdnative/include/net/godot_net.h @@ -51,9 +51,9 @@ typedef struct { /* This is StreamPeer */ godot_error (*get_data)(void *user, uint8_t *p_buffer, int p_bytes); - godot_error (*get_partial_data)(void *user, uint8_t *p_buffer, int p_bytes, int &r_received); + godot_error (*get_partial_data)(void *user, uint8_t *p_buffer, int p_bytes, int *r_received); godot_error (*put_data)(void *user, const uint8_t *p_data, int p_bytes); - godot_error (*put_partial_data)(void *user, const uint8_t *p_data, int p_bytes, int &r_sent); + godot_error (*put_partial_data)(void *user, const uint8_t *p_data, int p_bytes, int *r_sent); int (*get_available_bytes)(const void *user); @@ -61,7 +61,7 @@ typedef struct { } godot_net_stream_peer; /* Binds a StreamPeerGDNative to the provided interface */ -void godot_net_bind_stream_peer(godot_object *p_obj, godot_net_stream_peer *p_interface); +void godot_net_bind_stream_peer(godot_object *p_obj, const godot_net_stream_peer *p_interface); typedef struct { godot_gdnative_api_version version; /* version of our API */ @@ -69,7 +69,7 @@ typedef struct { godot_object *data; /* User reference */ /* This is PacketPeer */ - godot_error (*get_packet)(void *, const uint8_t **, int &); + godot_error (*get_packet)(void *, const uint8_t **, int *); godot_error (*put_packet)(void *, const uint8_t *, int); godot_int (*get_available_packet_count)(const void *); godot_int (*get_max_packet_size)(const void *); @@ -86,7 +86,7 @@ typedef struct { godot_object *data; /* User reference */ /* This is PacketPeer */ - godot_error (*get_packet)(void *, const uint8_t **, int &); + godot_error (*get_packet)(void *, const uint8_t **, int *); godot_error (*put_packet)(void *, const uint8_t *, int); godot_int (*get_available_packet_count)(const void *); godot_int (*get_max_packet_size)(const void *); diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 9fd0a2e8ec..c2b772df85 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -1599,18 +1599,20 @@ bool NativeScriptLanguage::handles_global_class_type(const String &p_type) const } String NativeScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { - Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript"); - if (script.is_valid()) { + if (!p_path.empty()) { + Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript"); + if (script.is_valid()) { + if (r_base_type) + *r_base_type = script->get_instance_base_type(); + if (r_icon_path) + *r_icon_path = script->get_script_class_icon_path(); + return script->get_script_class_name(); + } if (r_base_type) - *r_base_type = script->get_instance_base_type(); + *r_base_type = String(); if (r_icon_path) - *r_icon_path = script->get_script_class_icon_path(); - return script->get_script_class_name(); + *r_icon_path = String(); } - if (r_base_type) - *r_base_type = String(); - if (r_icon_path) - *r_icon_path = String(); return String(); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp index 2466838357..bdeba149d2 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -43,7 +43,7 @@ void MultiplayerPeerGDNative::set_native_multiplayer_peer(const godot_net_multip Error MultiplayerPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); - return (Error)interface->get_packet(interface->data, r_buffer, r_buffer_size); + return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); } Error MultiplayerPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { diff --git a/modules/gdnative/net/packet_peer_gdnative.cpp b/modules/gdnative/net/packet_peer_gdnative.cpp index 9adfd841b2..877baff9e2 100644 --- a/modules/gdnative/net/packet_peer_gdnative.cpp +++ b/modules/gdnative/net/packet_peer_gdnative.cpp @@ -46,7 +46,7 @@ void PacketPeerGDNative::_bind_methods() { Error PacketPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); - return (Error)interface->get_packet(interface->data, r_buffer, r_buffer_size); + return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); } Error PacketPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { diff --git a/modules/gdnative/net/stream_peer_gdnative.cpp b/modules/gdnative/net/stream_peer_gdnative.cpp index 1b141fa2e6..8a4ea35f95 100644 --- a/modules/gdnative/net/stream_peer_gdnative.cpp +++ b/modules/gdnative/net/stream_peer_gdnative.cpp @@ -37,7 +37,7 @@ StreamPeerGDNative::StreamPeerGDNative() { StreamPeerGDNative::~StreamPeerGDNative() { } -void StreamPeerGDNative::set_native_stream_peer(godot_net_stream_peer *p_interface) { +void StreamPeerGDNative::set_native_stream_peer(const godot_net_stream_peer *p_interface) { interface = p_interface; } @@ -51,7 +51,7 @@ Error StreamPeerGDNative::put_data(const uint8_t *p_data, int p_bytes) { Error StreamPeerGDNative::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); - return (Error)(interface->put_partial_data(interface->data, p_data, p_bytes, r_sent)); + return (Error)(interface->put_partial_data(interface->data, p_data, p_bytes, &r_sent)); } Error StreamPeerGDNative::get_data(uint8_t *p_buffer, int p_bytes) { @@ -61,7 +61,7 @@ Error StreamPeerGDNative::get_data(uint8_t *p_buffer, int p_bytes) { Error StreamPeerGDNative::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); - return (Error)(interface->get_partial_data(interface->data, p_buffer, p_bytes, r_received)); + return (Error)(interface->get_partial_data(interface->data, p_buffer, p_bytes, &r_received)); } int StreamPeerGDNative::get_available_bytes() const { @@ -71,7 +71,7 @@ int StreamPeerGDNative::get_available_bytes() const { extern "C" { -void GDAPI godot_net_bind_stream_peer(godot_object *p_obj, godot_net_stream_peer *p_interface) { +void GDAPI godot_net_bind_stream_peer(godot_object *p_obj, const godot_net_stream_peer *p_interface) { ((StreamPeerGDNative *)p_obj)->set_native_stream_peer(p_interface); } } diff --git a/modules/gdnative/net/stream_peer_gdnative.h b/modules/gdnative/net/stream_peer_gdnative.h index f39fdbb1d3..7859d57a4b 100644 --- a/modules/gdnative/net/stream_peer_gdnative.h +++ b/modules/gdnative/net/stream_peer_gdnative.h @@ -41,14 +41,14 @@ class StreamPeerGDNative : public StreamPeer { protected: static void _bind_methods(); - godot_net_stream_peer *interface; + const godot_net_stream_peer *interface; public: StreamPeerGDNative(); ~StreamPeerGDNative(); /* Sets the interface implementation from GDNative */ - void set_native_stream_peer(godot_net_stream_peer *p_interface); + void set_native_stream_peer(const godot_net_stream_peer *p_interface); /* Specific to StreamPeer */ Error put_data(const uint8_t *p_data, int p_bytes); diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp index 8c2a84f60b..d1794b6c36 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp @@ -76,7 +76,7 @@ int64_t GDAPI godot_videodecoder_file_seek(void *ptr, int64_t pos, int whence) { } break; case SEEK_CUR: { // Just in case it doesn't exist - if (pos < 0 && -pos > file->get_position()) { + if (pos < 0 && (size_t)-pos > file->get_position()) { return -1; } pos = pos + static_cast<int>(file->get_position()); @@ -86,7 +86,7 @@ int64_t GDAPI godot_videodecoder_file_seek(void *ptr, int64_t pos, int whence) { } break; case SEEK_END: { // Just in case something goes wrong - if (-pos > len) { + if ((size_t)-pos > len) { return -1; } file->seek_end(pos); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index adbd7e4e04..5ebf68177d 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -4691,6 +4691,16 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { ConstantNode *cn = static_cast<ConstantNode *>(subexpr); if (cn->value.get_type() != Variant::NIL) { + if (member._export.type != Variant::NIL && cn->value.get_type() != member._export.type) { + if (Variant::can_convert(cn->value.get_type(), member._export.type)) { + Variant::CallError err; + const Variant *args = &cn->value; + cn->value = Variant::construct(member._export.type, &args, 1, err); + } else { + _set_error("Cannot convert the provided value to the export type."); + return; + } + } member.default_value = cn->value; } } diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 480bf0fa3c..8b22d6f085 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -1417,7 +1417,7 @@ StringName GDScriptTokenizerBuffer::get_token_identifier(int p_offset) const { ERR_FAIL_INDEX_V(offset, tokens.size(), StringName()); uint32_t identifier = tokens[offset] >> TOKEN_BITS; - ERR_FAIL_UNSIGNED_INDEX_V(identifier, identifiers.size(), StringName()); + ERR_FAIL_UNSIGNED_INDEX_V(identifier, (uint32_t)identifiers.size(), StringName()); return identifiers[identifier]; } @@ -1473,7 +1473,7 @@ const Variant &GDScriptTokenizerBuffer::get_token_constant(int p_offset) const { int offset = token + p_offset; ERR_FAIL_INDEX_V(offset, tokens.size(), nil); uint32_t constant = tokens[offset] >> TOKEN_BITS; - ERR_FAIL_UNSIGNED_INDEX_V(constant, constants.size(), nil); + ERR_FAIL_UNSIGNED_INDEX_V(constant, (uint32_t)constants.size(), nil); return constants[constant]; } String GDScriptTokenizerBuffer::get_token_error(int p_offset) const { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 51615df64e..a7ac7f46c5 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -449,7 +449,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) { Variant::_RID }; - for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) { + for (unsigned int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) { if (p_var_type_name == Variant::get_type_name(var_types[i])) return p_var_type_name; } @@ -2172,7 +2172,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ return false; } - if (val != i) { + if (val != (unsigned int)i) { uses_default_values = false; } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index cffccd5cb5..890bea0d1d 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -703,7 +703,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls; if (verbose_output) - OS::get_singleton()->print(String("Generating " + itype.proxy_name + ".cs...\n").utf8()); + OS::get_singleton()->print("Generating %s.cs...\n", itype.proxy_name.utf8().get_data()); String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types @@ -1280,7 +1280,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls; - OS::get_singleton()->print(String("Generating " + itype.name + "...\n").utf8()); + OS::get_singleton()->print("Generating %s...\n", itype.name.utf8().get_data()); String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 17e29fba19..5b68810017 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -167,9 +167,6 @@ void GodotSharpEditor::_remove_create_sln_menu_option() { menu_popup->remove_item(menu_popup->get_item_index(MENU_CREATE_SLN)); - if (menu_popup->get_item_count() == 0) - menu_button->hide(); - bottom_panel_btn->show(); } @@ -277,43 +274,23 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int // TODO: Use initializer lists once C++11 is allowed - // Try with hint paths - static Vector<String> hint_paths; -#ifdef WINDOWS_ENABLED - if (hint_paths.empty()) { - hint_paths.push_back(OS::get_singleton()->get_environment("ProgramFiles") + "\\Microsoft VS Code\\Code.exe"); - if (sizeof(size_t) == 8) { - hint_paths.push_back(OS::get_singleton()->get_environment("ProgramFiles(x86)") + "\\Microsoft VS Code\\Code.exe"); - } + static Vector<String> vscode_names; + if (vscode_names.empty()) { + vscode_names.push_back("code"); + vscode_names.push_back("code-oss"); + vscode_names.push_back("vscode"); + vscode_names.push_back("vscode-oss"); + vscode_names.push_back("visual-studio-code"); + vscode_names.push_back("visual-studio-code-oss"); } -#endif - for (int i = 0; i < hint_paths.size(); i++) { - vscode_path = hint_paths[i]; - if (FileAccess::exists(vscode_path)) { + for (int i = 0; i < vscode_names.size(); i++) { + vscode_path = path_which(vscode_names[i]); + if (!vscode_path.empty()) { found = true; break; } } - if (!found) { - static Vector<String> vscode_names; - if (vscode_names.empty()) { - vscode_names.push_back("code"); - vscode_names.push_back("code-oss"); - vscode_names.push_back("vscode"); - vscode_names.push_back("vscode-oss"); - vscode_names.push_back("visual-studio-code"); - vscode_names.push_back("visual-studio-code-oss"); - } - for (int i = 0; i < vscode_names.size(); i++) { - vscode_path = path_which(vscode_names[i]); - if (!vscode_path.empty()) { - found = true; - break; - } - } - } - if (!found) vscode_path.clear(); // Not found, clear so next time the empty() check is enough } @@ -433,9 +410,12 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { editor->add_child(memnew(MonoReloadNode)); - menu_button = memnew(MenuButton); - menu_button->set_text(TTR("Mono")); - menu_popup = menu_button->get_popup(); + menu_popup = memnew(PopupMenu); + menu_popup->hide(); + menu_popup->set_as_toplevel(true); + menu_popup->set_pass_on_modal_close_click(false); + + editor->add_tool_submenu_item("Mono", menu_popup); // TODO: Remove or edit this info dialog once Mono support is no longer in alpha { @@ -498,10 +478,12 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { menu_popup->connect("id_pressed", this, "_menu_option_pressed"); - if (menu_popup->get_item_count() == 0) - menu_button->hide(); - - editor->get_menu_hb()->add_child(menu_button); + ToolButton *build_button = memnew(ToolButton); + build_button->set_text("Build"); + build_button->set_tooltip("Build solution"); + build_button->set_focus_mode(Control::FOCUS_NONE); + build_button->connect("pressed", MonoBottomPanel::get_singleton(), "_build_project_pressed"); + editor->get_menu_hb()->add_child(build_button); // External editor settings EditorSettings *ed_settings = EditorSettings::get_singleton(); diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index cc9822e319..21ce9ca5c4 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -125,9 +125,14 @@ void MonoBottomPanel::_build_tabs_item_selected(int p_idx) { void MonoBottomPanel::_build_tabs_nothing_selected() { - if (build_tabs->get_tab_count() != 0) // just in case + if (build_tabs->get_tab_count() != 0) { // just in case build_tabs->set_visible(false); + // This callback is called when clicking on the empty space of the list. + // ItemList won't deselect the items automatically, so we must do it ourselves. + build_tabs_list->unselect_all(); + } + warnings_btn->set_visible(false); errors_btn->set_visible(false); view_log_btn->set_visible(false); diff --git a/modules/mono/editor/mono_bottom_panel.h b/modules/mono/editor/mono_bottom_panel.h index d3109592a9..406e46f7ce 100644 --- a/modules/mono/editor/mono_bottom_panel.h +++ b/modules/mono/editor/mono_bottom_panel.h @@ -51,8 +51,8 @@ class MonoBottomPanel : public VBoxContainer { ItemList *build_tabs_list; TabContainer *build_tabs; - Button *warnings_btn; - Button *errors_btn; + ToolButton *warnings_btn; + ToolButton *errors_btn; Button *view_log_btn; void _update_build_tabs_list(); diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp index 53a043b675..fcc58c22e8 100644 --- a/modules/mono/editor/script_class_parser.cpp +++ b/modules/mono/editor/script_class_parser.cpp @@ -567,7 +567,7 @@ Error ScriptClassParser::parse(const String &p_code) { if (full_name.length()) full_name += "."; full_name += class_decl.name; - OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8()); + OS::get_singleton()->print("%s", String("Ignoring generic class declaration: " + class_decl.name).utf8().get_data()); } } } else if (tk == TK_IDENTIFIER && String(value) == "struct") { diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 0e5747a014..d905810d66 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -86,7 +86,7 @@ bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) { } void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) { - int count = ptr->size(); + unsigned int count = ptr->size(); if (mono_array_length(array) < (array_index + count)) { MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); @@ -94,7 +94,7 @@ void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) { return; } - for (int i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i)); mono_array_setref(array, array_index, boxed); array_index++; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index bba8b1050f..dfabfddd64 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -91,7 +91,7 @@ static bool _wait_for_debugger_msecs(uint32_t p_msecs) { OS::get_singleton()->delay_usec((p_msecs < 25 ? p_msecs : 25) * 1000); - int tdiff = OS::get_singleton()->get_ticks_msec() - last_tick; + uint32_t tdiff = OS::get_singleton()->get_ticks_msec() - last_tick; if (tdiff > p_msecs) { p_msecs = 0; @@ -864,7 +864,7 @@ Error GDMono::reload_scripts_domain() { metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); } - Error err = _unload_scripts_domain(); + err = _unload_scripts_domain(); if (err != OK) { WARN_PRINT("Mono: Failed to unload scripts domain"); } diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp index 01e011e64c..82f323e8cf 100644 --- a/modules/pvr/texture_loader_pvr.cpp +++ b/modules/pvr/texture_loader_pvr.cpp @@ -216,7 +216,7 @@ static void _compress_pvrtc4(Image *p_img) { int ofs, size, w, h; img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); Javelin::RgbaBitmap bm(w, h); - for (unsigned j = 0; j < size / 4; j++) { + for (int j = 0; j < size / 4; j++) { Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); /* red and Green colors are swapped. */ new (dp) Javelin::ColorRgba<unsigned char>(r[ofs + 4 * j + 2], r[ofs + 4 * j + 1], r[ofs + 4 * j], r[ofs + 4 * j + 3]); diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp index 6e12bc9bf0..7254f57672 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp @@ -76,7 +76,7 @@ void ResourceImporterOGGVorbis::get_import_options(List<ImportOption> *r_options r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "loop_offset"), 0)); } -Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { +Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.h b/modules/stb_vorbis/resource_importer_ogg_vorbis.h index f61fc91cda..d3d0574d56 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.h +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.h @@ -49,7 +49,7 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); ResourceImporterOGGVorbis(); }; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index fa7b13bf5b..ac5f73d113 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -421,7 +421,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt } Vector<String> desc = path[path.size() - 1].replace("(", "( ").replace(")", " )").replace(",", ", ").split(" "); - for (size_t i = 0; i < desc.size(); i++) { + for (int i = 0; i < desc.size(); i++) { desc.write[i] = desc[i].capitalize(); if (desc[i].ends_with(",")) { desc.write[i] = desc[i].replace(",", ", "); diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h index 5794288c2b..47786a87a6 100644 --- a/modules/websocket/packet_buffer.h +++ b/modules/websocket/packet_buffer.h @@ -50,7 +50,7 @@ public: Error write_packet(const uint8_t *p_payload, uint32_t p_size, const T *p_info) { #ifdef TOOLS_ENABLED // Verbose buffer warnings - if (p_payload && _payload.space_left() < p_size) { + if (p_payload && _payload.space_left() < (int32_t)p_size) { ERR_PRINT("Buffer payload full! Dropping data."); ERR_FAIL_V(ERR_OUT_OF_MEMORY); } @@ -83,8 +83,8 @@ public: ERR_FAIL_COND_V(_packets.data_left() < 1, ERR_UNAVAILABLE); _Packet p; _packets.read(&p, 1); - ERR_FAIL_COND_V(_payload.data_left() < p.size, ERR_BUG); - ERR_FAIL_COND_V(p_bytes < p.size, ERR_OUT_OF_MEMORY); + ERR_FAIL_COND_V(_payload.data_left() < (int)p.size, ERR_BUG); + ERR_FAIL_COND_V(p_bytes < (int)p.size, ERR_OUT_OF_MEMORY); r_read = p.size; copymem(r_info, &p.info, sizeof(T)); diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index a48738b6a4..6aab8a7e81 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -213,7 +213,7 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) { _send_sys(get_peer(p_peer_id), SYS_ADD, 1); for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) { - uint32_t id = E->key(); + int32_t id = E->key(); if (p_peer_id == id) continue; // Skip the newwly added peer (already confirmed) @@ -226,7 +226,7 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) { void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) { for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) { - uint32_t id = E->key(); + int32_t id = E->key(); if (p_peer_id != id) _send_sys(get_peer(id), SYS_DEL, p_peer_id); } @@ -288,7 +288,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u data_size = size - PROTO_SIZE; uint8_t type = 0; - int32_t from = 0; + uint32_t from = 0; int32_t to = 0; copymem(&type, in_buffer, 1); copymem(&from, &in_buffer[1], 4); diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp index 840dd371ac..903b57f017 100644 --- a/modules/xatlas_unwrap/register_types.cpp +++ b/modules/xatlas_unwrap/register_types.cpp @@ -108,7 +108,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver float max_x = 0; float max_y = 0; - for (int i = 0; i < output->vertexCount; i++) { + for (uint32_t i = 0; i < output->vertexCount; i++) { (*r_vertex)[i] = output->vertexArray[i].xref; (*r_uv)[i * 2 + 0] = output->vertexArray[i].uv[0] / w; (*r_uv)[i * 2 + 1] = output->vertexArray[i].uv[1] / h; @@ -119,7 +119,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver printf("final texsize: %f,%f - max %f,%f\n", w, h, max_x, max_y); *r_vertex_count = output->vertexCount; - for (int i = 0; i < output->indexCount; i++) { + for (uint32_t i = 0; i < output->indexCount; i++) { (*r_index)[i] = output->indexArray[i]; } diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 4b3d93aaa7..8c464465ca 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -31,6 +31,7 @@ #include "dir_access_jandroid.h" #include "core/print_string.h" #include "file_access_jandroid.h" +#include "string_android.h" #include "thread_jandroid.h" jobject DirAccessJAndroid::io = NULL; @@ -69,7 +70,7 @@ String DirAccessJAndroid::get_next() { if (!str) return ""; - String ret = String::utf8(env->GetStringUTFChars((jstring)str, NULL)); + String ret = jstring_to_string((jstring)str, env); env->DeleteLocalRef((jobject)str); return ret; } diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 9d9270bdac..8d9d9c697e 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1453,6 +1453,12 @@ public: err += TTR("Invalid package name:") + " " + pn_err + "\n"; } + String etc_error = test_etc2(); + if (etc_error != String()) { + valid = false; + err += etc_error; + } + r_error = err; return valid; } diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp index 4be1106967..2bed1f0892 100644 --- a/platform/android/java_class_wrapper.cpp +++ b/platform/android/java_class_wrapper.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "java_class_wrapper.h" +#include "string_android.h" #include "thread_jandroid.h" bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error, Variant &ret) { @@ -553,7 +554,7 @@ void JavaClassWrapper::_bind_methods() { bool JavaClassWrapper::_get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig) { jstring name2 = (jstring)env->CallObjectMethod(obj, Class_getName); - String str_type = env->GetStringUTFChars(name2, NULL); + String str_type = jstring_to_string(name2, env); env->DeleteLocalRef(name2); uint32_t t = 0; @@ -697,7 +698,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va } break; case ARG_TYPE_STRING: { - var = String::utf8(env->GetStringUTFChars((jstring)obj, NULL)); + var = jstring_to_string((jstring)obj, env); return true; } break; case ARG_TYPE_CLASS: { @@ -1030,7 +1031,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va if (!o) ret.push_back(Variant()); else { - String val = String::utf8(env->GetStringUTFChars((jstring)o, NULL)); + String val = jstring_to_string((jstring)o, env); ret.push_back(val); } env->DeleteLocalRef(o); @@ -1075,7 +1076,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) { ERR_CONTINUE(!obj); jstring name = (jstring)env->CallObjectMethod(obj, getName); - String str_method = env->GetStringUTFChars(name, NULL); + String str_method = jstring_to_string(name, env); env->DeleteLocalRef(name); Vector<String> params; @@ -1204,7 +1205,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) { ERR_CONTINUE(!obj); jstring name = (jstring)env->CallObjectMethod(obj, Field_getName); - String str_field = env->GetStringUTFChars(name, NULL); + String str_field = jstring_to_string(name, env); env->DeleteLocalRef(name); int mods = env->CallIntMethod(obj, Field_getModifiers); if ((mods & 0x8) && (mods & 0x10) && (mods & 0x1)) { //static final public! diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 885fb185a7..53c909da88 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -41,6 +41,7 @@ #include "main/input_default.h" #include "main/main.h" #include "os_android.h" +#include "string_android.h" #include "thread_jandroid.h" #include <unistd.h> @@ -223,7 +224,7 @@ String _get_class_name(JNIEnv *env, jclass cls, bool *array) { jboolean isarr = env->CallBooleanMethod(cls, isArray); (*array) = isarr ? true : false; } - String name = env->GetStringUTFChars(clsName, NULL); + String name = jstring_to_string(clsName, env); env->DeleteLocalRef(clsName); return name; @@ -241,7 +242,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) { if (name == "java.lang.String") { - return String::utf8(env->GetStringUTFChars((jstring)obj, NULL)); + return jstring_to_string((jstring)obj, env); }; if (name == "[Ljava.lang.String;") { @@ -252,7 +253,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) { for (int i = 0; i < stringCount; i++) { jstring string = (jstring)env->GetObjectArrayElement(arr, i); - sarr.push_back(String::utf8(env->GetStringUTFChars(string, NULL))); + sarr.push_back(jstring_to_string(string, env)); env->DeleteLocalRef(string); } @@ -487,7 +488,7 @@ public: case Variant::STRING: { jobject o = env->CallObjectMethodA(instance, E->get().method, v); - ret = String::utf8(env->GetStringUTFChars((jstring)o, NULL)); + ret = jstring_to_string((jstring)o, env); env->DeleteLocalRef(o); } break; case Variant::POOL_STRING_ARRAY: { @@ -634,20 +635,20 @@ static String _get_user_data_dir() { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(godot_io, _getDataDir); - return String(env->GetStringUTFChars(s, NULL)); + return jstring_to_string(s, env); } static String _get_locale() { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(godot_io, _getLocale); - return String(env->GetStringUTFChars(s, NULL)); + return jstring_to_string(s, env); } static String _get_clipboard() { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(_godot_instance, _getClipboard); - return String(env->GetStringUTFChars(s, NULL)); + return jstring_to_string(s, env); } static void _set_clipboard(const String &p_text) { @@ -661,7 +662,7 @@ static String _get_model() { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(godot_io, _getModel); - return String(env->GetStringUTFChars(s, NULL)); + return jstring_to_string(s, env); } static int _get_screen_dpi() { @@ -674,7 +675,7 @@ static String _get_unique_id() { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(godot_io, _getUniqueID); - return String(env->GetStringUTFChars(s, NULL)); + return jstring_to_string(s, env); } static void _show_vk(const String &p_existing) { @@ -694,7 +695,7 @@ static String _get_system_dir(int p_dir) { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(godot_io, _getSystemDir, p_dir); - return String(env->GetStringUTFChars(s, NULL)); + return jstring_to_string(s, env); } static int _get_gles_version_code() { @@ -891,12 +892,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo ThreadAndroid::setup_thread(); const char **cmdline = NULL; + jstring *j_cmdline = NULL; int cmdlen = 0; if (p_cmdline) { cmdlen = env->GetArrayLength(p_cmdline); if (cmdlen) { - cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *)); + cmdline = (const char **)malloc((cmdlen + 1) * sizeof(const char *)); cmdline[cmdlen] = NULL; + j_cmdline = (jstring *)malloc(cmdlen * sizeof(jstring)); for (int i = 0; i < cmdlen; i++) { @@ -904,12 +907,19 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo const char *rawString = env->GetStringUTFChars(string, 0); cmdline[i] = rawString; + j_cmdline[i] = string; } } } Error err = Main::setup("apk", cmdlen, (char **)cmdline, false); if (cmdline) { + if (j_cmdline) { + for (int i = 0; i < cmdlen; ++i) { + env->ReleaseStringUTFChars(j_cmdline[i], cmdline[i]); + } + free(j_cmdline); + } free(cmdline); } @@ -1313,7 +1323,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) { if (os_android) { - String name = env->GetStringUTFChars(p_name, NULL); + String name = jstring_to_string(p_name, env); os_android->joy_connection_changed(p_device, p_connected, name); } } @@ -1386,7 +1396,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jo JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env, jobject obj, jstring name, jobject p_object) { - String singname = env->GetStringUTFChars(name, NULL); + String singname = jstring_to_string(name, env); JNISingleton *s = memnew(JNISingleton); s->set_instance(env->NewGlobalRef(p_object)); jni_singletons[singname] = s; @@ -1463,21 +1473,21 @@ static const char *get_jni_sig(const String &p_type) { JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path) { - String js = env->GetStringUTFChars(path, NULL); + String js = jstring_to_string(path, env); return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data()); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) { - String singname = env->GetStringUTFChars(sname, NULL); + String singname = jstring_to_string(sname, env); ERR_FAIL_COND(!jni_singletons.has(singname)); JNISingleton *s = jni_singletons.get(singname); - String mname = env->GetStringUTFChars(name, NULL); - String retval = env->GetStringUTFChars(ret, NULL); + String mname = jstring_to_string(name, env); + String retval = jstring_to_string(ret, env); Vector<Variant::Type> types; String cs = "("; @@ -1486,9 +1496,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j for (int i = 0; i < stringCount; i++) { jstring string = (jstring)env->GetObjectArrayElement(args, i); - const char *rawString = env->GetStringUTFChars(string, 0); - types.push_back(get_jni_type(String(rawString))); - cs += get_jni_sig(String(rawString)); + const String rawString = jstring_to_string(string, env); + types.push_back(get_jni_type(rawString)); + cs += get_jni_sig(rawString); } cs += ")"; @@ -1511,7 +1521,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en int res = env->PushLocalFrame(16); ERR_FAIL_COND(res != 0); - String str_method = env->GetStringUTFChars(method, NULL); + String str_method = jstring_to_string(method, env); int count = env->GetArrayLength(params); Variant *vlist = (Variant *)alloca(sizeof(Variant) * count); @@ -1543,7 +1553,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * int res = env->PushLocalFrame(16); ERR_FAIL_COND(res != 0); - String str_method = env->GetStringUTFChars(method, NULL); + String str_method = jstring_to_string(method, env); int count = env->GetArrayLength(params); Variant args[VARIANT_ARG_MAX]; diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 3ba8468e0b..b86976843c 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -706,7 +706,7 @@ String OS_Android::get_joy_guid(int p_device) const { } bool OS_Android::_check_internal_feature_support(const String &p_feature) { - if (p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2") { + if (p_feature == "mobile") { //TODO support etc2 only if GLES3 driver is selected return true; } diff --git a/platform/android/string_android.h b/platform/android/string_android.h new file mode 100644 index 0000000000..fe627a3e0c --- /dev/null +++ b/platform/android/string_android.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* string_android.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef STRING_ANDROID_H +#define STRING_ANDROID_H +#include "core/ustring.h" +#include "thread_jandroid.h" +#include <jni.h> + +/** + * Converts JNI jstring to Godot String. + * @param source Source JNI string. If null an empty string is returned. + * @param env JNI environment instance. If null obtained by ThreadAndroid::get_env(). + * @return Godot string instance. + */ +static inline String jstring_to_string(jstring source, JNIEnv *env = NULL) { + String result; + if (source) { + if (!env) { + env = ThreadAndroid::get_env(); + } + const char *const source_utf8 = env->GetStringUTFChars(source, NULL); + if (source_utf8) { + result.parse_utf8(source_utf8); + env->ReleaseStringUTFChars(source, source_utf8); + } + } + return result; +} + +#endif // STRING_ANDROID_H diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index a5b2e66a22..a6d5a00852 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -322,7 +322,7 @@ String OS_Haiku::get_executable_path() const { bool OS_Haiku::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc" || p_feature == "s3tc"; + return p_feature == "pc"; } String OS_Haiku::get_config_path() const { diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index bb0c11c767..d160553050 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -598,8 +598,10 @@ static int frame_count = 0; }; - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { - OS::get_singleton()->get_main_loop()->notification( - MainLoop::NOTIFICATION_OS_MEMORY_WARNING); + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification( + MainLoop::NOTIFICATION_OS_MEMORY_WARNING); + } }; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index d234ddac27..09ded63e96 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -1150,6 +1150,12 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset } } + String etc_error = test_etc2(); + if (etc_error != String()) { + valid = false; + err += etc_error; + } + if (!err.empty()) r_error = err; diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index c939e234b9..b44b3127c7 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -587,7 +587,7 @@ void OSIPhone::native_video_stop() { bool OSIPhone::_check_internal_feature_support(const String &p_feature) { - return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2"; + return p_feature == "mobile"; } // Initialization order between compilation units is not guaranteed, diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 123c6ae645..2da6ea6670 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -167,6 +167,12 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p } } + String etc_error = test_etc2(); + if (etc_error != String()) { + valid = false; + err += etc_error; + } + if (!err.empty()) r_error = err; diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 594c0a46cc..57ae1b6e26 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -1071,16 +1071,6 @@ bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { return true; #endif - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); - // All extensions are already automatically enabled, this function allows - // checking WebGL extension support without inline JavaScript - if (p_feature == "s3tc") - return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc_srgb"); - if (p_feature == "etc") - return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc1"); - if (p_feature == "etc2") - return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc"); - return false; } diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 4e4d9c9eea..5206dc13b6 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -2812,7 +2812,7 @@ OS_OSX::OS_OSX() { } bool OS_OSX::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc" || p_feature == "s3tc"; + return p_feature == "pc"; } void OS_OSX::disable_crash_handler() { diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 520e179611..637ef5aaef 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -889,7 +889,7 @@ String OS_UWP::get_user_data_dir() const { } bool OS_UWP::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc" || p_feature == "s3tc"; + return p_feature == "pc"; } OS::PowerState OS_UWP::get_power_state() { diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 9f15e7aad7..61aeb3ec93 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1395,6 +1395,8 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); } + update_real_mouse_position(); + return OK; } @@ -1596,6 +1598,19 @@ Point2 OS_Windows::get_mouse_position() const { return Point2(old_x, old_y); } +void OS_Windows::update_real_mouse_position() { + + POINT mouse_pos; + if (GetCursorPos(&mouse_pos) && ScreenToClient(hWnd, &mouse_pos)) { + if (mouse_pos.x > 0 && mouse_pos.y > 0 && mouse_pos.x <= video_mode.width && mouse_pos.y <= video_mode.height) { + old_x = mouse_pos.x; + old_y = mouse_pos.y; + old_invalid = false; + input->set_mouse_position(Point2i(mouse_pos.x, mouse_pos.y)); + } + } +} + int OS_Windows::get_mouse_button_state() const { return last_button_state; @@ -1738,6 +1753,7 @@ void OS_Windows::set_window_position(const Point2 &p_position) { } last_pos = p_position; + update_real_mouse_position(); } Size2 OS_Windows::get_window_size() const { @@ -2960,7 +2976,7 @@ int OS_Windows::get_power_percent_left() { bool OS_Windows::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc" || p_feature == "s3tc" || p_feature == "bptc"; + return p_feature == "pc"; } void OS_Windows::disable_crash_handler() { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index e27dbbe530..6c257016ec 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -197,6 +197,7 @@ public: virtual void warp_mouse_position(const Point2 &p_to); virtual Point2 get_mouse_position() const; + void update_real_mouse_position(); virtual int get_mouse_button_state() const; virtual void set_window_title(const String &p_title); diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 16760f9407..1355ae542d 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -2,7 +2,7 @@ import os import platform import sys from compat import decode_utf8 -from methods import get_compiler_version +from methods import get_compiler_version, use_gcc def is_active(): return True @@ -162,10 +162,11 @@ def configure(env): env.Append(LINKFLAGS=['-pipe']) # Check for gcc version >= 6 before adding -no-pie - version = get_compiler_version(env) - if version != None and version[0] > '6': - env.Append(CCFLAGS=['-fpie']) - env.Append(LINKFLAGS=['-no-pie']) + if use_gcc(env): + version = get_compiler_version(env) + if version != None and version[0] >= '6': + env.Append(CCFLAGS=['-fpie']) + env.Append(LINKFLAGS=['-no-pie']) ## Dependencies diff --git a/platform/x11/detect_prime.cpp b/platform/x11/detect_prime.cpp index 04a825fac9..0fde2a0c04 100644 --- a/platform/x11/detect_prime.cpp +++ b/platform/x11/detect_prime.cpp @@ -180,8 +180,8 @@ int detect_prime() { const char *vendor = (const char *)glGetString(GL_VENDOR); const char *renderer = (const char *)glGetString(GL_RENDERER); - int vendor_len = strlen(vendor) + 1; - int renderer_len = strlen(renderer) + 1; + unsigned int vendor_len = strlen(vendor) + 1; + unsigned int renderer_len = strlen(renderer) + 1; if (vendor_len + renderer_len >= sizeof(string)) { renderer_len = 200 - vendor_len; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 879642d8f9..6a09c507c6 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -2593,7 +2593,7 @@ Error OS_X11::shell_open(String p_uri) { bool OS_X11::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc" || p_feature == "s3tc" || p_feature == "bptc"; + return p_feature == "pc"; } String OS_X11::get_config_path() const { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index cf48a2503c..4b3934c4ea 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -860,7 +860,9 @@ void AudioStreamPlayer3D::set_doppler_tracking(DopplerTracking p_tracking) { if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { set_notify_transform(true); velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP); - velocity_tracker->reset(get_global_transform().origin); + if (is_inside_tree()) { + velocity_tracker->reset(get_global_transform().origin); + } } else { set_notify_transform(false); } diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index ed9374e422..368cebeeab 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -449,7 +449,9 @@ void Camera::set_doppler_tracking(DopplerTracking p_tracking) { doppler_tracking = p_tracking; if (p_tracking != DOPPLER_TRACKING_DISABLED) { velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP); - velocity_tracker->reset(get_global_transform().origin); + if (is_inside_tree()) { + velocity_tracker->reset(get_global_transform().origin); + } } _update_camera_mode(); } diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 9250ca7937..750ed97ae6 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -887,7 +887,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C distance -= distance_adv; } - if (result == idx) { + if (result == (uint32_t)idx) { //cell hit itself! hooray! Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); @@ -1018,7 +1018,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color distance -= distance_adv; } - if (result == idx) { + if (result == (uint32_t)idx) { //cell hit itself! hooray! if (normal == Vector3()) { @@ -1152,7 +1152,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi distance -= distance_adv; } - if (result == idx) { + if (result == (uint32_t)idx) { //cell hit itself! hooray! if (normal == Vector3()) { @@ -2252,7 +2252,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re uint32_t child = bake_cells[p_idx].children[i]; - if (child == CHILD_EMPTY || child >= max_original_cells) + if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells) continue; AABB aabb = p_aabb; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 513befb8f3..998e91cfc2 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -206,65 +206,62 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { if (name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); + if (data.icon_override.has(dname)) { + data.icon_override[dname]->disconnect("changed", this, "_override_changed"); + } data.icon_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_shaders/")) { String dname = name.get_slicec('/', 1); + if (data.shader_override.has(dname)) { + data.shader_override[dname]->disconnect("changed", this, "_override_changed"); + } data.shader_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); + if (data.style_override.has(dname)) { + data.style_override[dname]->disconnect("changed", this, "_override_changed"); + } data.style_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_fonts/")) { String dname = name.get_slicec('/', 1); if (data.font_override.has(dname)) { - _unref_font(data.font_override[dname]); + data.font_override[dname]->disconnect("changed", this, "_override_changed"); } data.font_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_colors/")) { String dname = name.get_slicec('/', 1); data.color_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_constants/")) { String dname = name.get_slicec('/', 1); data.constant_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else return false; } else { if (name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); - notification(NOTIFICATION_THEME_CHANGED); add_icon_override(dname, p_value); } else if (name.begins_with("custom_shaders/")) { String dname = name.get_slicec('/', 1); add_shader_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); add_style_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_fonts/")) { String dname = name.get_slicec('/', 1); add_font_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_colors/")) { String dname = name.get_slicec('/', 1); add_color_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_constants/")) { String dname = name.get_slicec('/', 1); add_constant_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else return false; } @@ -1800,51 +1797,63 @@ Rect2 Control::get_anchorable_rect() const { void Control::add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon) { ERR_FAIL_COND(p_icon.is_null()); + if (data.icon_override.has(p_name)) { + data.icon_override[p_name]->disconnect("changed", this, "_override_changed"); + } data.icon_override[p_name] = p_icon; + if (data.icon_override[p_name].is_valid()) { + data.icon_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) { ERR_FAIL_COND(p_shader.is_null()); + if (data.shader_override.has(p_name)) { + data.shader_override[p_name]->disconnect("changed", this, "_override_changed"); + } data.shader_override[p_name] = p_shader; + if (data.shader_override[p_name].is_valid()) { + data.shader_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { ERR_FAIL_COND(p_style.is_null()); + if (data.style_override.has(p_name)) { + data.style_override[p_name]->disconnect("changed", this, "_override_changed"); + } data.style_override[p_name] = p_style; + if (data.style_override[p_name].is_valid()) { + data.style_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } + notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_font_override(const StringName &p_name, const Ref<Font> &p_font) { ERR_FAIL_COND(p_font.is_null()); if (data.font_override.has(p_name)) { - _unref_font(data.font_override[p_name]); + data.font_override[p_name]->disconnect("changed", this, "_override_changed"); } data.font_override[p_name] = p_font; - - if (p_font.is_valid()) { - _ref_font(p_font); + if (data.font_override[p_name].is_valid()) { + data.font_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); } notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_color_override(const StringName &p_name, const Color &p_color) { data.color_override[p_name] = p_color; notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_constant_override(const StringName &p_name, int p_constant) { data.constant_override[p_name] = p_constant; notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::set_focus_mode(FocusMode p_focus_mode) { @@ -2143,7 +2152,6 @@ void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool c->data.theme_owner = p_owner; } c->notification(NOTIFICATION_THEME_CHANGED); - c->update(); } } @@ -2550,32 +2558,10 @@ float Control::get_rotation_degrees() const { return Math::rad2deg(get_rotation()); } -//needed to update the control if the font changes.. -void Control::_ref_font(Ref<Font> p_sc) { +void Control::_override_changed() { - if (!data.font_refcount.has(p_sc)) { - data.font_refcount[p_sc] = 1; - p_sc->connect("changed", this, "_font_changed"); - } else { - data.font_refcount[p_sc] += 1; - } -} - -void Control::_unref_font(Ref<Font> p_sc) { - - ERR_FAIL_COND(!data.font_refcount.has(p_sc)); - data.font_refcount[p_sc]--; - if (data.font_refcount[p_sc] == 0) { - p_sc->disconnect("changed", this, "_font_changed"); - data.font_refcount.erase(p_sc); - } -} - -void Control::_font_changed() { - - update(); notification(NOTIFICATION_THEME_CHANGED); - minimum_size_changed(); //fonts affect minimum size pretty much almost always + minimum_size_changed(); // overrides are likely to affect minimum size } void Control::set_pivot_offset(const Vector2 &p_pivot) { @@ -2829,7 +2815,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("_theme_changed"), &Control::_theme_changed); - ClassDB::bind_method(D_METHOD("_font_changed"), &Control::_font_changed); + ClassDB::bind_method(D_METHOD("_override_changed"), &Control::_override_changed); BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size")); diff --git a/scene/gui/control.h b/scene/gui/control.h index 0812457bd2..5e33f6ba43 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -207,7 +207,6 @@ private: HashMap<StringName, Ref<Font> > font_override; HashMap<StringName, Color> color_override; HashMap<StringName, int> constant_override; - Map<Ref<Font>, int> font_refcount; } data; @@ -234,9 +233,7 @@ private: void _size_changed(); String _get_tooltip() const; - void _ref_font(Ref<Font> p_sc); - void _unref_font(Ref<Font> p_sc); - void _font_changed(); + void _override_changed(); void _update_canvas_item_transform(); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index 2195ec9778..264eda4035 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -39,9 +39,12 @@ Size2 ProgressBar::get_minimum_size() const { Size2 minimum_size = bg->get_minimum_size(); minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height); minimum_size.width = MAX(minimum_size.width, fg->get_minimum_size().width); - //if (percent_visible) { this is needed, else the progressbar will collapse - minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + font->get_height()); - //} + if (percent_visible) { + minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + font->get_height()); + } else { // this is needed, else the progressbar will collapse + minimum_size.width = MAX(minimum_size.width, 1); + minimum_size.height = MAX(minimum_size.height, 1); + } return minimum_size; } diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 8263096c8f..d2e4d28b44 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -332,7 +332,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) prevx = stepx; prevy = stepy; - ERR_FAIL_COND_V(count > width * height, _points); + ERR_FAIL_COND_V((int)count > width * height, _points); } while (curx != startx || cury != starty); return _points; } diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 9a52e9a6bb..536eb11a27 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -607,17 +607,17 @@ void SpatialMaterial::_update_shader() { code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);\n"; if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n"; + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; } } break; case BILLBOARD_FIXED_Y: { - code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)),0.0),WORLD_MATRIX[3]);\n"; + code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)), 0.0),WORLD_MATRIX[3]);\n"; if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,1,0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n"; + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, 1.0, 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } else { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1,0,0,0),vec4(0,1.0/length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1.0, 0.0, 0.0, 0.0),vec4(0.0, 1.0/length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0 ,1.0));\n"; } } break; case BILLBOARD_PARTICLES: { @@ -625,7 +625,7 @@ void SpatialMaterial::_update_shader() { //make billboard code += "\tmat4 mat_world = mat4(normalize(CAMERA_MATRIX[0])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[1])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[2])*length(WORLD_MATRIX[2]),WORLD_MATRIX[3]);\n"; //rotate by rotation - code += "\tmat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x),0.0,0.0), vec4(sin(INSTANCE_CUSTOM.x),cos(INSTANCE_CUSTOM.x),0.0,0.0),vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0));\n"; + code += "\tmat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; //set modelview code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world;\n"; @@ -721,7 +721,7 @@ void SpatialMaterial::_update_shader() { code += "\tvec2 base_uv2 = UV2;\n"; } - if (features[FEATURE_DEPTH_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //depthmap not supported with triplanar + if (!VisualServer::get_singleton()->is_low_end() && features[FEATURE_DEPTH_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //depthmap not supported with triplanar code += "\t{\n"; code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*depth_flip.x,-BINORMAL*depth_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-) diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 59fde7787e..ef67e6ea80 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -311,8 +311,8 @@ void ParticlesMaterial::_update_shader() { //initiate velocity spread in 3D code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; - code += " vec3 direction_xz = vec3(sin(angle1_rad), 0, cos(angle1_rad));\n"; - code += " vec3 direction_yz = vec3(0, sin(angle2_rad), cos(angle2_rad));\n"; + code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; + code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; code += " vec3 direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; code += " direction = normalize(direction);\n"; @@ -347,7 +347,7 @@ void ParticlesMaterial::_update_shader() { code += " VELOCITY.xy = rotm * VELOCITY.xy;\n"; } else { code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n"; - code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n"; + code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n"; code += " vec3 tangent = normalize(cross(v0, normal));\n"; code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; code += " VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 44899bf9fc..210fbe9f20 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1389,7 +1389,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, if (!p_main && (!bundle_resources) && res->get_path().length() && res->get_path().find("::") == -1) { if (res->get_path() == local_path) { - ERR_PRINTS("Circular reference to resource being saved found: '"+local_path+"' will be null next time it's loaded."); + ERR_PRINTS("Circular reference to resource being saved found: '" + local_path + "' will be null next time it's loaded."); return; } int index = external_resources.size(); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index affe9a3e24..cdd65c7642 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -903,6 +903,7 @@ int StyleBoxLine::get_thickness() const { void StyleBoxLine::set_vertical(bool p_vertical) { vertical = p_vertical; + emit_changed(); } bool StyleBoxLine::is_vertical() const { return vertical; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index e8cc160acf..08b2a05d43 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -426,6 +426,8 @@ ImageTexture::ImageTexture() { texture = VisualServer::get_singleton()->texture_create(); storage = STORAGE_RAW; lossy_storage_quality = 0.7; + image_stored = false; + format = Image::FORMAT_L8; } ImageTexture::~ImageTexture() { @@ -481,7 +483,7 @@ Image::Format StreamTexture::get_format() const { return format; } -Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit) { +Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit) { alpha_cache.unref(); @@ -497,8 +499,11 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'D' || header[2] != 'S' || header[3] != 'T', ERR_FILE_CORRUPT); } - tw = f->get_32(); - th = f->get_32(); + tw = f->get_16(); + tw_custom = f->get_16(); + th = f->get_16(); + th_custom = f->get_16(); + flags = f->get_32(); //texture flags! uint32_t df = f->get_32(); //data format @@ -705,18 +710,26 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla Error StreamTexture::load(const String &p_path) { - int lw, lh, lflags; + int lw, lh, lwc, lhc, lflags; Ref<Image> image; image.instance(); - Error err = _load_data(p_path, lw, lh, lflags, image); + Error err = _load_data(p_path, lw, lh, lwc, lhc, lflags, image); if (err) return err; + if (get_path() == String()) { + //temporarily set path if no path set for resource, helps find errors + VisualServer::get_singleton()->texture_set_path(texture, p_path); + } VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags); VS::get_singleton()->texture_set_data(texture, image); + if (lwc || lhc) { + VS::get_singleton()->texture_set_size_override(texture, lwc, lhc, 0); + } else { + } - w = lw; - h = lh; + w = lwc ? lwc : lw; + h = lhc ? lhc : lh; flags = lflags; path_to_file = p_path; format = image->get_format(); @@ -784,6 +797,7 @@ bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { decom->decompress(); img = decom; } + alpha_cache.instance(); alpha_cache->create_from_image_alpha(img); } @@ -1502,6 +1516,7 @@ CubeMap::CubeMap() { cubemap = VisualServer::get_singleton()->texture_create(); storage = STORAGE_RAW; lossy_storage_quality = 0.7; + format = Image::FORMAT_BPTC_RGBA; } CubeMap::~CubeMap() { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index dc3a3e0c74..21d3782897 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -187,7 +187,7 @@ public: }; private: - Error _load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit = 0); + Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit = 0); String path_to_file; RID texture; Image::Format format; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index d95e0e2da1..e47069d723 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -1136,7 +1136,7 @@ String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShad "round($)", "ceil($)", "fract($)", - "min(max($,0),1)", + "min(max($,0.0),1.0)", "-($)", }; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index bd98619e92..12ee98595d 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -138,7 +138,7 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer(); unsigned int input_size = AudioDriver::get_singleton()->get_input_size(); int mix_rate = AudioDriver::get_singleton()->get_mix_rate(); - int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1); + unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1); #ifdef DEBUG_ENABLED unsigned int input_position = AudioDriver::get_singleton()->get_input_position(); #endif @@ -152,11 +152,11 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr for (int i = 0; i < p_frames; i++) { if (input_size > input_ofs) { float l = (buf[input_ofs++] >> 16) / 32768.f; - if (input_ofs >= buf.size()) { + if ((int)input_ofs >= buf.size()) { input_ofs = 0; } float r = (buf[input_ofs++] >> 16) / 32768.f; - if (input_ofs >= buf.size()) { + if ((int)input_ofs >= buf.size()) { input_ofs = 0; } @@ -168,7 +168,7 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr } #ifdef DEBUG_ENABLED - if (input_ofs > input_position && (input_ofs - input_position) < (p_frames * 2)) { + if (input_ofs > input_position && (int)(input_ofs - input_position) < (p_frames * 2)) { print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size)); } #endif diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index a2e5813a4f..df6218ac79 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -91,10 +91,10 @@ void AudioDriver::input_buffer_init(int driver_buffer_frames) { void AudioDriver::input_buffer_write(int32_t sample) { input_buffer.write[input_position++] = sample; - if (input_position >= input_buffer.size()) { + if ((int)input_position >= input_buffer.size()) { input_position = 0; } - if (input_size < input_buffer.size()) { + if ((int)input_size < input_buffer.size()) { input_size++; } } diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 4e167be300..922f017d0b 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -88,8 +88,21 @@ Physics2DServer *_createGodotPhysics2DCallback() { return Physics2DServerWrapMT::init_server<Physics2DServerSW>(); } +static bool has_server_feature_callback(const String &p_feature) { + + if (VisualServer::get_singleton()) { + if (VisualServer::get_singleton()->has_os_feature(p_feature)) { + return true; + } + } + + return false; +} + void register_server_types() { + OS::get_singleton()->set_has_server_feature_callback(has_server_feature_callback); + ClassDB::register_virtual_class<VisualServer>(); ClassDB::register_class<AudioServer>(); ClassDB::register_virtual_class<PhysicsServer>(); diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 9a0218d5d0..1f9d263354 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2074,7 +2074,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p bool fail = false; for (int i = 0; i < argcount; i++) { - if (args[i] != builtin_func_defs[idx].args[i]) { + if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) { + //all good, but needs implicit conversion later + } else if (args[i] != builtin_func_defs[idx].args[i]) { fail = true; break; } @@ -2119,6 +2121,24 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p outarg_idx++; } + //implicitly convert values if possible + for (int i = 0; i < argcount; i++) { + + if (get_scalar_type(args[i]) != args[i] || args[i] == builtin_func_defs[idx].args[i] || p_func->arguments[i + 1]->type != Node::TYPE_CONSTANT) { + //can't do implicit conversion here + continue; + } + + //this is an implicit conversion + ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[i + 1]); + ConstantNode *conversion = alloc_node<ConstantNode>(); + + conversion->datatype = builtin_func_defs[idx].args[i]; + conversion->values.resize(1); + + convert_constant(constant, builtin_func_defs[idx].args[i], conversion->values.ptrw()); + p_func->arguments.write[i + 1] = conversion; + } if (r_ret_type) *r_ret_type = builtin_func_defs[idx].rettype; @@ -2184,13 +2204,35 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p for (int j = 0; j < args.size(); j++) { - if (args[j] != pfunc->arguments[j].type) { + if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) { + //all good, but it needs implicit conversion later + } else if (args[j] != pfunc->arguments[j].type) { fail = true; break; } } if (!fail) { + + //implicitly convert values if possible + for (int k = 0; k < args.size(); k++) { + + if (get_scalar_type(args[k]) != args[k] || args[k] == pfunc->arguments[k].type || p_func->arguments[k + 1]->type != Node::TYPE_CONSTANT) { + //can't do implicit conversion here + continue; + } + + //this is an implicit conversion + ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[k + 1]); + ConstantNode *conversion = alloc_node<ConstantNode>(); + + conversion->datatype = pfunc->arguments[k].type; + conversion->values.resize(1); + + convert_constant(constant, pfunc->arguments[k].type, conversion->values.ptrw()); + p_func->arguments.write[k + 1] = conversion; + } + if (r_ret_type) *r_ret_type = pfunc->return_type; return true; diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index d6e43b0f00..2c6709662f 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -167,7 +167,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E RasterizerCanvas::Light *light = lights_with_shadow; while (light) { - VSG::canvas_render->canvas_light_shadow_buffer_update(light->shadow_buffer, light->xform_cache.affine_inverse(), light->item_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, &light->shadow_matrix_cache); + VSG::canvas_render->canvas_light_shadow_buffer_update(light->shadow_buffer, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, &light->shadow_matrix_cache); light = light->shadows_next_ptr; } diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index c61e2b99e2..3dbe516f74 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2368,11 +2368,11 @@ VisualServer::VisualServer() { //ERR_FAIL_COND(singleton); singleton = this; - GLOBAL_DEF("rendering/vram_compression/import_bptc", false); - GLOBAL_DEF("rendering/vram_compression/import_s3tc", true); - GLOBAL_DEF("rendering/vram_compression/import_etc", false); - GLOBAL_DEF("rendering/vram_compression/import_etc2", true); - GLOBAL_DEF("rendering/vram_compression/import_pvrtc", false); + GLOBAL_DEF_RST("rendering/vram_compression/import_bptc", false); + GLOBAL_DEF_RST("rendering/vram_compression/import_s3tc", true); + GLOBAL_DEF_RST("rendering/vram_compression/import_etc", false); + GLOBAL_DEF_RST("rendering/vram_compression/import_etc2", true); + GLOBAL_DEF_RST("rendering/vram_compression/import_pvrtc", false); GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); |