diff options
133 files changed, 1286 insertions, 865 deletions
diff --git a/SConstruct b/SConstruct index 92dc4d9da2..aa5e3a98c8 100644 --- a/SConstruct +++ b/SConstruct @@ -311,6 +311,10 @@ if selected_platform in platform_list: # must happen after the flags, so when flags are used by configure, stuff happens (ie, ssl on x11) detect.configure(env) + # Enable C++11 support + if not env.msvc: + env.Append(CXXFLAGS=['-std=c++11']) + # Configure compiler warnings if env.msvc: # Truncations, narrowing conversions, signed/unsigned comparisons... diff --git a/core/image.cpp b/core/image.cpp index a88395204a..10778eced6 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -240,27 +240,27 @@ int Image::get_format_block_size(Format p_format) { case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1: return 4; - } break; + } case FORMAT_PVRTC2: case FORMAT_PVRTC2A: { return 4; - } break; + } case FORMAT_PVRTC4A: case FORMAT_PVRTC4: { return 4; - } break; + } case FORMAT_ETC: { return 4; - } break; + } case FORMAT_BPTC_RGBA: case FORMAT_BPTC_RGBF: case FORMAT_BPTC_RGBFU: { return 4; - } break; + } case FORMAT_ETC2_R11: //etc2 case FORMAT_ETC2_R11S: //signed: NOT srgb. case FORMAT_ETC2_RG11: @@ -270,7 +270,7 @@ int Image::get_format_block_size(Format p_format) { case FORMAT_ETC2_RGB8A1: { return 4; - } break; + } default: { } } @@ -852,7 +852,7 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, float p_alpha, uint32_t p_width, uint32_t p_height, uint32_t p_pixel_size) { - uint16_t alpha = CLAMP((uint16_t)(p_alpha * 256.0f), 0, 256); + uint16_t alpha = MIN((uint16_t)(p_alpha * 256.0f), 256); for (uint32_t i = 0; i < p_width * p_height * p_pixel_size; i++) { @@ -2421,38 +2421,36 @@ Color Image::get_pixel(int p_x, int p_y) const { case FORMAT_L8: { float l = ptr[ofs] / 255.0; return Color(l, l, l, 1); - } break; + } case FORMAT_LA8: { float l = ptr[ofs * 2 + 0] / 255.0; float a = ptr[ofs * 2 + 1] / 255.0; return Color(l, l, l, a); - } break; + } case FORMAT_R8: { float r = ptr[ofs] / 255.0; return Color(r, 0, 0, 1); - } break; + } case FORMAT_RG8: { float r = ptr[ofs * 2 + 0] / 255.0; float g = ptr[ofs * 2 + 1] / 255.0; return Color(r, g, 0, 1); - } break; + } case FORMAT_RGB8: { float r = ptr[ofs * 3 + 0] / 255.0; float g = ptr[ofs * 3 + 1] / 255.0; float b = ptr[ofs * 3 + 2] / 255.0; return Color(r, g, b, 1); - - } break; + } case FORMAT_RGBA8: { float r = ptr[ofs * 4 + 0] / 255.0; float g = ptr[ofs * 4 + 1] / 255.0; float b = ptr[ofs * 4 + 2] / 255.0; float a = ptr[ofs * 4 + 3] / 255.0; return Color(r, g, b, a); - - } break; + } case FORMAT_RGBA4444: { uint16_t u = ((uint16_t *)ptr)[ofs]; float r = (u & 0xF) / 15.0; @@ -2460,8 +2458,7 @@ Color Image::get_pixel(int p_x, int p_y) const { float b = ((u >> 8) & 0xF) / 15.0; float a = ((u >> 12) & 0xF) / 15.0; return Color(r, g, b, a); - - } break; + } case FORMAT_RGBA5551: { uint16_t u = ((uint16_t *)ptr)[ofs]; @@ -2470,25 +2467,25 @@ Color Image::get_pixel(int p_x, int p_y) const { float b = ((u >> 10) & 0x1F) / 15.0; float a = ((u >> 15) & 0x1) / 1.0; return Color(r, g, b, a); - } break; + } case FORMAT_RF: { float r = ((float *)ptr)[ofs]; return Color(r, 0, 0, 1); - } break; + } case FORMAT_RGF: { float r = ((float *)ptr)[ofs * 2 + 0]; float g = ((float *)ptr)[ofs * 2 + 1]; return Color(r, g, 0, 1); - } break; + } case FORMAT_RGBF: { float r = ((float *)ptr)[ofs * 3 + 0]; float g = ((float *)ptr)[ofs * 3 + 1]; float b = ((float *)ptr)[ofs * 3 + 2]; return Color(r, g, b, 1); - } break; + } case FORMAT_RGBAF: { float r = ((float *)ptr)[ofs * 4 + 0]; @@ -2496,25 +2493,25 @@ Color Image::get_pixel(int p_x, int p_y) const { float b = ((float *)ptr)[ofs * 4 + 2]; float a = ((float *)ptr)[ofs * 4 + 3]; return Color(r, g, b, a); - } break; + } case FORMAT_RH: { uint16_t r = ((uint16_t *)ptr)[ofs]; return Color(Math::half_to_float(r), 0, 0, 1); - } break; + } case FORMAT_RGH: { uint16_t r = ((uint16_t *)ptr)[ofs * 2 + 0]; uint16_t g = ((uint16_t *)ptr)[ofs * 2 + 1]; return Color(Math::half_to_float(r), Math::half_to_float(g), 0, 1); - } break; + } case FORMAT_RGBH: { uint16_t r = ((uint16_t *)ptr)[ofs * 3 + 0]; uint16_t g = ((uint16_t *)ptr)[ofs * 3 + 1]; uint16_t b = ((uint16_t *)ptr)[ofs * 3 + 2]; return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), 1); - } break; + } case FORMAT_RGBAH: { uint16_t r = ((uint16_t *)ptr)[ofs * 4 + 0]; @@ -2522,18 +2519,15 @@ Color Image::get_pixel(int p_x, int p_y) const { uint16_t b = ((uint16_t *)ptr)[ofs * 4 + 2]; uint16_t a = ((uint16_t *)ptr)[ofs * 4 + 3]; return Color(Math::half_to_float(r), Math::half_to_float(g), Math::half_to_float(b), Math::half_to_float(a)); - } break; + } case FORMAT_RGBE9995: { return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]); - - } break; + } default: { ERR_EXPLAIN("Can't get_pixel() on compressed image, sorry."); ERR_FAIL_V(Color()); } } - - return Color(); } void Image::set_pixelv(const Point2 &p_dst, const Color &p_color) { diff --git a/core/input_map.cpp b/core/input_map.cpp index 04911787a8..165999f081 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -202,7 +202,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str if (p_pressed != NULL) *p_pressed = input_event_action->is_pressed(); if (p_strength != NULL) - *p_strength = (*p_pressed) ? input_event_action->get_strength() : 0.0f; + *p_strength = (p_pressed != NULL && *p_pressed) ? input_event_action->get_strength() : 0.0f; return input_event_action->get_action() == p_action; } diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 861e34e415..38bef2768e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -712,8 +712,8 @@ Error ResourceInteractiveLoaderBinary::poll() { if (!obj) { error = ERR_FILE_CORRUPT; ERR_EXPLAIN(local_path + ":Resource of unrecognized type in file: " + t); + ERR_FAIL_V(ERR_FILE_CORRUPT); } - ERR_FAIL_COND_V(!obj, ERR_FILE_CORRUPT); Resource *r = Object::cast_to<Resource>(obj); if (!r) { diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 0cecca904d..e2c1c3402a 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -137,7 +137,6 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t save_callback(p_resource, p_path); return OK; - } else { } } diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index acf72dbba5..84b8554d54 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -369,7 +369,9 @@ Variant StreamPeer::get_var(bool p_allow_objects) { ERR_FAIL_COND_V(err != OK, Variant()); Variant ret; - decode_variant(ret, var.ptr(), len, NULL, p_allow_objects); + err = decode_variant(ret, var.ptr(), len, NULL, p_allow_objects); + ERR_FAIL_COND_V(err != OK, Variant()); + return ret; } diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index a12f9fee2e..cfa698282e 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -192,7 +192,7 @@ int BSP_Tree::get_points_inside(const Vector3 *p_points, int p_point_count) cons #ifdef DEBUG_ENABLED int plane_count = planes.size(); uint16_t plane = nodesptr[idx].plane; - ERR_FAIL_INDEX_V(plane, plane_count, false); + ERR_FAIL_UNSIGNED_INDEX_V(plane, plane_count, false); #endif idx = planesptr[nodesptr[idx].plane].is_point_over(point) ? nodes[idx].over : nodes[idx].under; @@ -258,7 +258,7 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const { #ifdef DEBUG_ENABLED int plane_count = planes.size(); uint16_t plane = nodesptr[idx].plane; - ERR_FAIL_INDEX_V(plane, plane_count, false); + ERR_FAIL_UNSIGNED_INDEX_V(plane, plane_count, false); #endif bool over = planesptr[nodesptr[idx].plane].is_point_over(p_point); diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 2786229cf3..15eea1d308 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -68,6 +68,7 @@ const char *Expression::func_name[Expression::FUNC_MAX] = { "step_decimals", "stepify", "lerp", + "lerp_angle", "inverse_lerp", "range_lerp", "smoothstep", @@ -190,6 +191,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) { case COLORN: return 2; case MATH_LERP: + case MATH_LERP_ANGLE: case MATH_INVERSE_LERP: case MATH_SMOOTHSTEP: case MATH_MOVE_TOWARD: @@ -395,6 +397,13 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant VALIDATE_ARG_NUM(2); *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; + case MATH_LERP_ANGLE: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::lerp_angle((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; case MATH_INVERSE_LERP: { VALIDATE_ARG_NUM(0); @@ -801,17 +810,13 @@ Error Expression::_get_token(Token &r_token) { #define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++]) CharType cchar = GET_CHAR(); - if (cchar == 0) { - r_token.type = TK_EOF; - return OK; - } switch (cchar) { case 0: { r_token.type = TK_EOF; return OK; - } break; + }; case '{': { r_token.type = TK_CURLY_BRACKET_OPEN; diff --git a/core/math/expression.h b/core/math/expression.h index 03a2bb70e6..833220592c 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -67,6 +67,7 @@ public: MATH_STEP_DECIMALS, MATH_STEPIFY, MATH_LERP, + MATH_LERP_ANGLE, MATH_INVERSE_LERP, MATH_RANGE_LERP, MATH_SMOOTHSTEP, diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index b6398712e4..b8b5151802 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -215,6 +215,17 @@ public: static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; } static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; } + static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) { + double difference = fmod(p_to - p_from, Math_TAU); + double distance = fmod(2.0 * difference, Math_TAU) - difference; + return p_from + distance * p_weight; + } + static _ALWAYS_INLINE_ float lerp_angle(float p_from, float p_to, float p_weight) { + float difference = fmod(p_to - p_from, (float)Math_TAU); + float distance = fmod(2.0f * difference, (float)Math_TAU) - difference; + return p_from + distance * p_weight; + } + static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); } static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); } diff --git a/core/object.cpp b/core/object.cpp index 67ab27c190..3367d6b6c3 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -635,12 +635,9 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons #endif p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT)); } - -#ifdef TOOLS_ENABLED - p_list->push_back(PropertyInfo(Variant::NIL, "Metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); -#endif - p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - + if (!metadata.empty()) { + p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + } if (script_instance && !p_reversed) { p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); script_instance->get_property_list(p_list); diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index 094352b5cc..9b342ef913 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -611,7 +611,7 @@ PoolAllocator::PoolAllocator(void *p_mem, int p_size, int p_align, bool p_needs_ PoolAllocator::PoolAllocator(int p_align, int p_size, bool p_needs_locking, int p_max_entries) { ERR_FAIL_COND(p_align < 1); - mem_ptr = Memory::alloc_static(p_size + p_align, "PoolAllocator()"); + mem_ptr = Memory::alloc_static(p_size + p_align, true); uint8_t *mem8 = (uint8_t *)mem_ptr; uint64_t ofs = (uint64_t)mem8; if (ofs % p_align) diff --git a/core/pool_vector.h b/core/pool_vector.h index 98a52c6938..3d28d86803 100644 --- a/core/pool_vector.h +++ b/core/pool_vector.h @@ -458,7 +458,7 @@ public: bool is_locked() const { return alloc && alloc->lock > 0; } - inline const T operator[](int p_index) const; + inline T operator[](int p_index) const; Error resize(int p_size); @@ -502,7 +502,7 @@ void PoolVector<T>::push_back(const T &p_val) { } template <class T> -const T PoolVector<T>::operator[](int p_index) const { +T PoolVector<T>::operator[](int p_index) const { CRASH_BAD_INDEX(p_index, size()); diff --git a/core/string_name.cpp b/core/string_name.cpp index 10b71ad3ac..b1a8bfb849 100644 --- a/core/string_name.cpp +++ b/core/string_name.cpp @@ -205,7 +205,6 @@ StringName::StringName(const char *p_name) { // exists lock->unlock(); return; - } else { } } @@ -253,7 +252,6 @@ StringName::StringName(const StaticCString &p_static_string) { // exists lock->unlock(); return; - } else { } } @@ -301,7 +299,6 @@ StringName::StringName(const String &p_name) { // exists lock->unlock(); return; - } else { } } diff --git a/core/type_info.h b/core/type_info.h index d85a63ee42..61ec7b2f20 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -83,15 +83,13 @@ enum Metadata { }; } +// If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template +// instead of one of the specializations, it's most likely because the type 'T' is not supported. +// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration +// instead of a forward declaration. You can always forward declare 'T' in a header file, and then +// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated. template <class T, typename = void> -struct GetTypeInfo { - static const Variant::Type VARIANT_TYPE = Variant::NIL; - static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; - static inline PropertyInfo get_class_info() { - ERR_PRINT("GetTypeInfo fallback. Bug!"); - return PropertyInfo(); // Not "Nil", this is an error - } -}; +struct GetTypeInfo; #define MAKE_TYPE_INFO(m_type, m_var_type) \ template <> \ @@ -283,10 +281,7 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) { return GetTypeInfo<T>::get_class_info().class_name; } -#define CLASS_INFO(m_type) \ - (GetTypeInfo<m_type *>::VARIANT_TYPE != Variant::NIL ? \ - GetTypeInfo<m_type *>::get_class_info() : \ - GetTypeInfo<m_type>::get_class_info()) +#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info()) #else diff --git a/core/variant.cpp b/core/variant.cpp index fe9623d068..1574af5239 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1834,8 +1834,6 @@ inline DA _convert_array_from_variant(const Variant &p_variant) { return DA(); } } - - return DA(); } Variant::operator Array() const { @@ -2299,7 +2297,7 @@ Variant::Variant(const Object *p_object) { Variant::Variant(const Dictionary &p_dictionary) { type = DICTIONARY; - memnew_placement(_data._mem, (Dictionary)(p_dictionary)); + memnew_placement(_data._mem, Dictionary(p_dictionary)); } Variant::Variant(const Array &p_array) { diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 3fdd18a630..b637e745af 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -70,7 +70,7 @@ struct _VariantCall { for (int i = 0; i < arg_count; i++) { - if (!tptr[i] || tptr[i] == p_args[i]->type) + if (tptr[i] == Variant::NIL || tptr[i] == p_args[i]->type) continue; // all good if (!Variant::can_convert(p_args[i]->type, tptr[i])) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index d677c7776a..ea9e29e744 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -2613,7 +2613,7 @@ bool Variant::in(const Variant &p_index, bool *r_valid) const { if (r_valid) { *r_valid = false; } - return "Attempted get on stray pointer."; + return true; // Attempted get on stray pointer. } } #endif diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index d5513bc2d7..07212ec669 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -1537,8 +1537,6 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r Token token; get_token(p_stream, token, line, r_err_str); Error err = parse_value(token, r_value, p_stream, line, r_err_str, p_res_parser); - if (err) { - } return err; } } else if (c == '\n') { diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml index 99e2db6d83..6d7adc9935 100644 --- a/doc/classes/AStar.xml +++ b/doc/classes/AStar.xml @@ -44,8 +44,8 @@ <description> Adds a new point at the given position with the given identifier. The algorithm prefers points with lower [code]weight_scale[/code] to form a path. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/code] must be 1 or larger. [codeblock] - var as = AStar.new() - as.add_point(1, Vector3(1, 0, 0), 4) # Adds the point (1, 0, 0) with weight_scale 4 and id 1 + var astar = AStar.new() + astar.add_point(1, Vector3(1, 0, 0), 4) # Adds the point (1, 0, 0) with weight_scale 4 and id 1 [/codeblock] If there already exists a point for the given [code]id[/code], its position and weight scale are updated to the given values. </description> @@ -80,10 +80,10 @@ <description> Creates a segment between the given points. If [code]bidirectional[/code] is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] is allowed, not the reverse direction. [codeblock] - var as = AStar.new() - as.add_point(1, Vector3(1, 1, 0)) - as.add_point(2, Vector3(0, 5, 0)) - as.connect_points(1, 2, false) + var astar = AStar.new() + astar.add_point(1, Vector3(1, 1, 0)) + astar.add_point(2, Vector3(0, 5, 0)) + astar.connect_points(1, 2, false) [/codeblock] </description> </method> @@ -122,11 +122,11 @@ <description> Returns the closest position to [code]to_position[/code] that resides inside a segment between two connected points. [codeblock] - var as = AStar.new() - as.add_point(1, Vector3(0, 0, 0)) - as.add_point(2, Vector3(0, 5, 0)) - as.connect_points(1, 2) - var res = as.get_closest_position_in_segment(Vector3(3, 3, 0)) # Returns (0, 3, 0) + var astar = AStar.new() + astar.add_point(1, Vector3(0, 0, 0)) + astar.add_point(2, Vector3(0, 5, 0)) + astar.connect_points(1, 2) + var res = astar.get_closest_position_in_segment(Vector3(3, 3, 0)) # Returns (0, 3, 0) [/codeblock] The result is in the segment that goes from [code]y = 0[/code] to [code]y = 5[/code]. It's the closest position in the segment to the given point. </description> @@ -141,19 +141,18 @@ <description> Returns an array with the IDs of the points that form the path found by AStar between the given points. The array is ordered from the starting point to the ending point of the path. [codeblock] - var as = AStar.new() - as.add_point(1, Vector3(0, 0, 0)) - as.add_point(2, Vector3(0, 1, 0), 1) # Default weight is 1 - as.add_point(3, Vector3(1, 1, 0)) - as.add_point(4, Vector3(2, 0, 0)) + var astar = AStar.new() + astar.add_point(1, Vector3(0, 0, 0)) + astar.add_point(2, Vector3(0, 1, 0), 1) # Default weight is 1 + astar.add_point(3, Vector3(1, 1, 0)) + astar.add_point(4, Vector3(2, 0, 0)) - as.connect_points(1, 2, false) - as.connect_points(2, 3, false) - as.connect_points(4, 3, false) - as.connect_points(1, 4, false) - as.connect_points(5, 4, false) + astar.connect_points(1, 2, false) + astar.connect_points(2, 3, false) + astar.connect_points(4, 3, false) + astar.connect_points(1, 4, false) - var res = as.get_id_path(1, 3) # Returns [1, 2, 3] + var res = astar.get_id_path(1, 3) # Returns [1, 2, 3] [/codeblock] If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2. </description> @@ -166,16 +165,16 @@ <description> Returns an array with the IDs of the points that form the connection with the given point. [codeblock] - var as = AStar.new() - as.add_point(1, Vector3(0, 0, 0)) - as.add_point(2, Vector3(0, 1, 0)) - as.add_point(3, Vector3(1, 1, 0)) - as.add_point(4, Vector3(2, 0, 0)) + var astar = AStar.new() + astar.add_point(1, Vector3(0, 0, 0)) + astar.add_point(2, Vector3(0, 1, 0)) + astar.add_point(3, Vector3(1, 1, 0)) + astar.add_point(4, Vector3(2, 0, 0)) - as.connect_points(1, 2, true) - as.connect_points(1, 3, true) + astar.connect_points(1, 2, true) + astar.connect_points(1, 3, true) - var neighbors = as.get_point_connections(1) # Returns [2, 3] + var neighbors = astar.get_point_connections(1) # Returns [2, 3] [/codeblock] </description> </method> diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml index 526d1c16da..9d51330139 100644 --- a/doc/classes/AStar2D.xml +++ b/doc/classes/AStar2D.xml @@ -21,8 +21,8 @@ <description> Adds a new point at the given position with the given identifier. The algorithm prefers points with lower [code]weight_scale[/code] to form a path. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/code] must be 1 or larger. [codeblock] - var as = AStar2D.new() - as.add_point(1, Vector2(1, 0), 4) # Adds the point (1, 0) with weight_scale 4 and id 1 + var astar = AStar2D.new() + astar.add_point(1, Vector2(1, 0), 4) # Adds the point (1, 0) with weight_scale 4 and id 1 [/codeblock] If there already exists a point for the given [code]id[/code], its position and weight scale are updated to the given values. </description> @@ -57,10 +57,10 @@ <description> Creates a segment between the given points. If [code]bidirectional[/code] is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] is allowed, not the reverse direction. [codeblock] - var as = AStar2D.new() - as.add_point(1, Vector2(1, 1)) - as.add_point(2, Vector2(0, 5)) - as.connect_points(1, 2, false) + var astar = AStar2D.new() + astar.add_point(1, Vector2(1, 1)) + astar.add_point(2, Vector2(0, 5)) + astar.connect_points(1, 2, false) [/codeblock] </description> </method> @@ -99,11 +99,11 @@ <description> Returns the closest position to [code]to_position[/code] that resides inside a segment between two connected points. [codeblock] - var as = AStar2D.new() - as.add_point(1, Vector2(0, 0)) - as.add_point(2, Vector2(0, 5)) - as.connect_points(1, 2) - var res = as.get_closest_position_in_segment(Vector2(3, 3)) # Returns (0, 3) + var astar = AStar2D.new() + astar.add_point(1, Vector2(0, 0)) + astar.add_point(2, Vector2(0, 5)) + astar.connect_points(1, 2) + var res = astar.get_closest_position_in_segment(Vector2(3, 3)) # Returns (0, 3) [/codeblock] The result is in the segment that goes from [code]y = 0[/code] to [code]y = 5[/code]. It's the closest position in the segment to the given point. </description> @@ -118,19 +118,18 @@ <description> Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path. [codeblock] - var as = AStar2D.new() - as.add_point(1, Vector2(0, 0)) - as.add_point(2, Vector2(0, 1), 1) # Default weight is 1 - as.add_point(3, Vector2(1, 1)) - as.add_point(4, Vector2(2, 0)) + var astar = AStar2D.new() + astar.add_point(1, Vector2(0, 0)) + astar.add_point(2, Vector2(0, 1), 1) # Default weight is 1 + astar.add_point(3, Vector2(1, 1)) + astar.add_point(4, Vector2(2, 0)) - as.connect_points(1, 2, false) - as.connect_points(2, 3, false) - as.connect_points(4, 3, false) - as.connect_points(1, 4, false) - as.connect_points(5, 4, false) + astar.connect_points(1, 2, false) + astar.connect_points(2, 3, false) + astar.connect_points(4, 3, false) + astar.connect_points(1, 4, false) - var res = as.get_id_path(1, 3) # Returns [1, 2, 3] + var res = astar.get_id_path(1, 3) # Returns [1, 2, 3] [/codeblock] If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2. </description> @@ -143,16 +142,16 @@ <description> Returns an array with the IDs of the points that form the connection with the given point. [codeblock] - var as = AStar2D.new() - as.add_point(1, Vector2(0, 0)) - as.add_point(2, Vector2(0, 1)) - as.add_point(3, Vector2(1, 1)) - as.add_point(4, Vector2(2, 0)) + var astar = AStar2D.new() + astar.add_point(1, Vector2(0, 0)) + astar.add_point(2, Vector2(0, 1)) + astar.add_point(3, Vector2(1, 1)) + astar.add_point(4, Vector2(2, 0)) - as.connect_points(1, 2, true) - as.connect_points(1, 3, true) + astar.connect_points(1, 2, true) + astar.connect_points(1, 3, true) - var neighbors = as.get_point_connections(1) # Returns [2, 3] + var neighbors = astar.get_point_connections(1) # Returns [2, 3] [/codeblock] </description> </method> diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index eb69a4aed4..b9ec9480cf 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -19,7 +19,7 @@ <argument index="2" name="shape_idx" type="int"> </argument> <description> - Accepts unhandled [InputEvent]s. [code]shape_idx[/code] is the child index of the clicked [Shape2D]. Connect to the [code]input_event[/code] signal to easily pick up these events. + Accepts unhandled [InputEvent]s. Requires [member input_pickable] to be [code]true[/code]. [code]shape_idx[/code] is the child index of the clicked [Shape2D]. Connect to the [code]input_event[/code] signal to easily pick up these events. </description> </method> <method name="create_shape_owner"> @@ -227,17 +227,17 @@ <argument index="2" name="shape_idx" type="int"> </argument> <description> - Emitted when an input event occurs. Requires [code]input_pickable[/code] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. See [method _input_event] for details. + Emitted when an input event occurs. Requires [member input_pickable] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. See [method _input_event] for details. </description> </signal> <signal name="mouse_entered"> <description> - Emitted when the mouse pointer enters any of this object's shapes. Requires [code]input_pickable[/code] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. + Emitted when the mouse pointer enters any of this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. </description> </signal> <signal name="mouse_exited"> <description> - Emitted when the mouse pointer exits all this object's shapes. Requires [code]input_pickable[/code] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. + Emitted when the mouse pointer exits all this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. </description> </signal> </signals> diff --git a/doc/classes/DirectionalLight.xml b/doc/classes/DirectionalLight.xml index 4d0ff7f13b..687e7519b2 100644 --- a/doc/classes/DirectionalLight.xml +++ b/doc/classes/DirectionalLight.xml @@ -21,7 +21,7 @@ <member name="directional_shadow_depth_range" type="int" setter="set_shadow_depth_range" getter="get_shadow_depth_range" enum="DirectionalLight.ShadowDepthRange" default="0"> Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange]. </member> - <member name="directional_shadow_max_distance" type="float" setter="set_param" getter="get_param" default="200.0"> + <member name="directional_shadow_max_distance" type="float" setter="set_param" getter="get_param" default="100.0"> The maximum distance for shadow splits. </member> <member name="directional_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="DirectionalLight.ShadowMode" default="2"> diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 6f07682b04..d55e810c9e 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -166,6 +166,7 @@ <argument index="0" name="file" type="String"> </argument> <description> + Selects the file, with the path provided by [code]file[/code], in the FileSystem dock. </description> </method> <method name="set_plugin_enabled"> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index bd9a100267..fddc5e9d36 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -29,7 +29,7 @@ <argument index="1" name="title" type="String"> </argument> <description> - Adds a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [code]queue_free()[/code]. + Adds a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [method Node.queue_free]. </description> </method> <method name="add_control_to_container"> @@ -40,9 +40,9 @@ <argument index="1" name="control" type="Control"> </argument> <description> - Adds a custom control to a container (see [code]CONTAINER_*[/code] enum). There are many locations where custom controls can be added in the editor UI. + Adds a custom control to a container (see [enum CustomControlContainer]). There are many locations where custom controls can be added in the editor UI. Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it). - When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_container] and free it with [code]queue_free()[/code]. + When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_container] and free it with [method Node.queue_free]. </description> </method> <method name="add_control_to_dock"> @@ -53,9 +53,9 @@ <argument index="1" name="control" type="Control"> </argument> <description> - Adds the control to a specific dock slot (see [code]DOCK_*[/code] enum for options). + Adds the control to a specific dock slot (see [enum DockSlot] for options). If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions. - When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_docks] and free it with [code]queue_free()[/code]. + When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_docks] and free it with [method Node.queue_free]. </description> </method> <method name="add_custom_type"> @@ -167,6 +167,7 @@ <return type="void"> </return> <description> + Called by the engine when the user disables the [EditorPlugin] in the Plugin tab of the project settings window. </description> </method> <method name="edit" qualifiers="virtual"> @@ -182,6 +183,7 @@ <return type="void"> </return> <description> + Called by the engine when the user enables the [EditorPlugin] in the Plugin tab of the project settings window. </description> </method> <method name="forward_canvas_draw_over_viewport" qualifiers="virtual"> @@ -190,12 +192,6 @@ <argument index="0" name="overlay" type="Control"> </argument> <description> - This method is called when there is an input event in the 2D viewport, e.g. the user clicks with the mouse in the 2D space (canvas GUI). Keep in mind that for this method to be called you have to first declare the virtual method [method handles] so the editor knows that you want to work with the workspace: - [codeblock] - func handles(object): - return true - [/codeblock] - Also note that the edited scene must have a root node. </description> </method> <method name="forward_canvas_force_draw_over_viewport" qualifiers="virtual"> @@ -212,6 +208,22 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> + Called when there is a root node in the current edited scene, [method handles] is implemented and an [InputEvent] happens in the 2D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example: + [codeblock] + # Prevents the InputEvent to reach other Editor classes + func forward_canvas_gui_input(event): + var forward = true + return forward + [/codeblock] + Must [code]return false[/code] in order to forward the [InputEvent] to other Editor classes. Example: + [codeblock] + # Consumes InputEventMouseMotion and forwards other InputEvent types + func forward_canvas_gui_input(event): + var forward = false + if event is InputEventMouseMotion: + forward = true + return forward + [/codeblock] </description> </method> <method name="forward_spatial_gui_input" qualifiers="virtual"> @@ -222,12 +234,22 @@ <argument index="1" name="event" type="InputEvent"> </argument> <description> - This method is called when there is an input event in the 3D viewport, e.g. the user clicks with the mouse in the 3D space (spatial GUI). Keep in mind that for this method to be called you have to first declare the virtual method [method handles] so the editor knows that you want to work with the workspace: + Called when there is a root node in the current edited scene, [method handles] is implemented and an [InputEvent] happens in the 3D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example: + [codeblock] + # Prevents the InputEvent to reach other Editor classes + func forward_spatial_gui_input(camera, event): + var forward = true + return forward + [/codeblock] + Must [code]return false[/code] in order to forward the [InputEvent] to other Editor classes. Example: [codeblock] - func handles(object): - return true + # Consumes InputEventMouseMotion and forwards other InputEvent types + func forward_spatial_gui_input(camera, event): + var forward = false + if event is InputEventMouseMotion: + forward = true + return forward [/codeblock] - Also note that the edited scene must have a root node. </description> </method> <method name="get_breakpoints" qualifiers="virtual"> @@ -349,7 +371,7 @@ <argument index="0" name="control" type="Control"> </argument> <description> - Removes the control from the bottom panel. You have to manually [code]queue_free()[/code] the control. + Removes the control from the bottom panel. You have to manually [method Node.queue_free] the control. </description> </method> <method name="remove_control_from_container"> @@ -360,7 +382,7 @@ <argument index="1" name="control" type="Control"> </argument> <description> - Removes the control from the specified container. You have to manually [code]queue_free()[/code] the control. + Removes the control from the specified container. You have to manually [method Node.queue_free] the control. </description> </method> <method name="remove_control_from_docks"> @@ -369,7 +391,7 @@ <argument index="0" name="control" type="Control"> </argument> <description> - Removes the control from the dock. You have to manually [code]queue_free()[/code] the control. + Removes the control from the dock. You have to manually [method Node.queue_free] the control. </description> </method> <method name="remove_custom_type"> diff --git a/doc/classes/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml index 4707543c91..96d8ce698d 100644 --- a/doc/classes/EditorSceneImporter.xml +++ b/doc/classes/EditorSceneImporter.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="EditorSceneImporter" inherits="Reference" category="Core" version="3.2"> <brief_description> + Imports scenes from third-parties' 3D files. </brief_description> <description> </description> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 7ab29e67ae..2d6ab4f72c 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -825,7 +825,7 @@ <member name="rendering/quality/subsurface_scattering/weight_samples" type="bool" setter="" getter="" default="true"> Weight subsurface scattering samples. Helps to avoid reading samples from unrelated parts of the screen. </member> - <member name="rendering/quality/voxel_cone_tracing/high_quality" type="bool" setter="" getter="" default="true"> + <member name="rendering/quality/voxel_cone_tracing/high_quality" type="bool" setter="" getter="" default="false"> Use high-quality voxel cone tracing. This results in better-looking reflections, but is much more expensive on the GPU. </member> <member name="rendering/threads/thread_model" type="int" setter="" getter="" default="1"> diff --git a/doc/classes/SpatialMaterial.xml b/doc/classes/SpatialMaterial.xml index f684f09263..df315d7430 100644 --- a/doc/classes/SpatialMaterial.xml +++ b/doc/classes/SpatialMaterial.xml @@ -192,7 +192,7 @@ </member> <member name="metallic_texture" type="Texture" setter="set_texture" getter="get_texture"> </member> - <member name="metallic_texture_channel" type="int" setter="set_metallic_texture_channel" getter="get_metallic_texture_channel" enum="SpatialMaterial.TextureChannel" default="2"> + <member name="metallic_texture_channel" type="int" setter="set_metallic_texture_channel" getter="get_metallic_texture_channel" enum="SpatialMaterial.TextureChannel" default="0"> </member> <member name="normal_enabled" type="bool" setter="set_feature" getter="get_feature" default="false"> If [code]true[/code], normal mapping is enabled. @@ -277,7 +277,7 @@ </member> <member name="roughness_texture" type="Texture" setter="set_texture" getter="get_texture"> </member> - <member name="roughness_texture_channel" type="int" setter="set_roughness_texture_channel" getter="get_roughness_texture_channel" enum="SpatialMaterial.TextureChannel" default="1"> + <member name="roughness_texture_channel" type="int" setter="set_roughness_texture_channel" getter="get_roughness_texture_channel" enum="SpatialMaterial.TextureChannel" default="0"> </member> <member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false"> If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges. diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml index eb07c70cc6..522e131b45 100644 --- a/doc/classes/Variant.xml +++ b/doc/classes/Variant.xml @@ -5,6 +5,19 @@ </brief_description> <description> A Variant takes up only 20 bytes and can store almost any engine datatype inside of it. Variants are rarely used to hold information for long periods of time. Instead, they are used mainly for communication, editing, serialization and moving data around. + A Variant: + - Can store almost any datatype. + - Can perform operations between many variants. GDScript uses Variant as its atomic/native datatype. + - Can be hashed, so it can be compared quickly to other variants. + - Can be used to convert safely between datatypes. + - Can be used to abstract calling methods and their arguments. Godot exports all its functions through variants. + - Can be used to defer calls or move data between threads. + - Can be serialized as binary and stored to disk, or transferred via network. + - Can be serialized to text and use it for printing values and editable settings. + - Can work as an exported property, so the editor can edit it universally. + - Can be used for dictionaries, arrays, parsers, etc. + [b]Containers ([Array] and [Dictionary]):[/b] Both are implemented using variants. A [Dictionary] can match any datatype used as key to any other datatype. An [Array] just holds an array of Variants. Of course, a Variant can also hold a [Dictionary] and an [Array] inside, making it even more flexible. + Modifications to a container will modify all references to it. A [Mutex] should be created to lock it if multi-threaded access is desired. </description> <tutorials> </tutorials> diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index c8ceca8d97..23b01b4e09 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -880,7 +880,11 @@ RID RasterizerSceneGLES2::light_instance_create(RID p_light) { light_instance->light_index = 0xFFFF; - ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); + if (!light_instance->light_ptr) { + memdelete(light_instance); + ERR_EXPLAIN("Condition ' !light_instance->light_ptr ' is true."); + ERR_FAIL_V(RID()); + } light_instance->self = light_instance_owner.make_rid(light_instance); @@ -1963,9 +1967,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado width /= 2; height /= 2; - if (k == 0) { - - } else if (k == 1) { + if (k == 1) { x += width; } else if (k == 2) { y += height; @@ -1978,9 +1980,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado height /= 2; - if (k == 0) { - - } else { + if (k != 0) { y += height; } } @@ -2287,19 +2287,6 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, prev_unshaded = unshaded; } - bool depth_prepass = false; - - if (!p_alpha_pass && material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - depth_prepass = true; - } - - if (depth_prepass != prev_depth_prepass) { - - state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, depth_prepass); - prev_depth_prepass = depth_prepass; - rebind = true; - } - bool base_pass = !accum_pass && !unshaded; //conditions for a base pass if (base_pass != prev_base_pass) { @@ -2434,6 +2421,19 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } } + bool depth_prepass = false; + + if (!p_alpha_pass && material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + depth_prepass = true; + } + + if (depth_prepass != prev_depth_prepass) { + + state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, depth_prepass); + prev_depth_prepass = depth_prepass; + rebind = true; + } + bool instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH; if (instancing != prev_instancing) { @@ -3171,9 +3171,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ width /= 2; height /= 2; - if (p_pass == 0) { - - } else if (p_pass == 1) { + if (p_pass == 1) { x += width; } else if (p_pass == 2) { y += height; diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index c591db4f3d..a0188da4f6 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -3976,20 +3976,19 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const { float len = light->param[VS::LIGHT_PARAM_RANGE]; float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); - } break; + }; case VS::LIGHT_OMNI: { float r = light->param[VS::LIGHT_PARAM_RANGE]; return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); - } break; + }; case VS::LIGHT_DIRECTIONAL: { return AABB(); - } break; + }; } ERR_FAIL_V(AABB()); - return AABB(); } /* PROBE API */ diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index ca222362e7..b7f8ec3ce9 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -1549,7 +1549,7 @@ FRAGMENT_SHADER_CODE #endif // ALPHA_SCISSOR_USED #ifdef USE_DEPTH_PREPASS - if (alpha < 0.99) { + if (alpha < 0.1) { discard; } #endif // USE_DEPTH_PREPASS @@ -2112,7 +2112,7 @@ FRAGMENT_SHADER_CODE #endif // ALPHA_SCISSOR_USED #ifdef USE_DEPTH_PREPASS - if (alpha < 0.99) { + if (alpha < 0.1) { discard; } #endif // USE_DEPTH_PREPASS diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index fb3d154a7a..f3ba29a0e7 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1008,7 +1008,8 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { if (!light_instance->light_ptr) { memdelete(light_instance); - ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); + ERR_EXPLAIN("Condition ' !light_instance->light_ptr ' is true."); + ERR_FAIL_V(RID()); } light_instance->self = light_instance_owner.make_rid(light_instance); @@ -2364,7 +2365,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G if (p_depth_pass) { - if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) || p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER || p_material->shader->spatial.no_depth_test) + if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) || p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER || p_material->shader->spatial.no_depth_test || p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) return; //bye if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { @@ -2763,9 +2764,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform width /= 2; height /= 2; - if (j == 0) { - - } else if (j == 1) { + if (j == 1) { x += width; } else if (j == 2) { y += height; @@ -2778,9 +2777,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform height /= 2; - if (j == 0) { - - } else { + if (j != 0) { y += height; } } @@ -4741,9 +4738,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ width /= 2; height /= 2; - if (p_pass == 0) { - - } else if (p_pass == 1) { + if (p_pass == 1) { x += width; } else if (p_pass == 2) { y += height; @@ -5301,7 +5296,7 @@ void RasterizerSceneGLES3::initialize() { GLOBAL_DEF("rendering/quality/subsurface_scattering/follow_surface", false); GLOBAL_DEF("rendering/quality/subsurface_scattering/weight_samples", true); - GLOBAL_DEF("rendering/quality/voxel_cone_tracing/high_quality", true); + GLOBAL_DEF("rendering/quality/voxel_cone_tracing/high_quality", false); } exposure_shrink_size = 243; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 994ed25f01..57b4c198eb 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5471,22 +5471,19 @@ AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { float len = light->param[VS::LIGHT_PARAM_RANGE]; float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); - } break; + }; case VS::LIGHT_OMNI: { float r = light->param[VS::LIGHT_PARAM_RANGE]; return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); - } break; + }; case VS::LIGHT_DIRECTIONAL: { return AABB(); - } break; - default: { - } + }; } ERR_FAIL_V(AABB()); - return AABB(); } /* PROBE API */ diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index d5582d00ed..251bab5783 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -136,31 +136,27 @@ String DirAccessUnix::get_next() { return ""; } - String fname = fix_unicode_name(entry->d_name); - - if (entry->d_type == DT_UNKNOWN) { - //typedef struct stat Stat; - struct stat flags; - - String f = current_dir.plus_file(fname); + //typedef struct stat Stat; + struct stat flags; - if (stat(f.utf8().get_data(), &flags) == 0) { + String fname = fix_unicode_name(entry->d_name); - if (S_ISDIR(flags.st_mode)) { + String f = current_dir.plus_file(fname); - _cisdir = true; + if (stat(f.utf8().get_data(), &flags) == 0) { - } else { + if (S_ISDIR(flags.st_mode)) { - _cisdir = false; - } + _cisdir = true; } else { _cisdir = false; } + } else { - _cisdir = (entry->d_type == DT_DIR); + + _cisdir = false; } _cishidden = (fname != "." && fname != ".." && fname.begins_with(".")); diff --git a/editor/SCsub b/editor/SCsub index 7d48e47c9f..2b560f68e8 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -31,7 +31,7 @@ if env['tools']: reg_exporters_inc = '#include "register_exporters.h"\n' reg_exporters = 'void register_exporters() {\n' for e in env.platform_exporters: - env.editor_sources.append("#platform/" + e + "/export/export.cpp") + env.add_source_files(env.editor_sources, "#platform/" + e + "/export/export.cpp") reg_exporters += '\tregister_' + e + '_exporter();\n' reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n' reg_exporters += '}\n' diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index bc7f01eb81..d1ac69c8d8 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -46,7 +46,7 @@ class AnimationTrackKeyEdit : public Object { public: bool setting; - bool _hide_object_properties_from_inspector() { + bool _hide_script_from_inspector() { return true; } @@ -58,7 +58,7 @@ public: ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj); ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed); - ClassDB::bind_method("_hide_object_properties_from_inspector", &AnimationTrackKeyEdit::_hide_object_properties_from_inspector); + ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector); ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path); ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo); } @@ -1274,12 +1274,7 @@ void AnimationTrackEdit::_notification(int p_what) { } text_color.a *= 0.7; } else if (node) { - Ref<Texture> icon; - if (has_icon(node->get_class(), "EditorIcons")) { - icon = get_icon(node->get_class(), "EditorIcons"); - } else { - icon = get_icon("Node", "EditorIcons"); - } + Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(node, "Node"); draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2)); icon_cache = icon; @@ -3500,9 +3495,7 @@ void AnimationTrackEditor::_update_tracks() { if (root && root->has_node(base_path)) { Node *n = root->get_node(base_path); if (n) { - if (has_icon(n->get_class(), "EditorIcons")) { - icon = get_icon(n->get_class(), "EditorIcons"); - } + icon = EditorNode::get_singleton()->get_object_icon(n, "Node"); name = n->get_name(); tooltip = root->get_path_to(n); } diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index 76ce020d8a..1ea2950df4 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -56,7 +56,7 @@ class EditorAutoloadSettings : public VBoxContainer { int order; Node *node; - bool operator==(const AutoLoadInfo &p_info) { + bool operator==(const AutoLoadInfo &p_info) const { return order == p_info.order; } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 38f30df169..f5846c10f6 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -499,7 +499,6 @@ Object *EditorData::instance_custom_type(const String &p_type, const String &p_i for (int i = 0; i < get_custom_types()[p_inherits].size(); i++) { if (get_custom_types()[p_inherits][i].name == p_type) { - Ref<Texture> icon = get_custom_types()[p_inherits][i].icon; Ref<Script> script = get_custom_types()[p_inherits][i].script; Object *ob = ClassDB::instance(p_inherits); @@ -508,8 +507,6 @@ Object *EditorData::instance_custom_type(const String &p_type, const String &p_i ob->call("set_name", p_type); } ob->set_script(script.get_ref_ptr()); - if (icon.is_valid()) - ob->set_meta("_editor_icon", icon); return ob; } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 0f76aeb818..e4ddf44bc4 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1550,7 +1550,7 @@ void EditorInspector::update_tree() { if (p.usage & PROPERTY_USAGE_HIGH_END_GFX && VS::get_singleton()->is_low_end()) continue; //do not show this property in low end gfx - if ((hide_object_properties || bool(object->call("_hide_object_properties_from_inspector"))) && (p.name == "script" || p.name == "__meta__")) { + if (p.name == "script" && (hide_script || bool(object->call("_hide_script_from_inspector")))) { continue; } @@ -1877,8 +1877,8 @@ void EditorInspector::set_use_doc_hints(bool p_enable) { use_doc_hints = p_enable; update_tree(); } -void EditorInspector::set_hide_object_properties(bool p_hide) { - hide_object_properties = p_hide; +void EditorInspector::set_hide_script(bool p_hide) { + hide_script = p_hide; update_tree(); } void EditorInspector::set_use_filter(bool p_use) { @@ -2318,7 +2318,7 @@ EditorInspector::EditorInspector() { set_enable_v_scroll(true); show_categories = false; - hide_object_properties = true; + hide_script = true; use_doc_hints = false; capitalize_paths = true; use_filter = false; diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 028e1e4111..117a63699e 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -272,7 +272,7 @@ class EditorInspector : public ScrollContainer { LineEdit *search_box; bool show_categories; - bool hide_object_properties; + bool hide_script; bool use_doc_hints; bool capitalize_paths; bool use_filter; @@ -360,7 +360,7 @@ public: void set_show_categories(bool p_show); void set_use_doc_hints(bool p_enable); - void set_hide_object_properties(bool p_hide); + void set_hide_script(bool p_hide); void set_use_filter(bool p_use); void register_text_enter(Node *p_line_edit); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3183f1ae97..f1944bf63f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -832,7 +832,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) { for (List<String>::Element *E = esl.front(); E; E = E->next()) { Variant st = cf->get_value("editor_states", E->get()); - if (st.get_type()) { + if (st.get_type() != Variant::NIL) { md[E->get()] = st; } } @@ -2488,12 +2488,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { screenshot_timer->start(); } break; - case EDITOR_OPEN_SCREENSHOT: { - - bool is_checked = settings_menu->get_popup()->is_item_checked(settings_menu->get_popup()->get_item_index(EDITOR_OPEN_SCREENSHOT)); - settings_menu->get_popup()->set_item_checked(settings_menu->get_popup()->get_item_index(EDITOR_OPEN_SCREENSHOT), !is_checked); - EditorSettings::get_singleton()->set_project_metadata("screenshot_options", "open_screenshot", !is_checked); - } break; case SETTINGS_PICK_MAIN_SCENE: { file->set_mode(EditorFileDialog::MODE_OPEN_FILE); @@ -2541,8 +2535,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { restart_editor(); } break; default: { - if (p_option >= IMPORT_PLUGIN_BASE) { - } } } } @@ -2555,7 +2547,7 @@ void EditorNode::_screenshot(bool p_use_utc) { String name = "editor_screenshot_" + OS::get_singleton()->get_iso_date_time(p_use_utc).replace(":", "") + ".png"; NodePath path = String("user://") + name; _save_screenshot(path); - if (EditorSettings::get_singleton()->get_project_metadata("screenshot_options", "open_screenshot", true)) { + if (EditorSettings::get_singleton()->get("interface/editor/automatically_open_screenshots")) { OS::get_singleton()->shell_open(String("file://") + ProjectSettings::get_singleton()->globalize_path(path)); } } @@ -3488,6 +3480,69 @@ void EditorNode::stop_child_process() { _menu_option_confirm(RUN_STOP, false); } +Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) const { + ERR_FAIL_COND_V(!p_object, NULL); + + Ref<Script> script = p_object->get_script(); + + if (script.is_valid()) { + // Uncommenting would break things! Consider adding a parameter if you need it. + // StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path()); + // if (name != StringName()) + // return name; + + // should probably be deprecated in 4.x + StringName base = script->get_instance_base_type(); + if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) { + const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base]; + + Ref<Script> base_script = script; + while (base_script.is_valid()) { + for (int i = 0; i < types.size(); ++i) { + if (types[i].script == base_script) { + return types[i].script; + } + } + base_script = base_script->get_base_script(); + } + } + } + + return NULL; +} + +StringName EditorNode::get_object_custom_type_name(const Object *p_object) const { + ERR_FAIL_COND_V(!p_object, StringName()); + + Ref<Script> script = p_object->get_script(); + if (script.is_null() && p_object->is_class("Script")) { + script = p_object; + } + + if (script.is_valid()) { + Ref<Script> base_script = script; + while (base_script.is_valid()) { + StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path()); + if (name != StringName()) + return name; + + // should probably be deprecated in 4.x + StringName base = base_script->get_instance_base_type(); + if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) { + const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base]; + for (int i = 0; i < types.size(); ++i) { + if (types[i].script == base_script) { + return types[i].name; + } + } + } + base_script = base_script->get_base_script(); + } + } + + return StringName(); +} + Ref<Texture> EditorNode::get_object_icon(const Object *p_object, const String &p_fallback) const { ERR_FAIL_COND_V(!p_object || !gui_base, NULL); @@ -3497,23 +3552,24 @@ Ref<Texture> EditorNode::get_object_icon(const Object *p_object, const String &p } if (script.is_valid()) { - StringName name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); - String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name); - if (icon_path.length()) - return ResourceLoader::load(icon_path); - - // should probably be deprecated in 4.x - StringName base = script->get_instance_base_type(); - if (base != StringName()) { - const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types(); - for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) { - const Vector<EditorData::CustomType> &ct = E->value(); - for (int i = 0; i < ct.size(); ++i) { - if (ct[i].name == base && ct[i].icon.is_valid()) { - return ct[i].icon; + Ref<Script> base_script = script; + while (base_script.is_valid()) { + StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path()); + String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name); + if (icon_path.length()) + return ResourceLoader::load(icon_path); + + // should probably be deprecated in 4.x + StringName base = base_script->get_instance_base_type(); + if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) { + const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base]; + for (int i = 0; i < types.size(); ++i) { + if (types[i].script == base_script && types[i].icon.is_valid()) { + return types[i].icon; } } } + base_script = base_script->get_base_script(); } } @@ -5938,16 +5994,13 @@ EditorNode::EditorNode() { p->add_child(editor_layouts); editor_layouts->connect("id_pressed", this, "_layout_menu_option"); p->add_submenu_item(TTR("Editor Layout"), "Layouts"); + p->add_separator(); #ifdef OSX_ENABLED p->add_shortcut(ED_SHORTCUT("editor/take_screenshot", TTR("Take Screenshot"), KEY_MASK_CMD | KEY_F12), EDITOR_SCREENSHOT); #else p->add_shortcut(ED_SHORTCUT("editor/take_screenshot", TTR("Take Screenshot"), KEY_MASK_CTRL | KEY_F12), EDITOR_SCREENSHOT); #endif p->set_item_tooltip(p->get_item_count() - 1, TTR("Screenshots are stored in the Editor Data/Settings Folder.")); - p->add_check_shortcut(ED_SHORTCUT("editor/open_screenshot", TTR("Automatically Open Screenshots")), EDITOR_OPEN_SCREENSHOT); - bool is_open_screenshot = EditorSettings::get_singleton()->get_project_metadata("screenshot_options", "open_screenshot", true); - p->set_item_checked(p->get_item_count() - 1, is_open_screenshot); - p->set_item_tooltip(p->get_item_count() - 1, TTR("Open in an external image editor.")); #ifdef OSX_ENABLED p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_F), SETTINGS_TOGGLE_FULLSCREEN); #else diff --git a/editor/editor_node.h b/editor/editor_node.h index 5dabe529f9..9aee19e6c1 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -776,6 +776,8 @@ public: void stop_child_process(); Ref<Theme> get_editor_theme() const { return theme; } + Ref<Script> get_object_custom_type_base(const Object *p_object) const; + StringName get_object_custom_type_name(const Object *p_object) const; Ref<Texture> get_object_icon(const Object *p_object, const String &p_fallback = "Object") const; Ref<Texture> get_class_icon(const String &p_class, const String &p_fallback = "Object") const; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index a8ef563368..d54f72382c 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -112,12 +112,13 @@ void EditorPropertyMultilineText::_open_big_text() { big_text->set_wrap_enabled(true); big_text_dialog = memnew(AcceptDialog); big_text_dialog->add_child(big_text); - big_text_dialog->set_title("Edit Text:"); + big_text_dialog->set_title(TTR("Edit Text:")); add_child(big_text_dialog); } big_text_dialog->popup_centered_ratio(); big_text->set_text(text->get_text()); + big_text->grab_focus(); } void EditorPropertyMultilineText::update_property() { @@ -389,7 +390,7 @@ void EditorPropertyMember::_property_select() { type = Variant::Type(i); } } - if (type) + if (type != Variant::NIL) selector->select_method_from_basic_type(type, current); } else if (hint == MEMBER_METHOD_OF_BASE_TYPE) { @@ -2412,7 +2413,6 @@ void EditorPropertyResource::_update_menu_items() { menu->add_separator(); menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM); } - } else { } RES cb = EditorSettings::get_singleton()->get_resource_clipboard(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 347699c632..203136a3f8 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -414,8 +414,6 @@ void EditorPropertyArray::_remove_pressed(int p_index) { } void EditorPropertyArray::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - } } void EditorPropertyArray::_edit_pressed() { @@ -968,9 +966,6 @@ void EditorPropertyDictionary::_object_id_selected(const String &p_property, Obj } void EditorPropertyDictionary::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - } } void EditorPropertyDictionary::_edit_pressed() { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 223ca7a108..b4c1fc3463 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -345,6 +345,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/separate_distraction_mode", false); + _initial_set("interface/editor/automatically_open_screenshots", true); _initial_set("interface/editor/hide_console_window", false); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression _initial_set("interface/editor/quit_confirmation", true); diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index bc507e91b2..8246e74814 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1327,7 +1327,9 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { if (bct.has("index")) { Ref<Texture> t = _get_texture(state, bct["index"]); material->set_texture(SpatialMaterial::TEXTURE_METALLIC, t); + material->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_BLUE); material->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, t); + material->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GREEN); if (!mr.has("metallicFactor")) { material->set_metallic(1); } @@ -1352,6 +1354,7 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { Dictionary bct = d["occlusionTexture"]; if (bct.has("index")) { material->set_texture(SpatialMaterial::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"])); + material->set_ao_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_RED); material->set_feature(SpatialMaterial::FEATURE_AMBIENT_OCCLUSION, true); } } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index a8197ec2a2..53b67c46b0 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -893,7 +893,6 @@ void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) { keep.insert(F->get()); } _filter_anim_tracks(anim->get_animation(name), keep); - } else { } } } diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index e728dbac31..d267b29224 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -206,6 +206,11 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s frames = chunksize; + if (format_channels == 0) { + file->close(); + memdelete(file); + ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA); + } frames /= format_channels; frames /= (format_bits >> 3); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 08df780232..8a0812973f 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -597,7 +597,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { inspector->set_show_categories(true); inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); inspector->set_use_doc_hints(true); - inspector->set_hide_object_properties(false); + inspector->set_hide_script(false); inspector->set_enable_capitalize_paths(bool(EDITOR_GET("interface/inspector/capitalize_properties"))); inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding"))); inspector->register_text_enter(search); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index d4eab888cc..19199f37ef 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1061,9 +1061,11 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { + bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control(); + if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) { // Scroll or pan down - if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { + if (pan_on_scroll) { view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); update_viewport(); } else { @@ -1074,7 +1076,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_UP) { // Scroll or pan up - if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { + if (pan_on_scroll) { view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); update_viewport(); } else { @@ -1085,7 +1087,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_LEFT) { // Pan left - if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { + if (pan_on_scroll) { view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); update_viewport(); return true; @@ -1094,7 +1096,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_RIGHT) { // Pan right - if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { + if (pan_on_scroll) { view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); update_viewport(); return true; @@ -1104,6 +1106,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { if (!panning) { if (b->is_pressed() && (b->get_button_index() == BUTTON_MIDDLE || + b->get_button_index() == BUTTON_RIGHT || (b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) || (b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) { // Pan the viewport @@ -1431,7 +1434,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { for (int i = 0; i < 4; i++) { anchor_pos[i] = (transform * control->get_global_transform_with_canvas()).xform(_anchor_to_position(control, anchor_pos[i])); anchor_rects[i] = Rect2(anchor_pos[i], anchor_handle->get_size()); - anchor_rects[i].position -= anchor_handle->get_size() * Vector2(i == 0 || i == 3, i <= 1); + anchor_rects[i].position -= anchor_handle->get_size() * Vector2(float(i == 0 || i == 3), float(i <= 1)); } DragType dragger[] = { diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index ebacccb03c..e125c18ef1 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -34,9 +34,6 @@ void MaterialEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { - } - if (p_what == NOTIFICATION_READY) { //get_scene()->connect("node_removed",this,"_node_removed"); diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 6203035e25..442110cc84 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -48,9 +48,6 @@ void MeshEditor::_gui_input(Ref<InputEvent> p_event) { void MeshEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { - } - if (p_what == NOTIFICATION_READY) { //get_scene()->connect("node_removed",this,"_node_removed"); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index b8d95efd49..620bf28415 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -39,9 +39,6 @@ void ResourcePreloaderEditor::_gui_input(Ref<InputEvent> p_event) { void ResourcePreloaderEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { - } - if (p_what == NOTIFICATION_ENTER_TREE) { load->set_icon(get_icon("Folder", "EditorIcons")); } diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 0aa4a7662c..6d71c56ead 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -39,9 +39,6 @@ void TextureEditor::_gui_input(Ref<InputEvent> p_event) { void TextureEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { - } - if (p_what == NOTIFICATION_READY) { //get_scene()->connect("node_removed",this,"_node_removed"); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index cb48b5eaa5..4d349f06b7 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -193,7 +193,7 @@ void TextureRegionEditor::_region_draw() { updating_scroll = false; if (node_ninepatch || obj_styleBox.is_valid()) { - float margins[4]; + float margins[4] = { 0 }; if (node_ninepatch) { margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP); margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM); @@ -204,12 +204,8 @@ void TextureRegionEditor::_region_draw() { margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM); margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT); margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); - } else { - margins[0] = 0; - margins[1] = 0; - margins[2] = 0; - margins[3] = 0; } + Vector2 pos[4] = { mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y * draw_zoom), -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y * draw_zoom), @@ -248,7 +244,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { if (mb->is_pressed()) { if (node_ninepatch || obj_styleBox.is_valid()) { edited_margin = -1; - float margins[4]; + float margins[4] = { 0 }; if (node_ninepatch) { margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP); margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM); @@ -260,6 +256,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT); margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); } + Vector2 pos[4] = { mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs * draw_zoom, mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs * draw_zoom, diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 5e87016171..f135becf5f 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -3369,7 +3369,7 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const void TilesetEditorContext::_bind_methods() { - ClassDB::bind_method("_hide_object_properties_from_inspector", &TilesetEditorContext::_hide_object_properties_from_inspector); + ClassDB::bind_method("_hide_script_from_inspector", &TilesetEditorContext::_hide_script_from_inspector); } TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) { diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 946c042b02..69ad8205a4 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -252,7 +252,7 @@ class TilesetEditorContext : public Object { bool snap_options_visible; public: - bool _hide_object_properties_from_inspector() { return true; } + bool _hide_script_from_inspector() { return true; } void set_tileset(const Ref<TileSet> &p_tileset); private: diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index aaa99996e6..28719d9e3e 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1513,7 +1513,6 @@ void VisualShaderEditor::_notification(int p_what) { if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) _update_graph(); - } else if (p_what == NOTIFICATION_PROCESS) { } } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index f05b6b5890..1c588a45f1 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -965,8 +965,6 @@ void ProjectSettingsEditor::_action_add() { while (r->get_next()) r = r->get_next(); - if (!r) - return; r->select(0); input_editor->ensure_cursor_is_visible(); action_add_error->hide(); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 82d974cae3..899343c0f8 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -614,7 +614,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: type = Variant::Type(i); } } - if (type) + if (type != Variant::NIL) property_select->select_method_from_basic_type(type, v); updating = false; return false; @@ -971,7 +971,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: menu->add_separator(); menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM); } - } else { } RES cb = EditorSettings::get_singleton()->get_resource_clipboard(); diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index 813e24bd61..3bc93c3900 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -337,7 +337,7 @@ void PropertySelector::_item_selected() { String name = item->get_metadata(0); String class_type; - if (type) { + if (type != Variant::NIL) { class_type = Variant::get_type_name(type); } else { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index c7fc466cd8..009ac603e2 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -467,8 +467,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *n = Object::cast_to<Node>(selection[i]); Ref<Script> existing = n->get_script(); - if (existing.is_valid()) { - const RefPtr empty; + Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n); + if (existing != empty) { editor_data->get_undo_redo().add_do_method(n, "set_script", empty); editor_data->get_undo_redo().add_undo_method(n, "set_script", existing); } @@ -2380,6 +2380,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->clear(); Ref<Script> existing_script; + bool exisiting_script_removable = true; if (selection.size() == 1) { Node *selected = selection[0]; @@ -2399,6 +2400,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); existing_script = selected->get_script(); + + if (EditorNode::get_singleton()->get_object_custom_type_base(selected) == existing_script) { + exisiting_script_removable = false; + } } if (profile_allow_script_editing) { @@ -2410,7 +2415,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_ATTACH_SCRIPT); } } - if (selection.size() > 1 || existing_script.is_valid()) { + if (selection.size() > 1 || (existing_script.is_valid() && exisiting_script_removable)) { menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); } menu->add_separator(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index c1a14685b0..2d9accc3d8 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -212,13 +212,19 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { Color accent = get_color("accent_color", "Editor"); Ref<Script> script = p_node->get_script(); - if (!script.is_null()) { + if (!script.is_null() && EditorNode::get_singleton()->get_object_custom_type_base(p_node) != script) { //has script item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT); } else { - //has no script + //has no script (or script is a custom type) item->set_custom_color(0, get_color("disabled_font_color", "Editor")); item->set_selectable(0, false); + + if (!script.is_null()) { // make sure to mark the script if a custom type + item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT); + item->set_button_disabled(0, item->get_button_count(0) - 1, true); + } + accent.a *= 0.7; } @@ -284,7 +290,10 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { item->add_button(0, get_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor")); item->set_tooltip(0, TTR("Instance:") + " " + p_node->get_filename() + "\n" + TTR("Type:") + " " + p_node->get_class()); } else { - item->set_tooltip(0, String(p_node->get_name()) + "\n" + TTR("Type:") + " " + p_node->get_class()); + StringName type = EditorNode::get_singleton()->get_object_custom_type_name(p_node); + if (type == StringName()) + type = p_node->get_class(); + item->set_tooltip(0, String(p_node->get_name()) + "\n" + TTR("Type:") + " " + type); } if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes @@ -295,6 +304,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { Ref<Script> script = p_node->get_script(); if (!script.is_null()) { item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path()); + if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) { + item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5)); + } } if (p_node->is_class("CanvasItem")) { diff --git a/main/SCsub b/main/SCsub index e7fe6ab4e1..62bc155c67 100644 --- a/main/SCsub +++ b/main/SCsub @@ -6,6 +6,7 @@ from platform_methods import run_in_subprocess import main_builders env.main_sources = [] + env.add_source_files(env.main_sources, "*.cpp") # order matters here. higher index controller database files write on top of lower index database files @@ -14,7 +15,9 @@ controller_databases = ["#main/gamecontrollerdb.txt", "#main/gamecontrollerdb_20 env.Depends("#main/default_controller_mappings.gen.cpp", controller_databases) env.CommandNoCache("#main/default_controller_mappings.gen.cpp", controller_databases, run_in_subprocess(main_builders.make_default_controller_mappings)) -env.main_sources.append("#main/default_controller_mappings.gen.cpp") +# Don't warn about duplicate entry here, we need it registered manually for first build, +# even if later builds will pick it up twice due to above *.cpp globbing. +env.add_source_files(env.main_sources, "#main/default_controller_mappings.gen.cpp", warn_duplicates=False) env.Depends("#main/splash.gen.h", "#main/splash.png") env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash)) diff --git a/methods.py b/methods.py index bb4adfb70b..7840fb1b64 100644 --- a/methods.py +++ b/methods.py @@ -8,14 +8,28 @@ import subprocess from compat import iteritems, isbasestring, decode_utf8 -def add_source_files(self, sources, filetype, lib_env=None, shared=False): - - if isbasestring(filetype): - dir_path = self.Dir('.').abspath - filetype = sorted(glob.glob(dir_path + "/" + filetype)) - - for path in filetype: - sources.append(self.Object(path)) +def add_source_files(self, sources, files, warn_duplicates=True): + # Convert string to list of absolute paths (including expanding wildcard) + if isbasestring(files): + # Keep SCons project-absolute path as they are (no wildcard support) + if files.startswith('#'): + if '*' in files: + print("ERROR: Wildcards can't be expanded in SCons project-absolute path: '{}'".format(files)) + return + files = [files] + else: + dir_path = self.Dir('.').abspath + files = sorted(glob.glob(dir_path + "/" + files)) + + # Add each path as compiled Object following environment (self) configuration + for path in files: + obj = self.Object(path) + if obj in sources: + if warn_duplicates: + print("WARNING: Object \"{}\" already included in environment sources.".format(obj)) + else: + continue + sources.append(obj) def disable_warnings(self): diff --git a/modules/SCsub b/modules/SCsub index 36c2472c42..42d89d6ce2 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -6,9 +6,9 @@ env_modules = env.Clone() Export('env_modules') -env.modules_sources = [ - "register_module_types.gen.cpp", -] +env.modules_sources = [] + +env_modules.add_source_files(env.modules_sources, "register_module_types.gen.cpp") for x in env.module_list: if (x in env.disabled_modules): diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm index de58f93276..68844c54c2 100644 --- a/modules/arkit/arkit_interface.mm +++ b/modules/arkit/arkit_interface.mm @@ -430,7 +430,7 @@ void ARKitInterface::process() { // get some info about our screen and orientation Size2 screen_size = OS::get_singleton()->get_window_size(); - UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; // Grab our camera image for our backbuffer CVPixelBufferRef pixelBuffer = current_frame.capturedImage; @@ -531,7 +531,7 @@ void ARKitInterface::process() { // we need to invert this, probably row v.s. column notation affine_transform = CGAffineTransformInvert(affine_transform); - if (orientation != UIDeviceOrientationPortrait) { + if (orientation != UIInterfaceOrientationPortrait) { affine_transform.b = -affine_transform.b; affine_transform.d = -affine_transform.d; affine_transform.ty = 1.0 - affine_transform.ty; @@ -582,28 +582,28 @@ void ARKitInterface::process() { // copy our current frame transform matrix_float4x4 m44 = camera.transform; - if (orientation == UIDeviceOrientationLandscapeLeft) { + if (orientation == UIInterfaceOrientationLandscapeLeft) { transform.basis.elements[0].x = m44.columns[0][0]; transform.basis.elements[1].x = m44.columns[0][1]; transform.basis.elements[2].x = m44.columns[0][2]; transform.basis.elements[0].y = m44.columns[1][0]; transform.basis.elements[1].y = m44.columns[1][1]; transform.basis.elements[2].y = m44.columns[1][2]; - } else if (orientation == UIDeviceOrientationPortrait) { + } else if (orientation == UIInterfaceOrientationPortrait) { transform.basis.elements[0].x = m44.columns[1][0]; transform.basis.elements[1].x = m44.columns[1][1]; transform.basis.elements[2].x = m44.columns[1][2]; transform.basis.elements[0].y = -m44.columns[0][0]; transform.basis.elements[1].y = -m44.columns[0][1]; transform.basis.elements[2].y = -m44.columns[0][2]; - } else if (orientation == UIDeviceOrientationLandscapeRight) { + } else if (orientation == UIInterfaceOrientationLandscapeRight) { transform.basis.elements[0].x = -m44.columns[0][0]; transform.basis.elements[1].x = -m44.columns[0][1]; transform.basis.elements[2].x = -m44.columns[0][2]; transform.basis.elements[0].y = -m44.columns[1][0]; transform.basis.elements[1].y = -m44.columns[1][1]; transform.basis.elements[2].y = -m44.columns[1][2]; - } else if (orientation == UIDeviceOrientationPortraitUpsideDown) { + } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { // this may not be correct transform.basis.elements[0].x = m44.columns[1][0]; transform.basis.elements[1].x = m44.columns[1][1]; diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub index 8a77e4f803..d8ef866bec 100644 --- a/modules/assimp/SCsub +++ b/modules/assimp/SCsub @@ -72,11 +72,6 @@ env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_X3D_IMPORTER']) env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_SINGLETHREADED']) -if (not env.msvc): - env_assimp.Append(CXXFLAGS=['-std=c++11']) -elif (env.msvc == False and env['platform'] == 'windows'): - env_assimp.Append(LDFLAGS=['-pthread']) - if(env['platform'] == 'windows'): env_assimp.Append(CPPDEFINES=['PLATFORM_WINDOWS']) env_assimp.Append(CPPDEFINES=[('PLATFORM', 'WINDOWS')]) diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index f23c66dbcf..65fa8b6459 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -1718,7 +1718,7 @@ void EditorSceneImporterAssimp::_find_texture_path(const String &p_path, _Direct } } -String EditorSceneImporterAssimp::_assimp_get_string(const aiString p_string) const { +String EditorSceneImporterAssimp::_assimp_get_string(const aiString &p_string) const { //convert an assimp String to a Godot String String name; name.parse_utf8(p_string.C_Str() /*,p_string.length*/); @@ -1733,7 +1733,7 @@ String EditorSceneImporterAssimp::_assimp_get_string(const aiString p_string) co return name; } -String EditorSceneImporterAssimp::_assimp_anim_string_to_string(const aiString p_string) const { +String EditorSceneImporterAssimp::_assimp_anim_string_to_string(const aiString &p_string) const { String name; name.parse_utf8(p_string.C_Str() /*,p_string.length*/); @@ -1745,7 +1745,7 @@ String EditorSceneImporterAssimp::_assimp_anim_string_to_string(const aiString p return name; } -String EditorSceneImporterAssimp::_assimp_raw_string_to_string(const aiString p_string) const { +String EditorSceneImporterAssimp::_assimp_raw_string_to_string(const aiString &p_string) const { String name; name.parse_utf8(p_string.C_Str() /*,p_string.length*/); return name; diff --git a/modules/assimp/editor_scene_importer_assimp.h b/modules/assimp/editor_scene_importer_assimp.h index 598845236e..7a30816e3b 100644 --- a/modules/assimp/editor_scene_importer_assimp.h +++ b/modules/assimp/editor_scene_importer_assimp.h @@ -178,7 +178,7 @@ private: }; const Transform _assimp_matrix_transform(const aiMatrix4x4 p_matrix); - String _assimp_get_string(const aiString p_string) const; + String _assimp_get_string(const aiString &p_string) const; Transform _get_global_assimp_node_transform(const aiNode *p_current_node); void _calc_tangent_from_mesh(const aiMesh *ai_mesh, int i, int tri_index, int index, PoolColorArray::Write &w); @@ -200,8 +200,8 @@ private: Spatial *_generate_scene(const String &p_path, const aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights); - String _assimp_anim_string_to_string(const aiString p_string) const; - String _assimp_raw_string_to_string(const aiString p_string) const; + String _assimp_anim_string_to_string(const aiString &p_string) const; + String _assimp_raw_string_to_string(const aiString &p_string) const; float _get_fbx_fps(int32_t time_mode, const aiScene *p_scene); template <class T> T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp); diff --git a/modules/etc/SCsub b/modules/etc/SCsub index 532b97b006..1742d3534f 100644 --- a/modules/etc/SCsub +++ b/modules/etc/SCsub @@ -29,10 +29,6 @@ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_etc.Prepend(CPPPATH=[thirdparty_dir]) -# upstream uses c++11 -if not env.msvc: - env_etc.Append(CXXFLAGS="-std=c++11") - env_thirdparty = env_etc.Clone() env_thirdparty.disable_warnings() env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp index b7ab887e11..3b46f33afb 100644 --- a/modules/gdnative/pluginscript/register_types.cpp +++ b/modules/gdnative/pluginscript/register_types.cpp @@ -114,6 +114,8 @@ void unregister_pluginscript_types() { for (List<PluginScriptLanguage *>::Element *e = pluginscript_languages.front(); e; e = e->next()) { PluginScriptLanguage *language = e->get(); ScriptServer::unregister_language(language); + ResourceLoader::remove_resource_format_loader(language->get_resource_loader()); + ResourceSaver::remove_resource_format_saver(language->get_resource_saver()); memdelete(language); } } diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index a21b6a2907..62a3794c6d 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -389,37 +389,6 @@ [/codeblock] </description> </method> - <method name="posmod"> - <return type="int"> - </return> - <argument index="0" name="a" type="int"> - </argument> - <argument index="1" name="b" type="int"> - </argument> - <description> - Returns the integer modulus of [code]a/b[/code] that wraps equally in positive and negative. - [codeblock] - var i = -6 - while i < 5: - prints(i, posmod(i, 3)) - i += 1 - [/codeblock] - Produces: - [codeblock] - -6 0 - -5 1 - -4 2 - -3 0 - -2 1 - -1 2 - 0 0 - 1 1 - 2 2 - 3 0 - 4 1 - [/codeblock] - </description> - </method> <method name="funcref"> <return type="FuncRef"> </return> @@ -604,6 +573,29 @@ [/codeblock] </description> </method> + <method name="lerp_angle"> + <return type="float"> + </return> + <argument index="0" name="from" type="float"> + </argument> + <argument index="1" name="to" type="float"> + </argument> + <argument index="2" name="weight" type="float"> + </argument> + <description> + Linearly interpolates between two angles (in radians) by a normalized value. + Similar to [method lerp] but interpolate correctly when the angles wrap around [constant @GDScript.TAU]. + [codeblock] + extends Sprite + var elapsed = 0.0 + func _process(delta): + var min_angle = deg2rad(0.0) + var max_angle = deg2rad(90.0) + rotation = lerp_angle(min_angle, max_angle, elapsed) + elapsed += delta + [/codeblock] + </description> + </method> <method name="linear2db"> <return type="float"> </return> @@ -730,12 +722,43 @@ Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis). </description> </method> + <method name="posmod"> + <return type="int"> + </return> + <argument index="0" name="a" type="int"> + </argument> + <argument index="1" name="b" type="int"> + </argument> + <description> + Returns the integer modulus of [code]a/b[/code] that wraps equally in positive and negative. + [codeblock] + var i = -6 + while i < 5: + prints(i, posmod(i, 3)) + i += 1 + [/codeblock] + Produces: + [codeblock] + -6 0 + -5 1 + -4 2 + -3 0 + -2 1 + -1 2 + 0 0 + 1 1 + 2 2 + 3 0 + 4 1 + [/codeblock] + </description> + </method> <method name="pow"> <return type="float"> </return> - <argument index="0" name="x" type="float"> + <argument index="0" name="base" type="float"> </argument> - <argument index="1" name="y" type="float"> + <argument index="1" name="exp" type="float"> </argument> <description> Returns the result of [code]x[/code] raised to the power of [code]y[/code]. diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 521b5ed538..9f65a9fff1 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -386,8 +386,6 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_line >= 0) - return ""; return ""; } diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 8c33d6613c..f5f245b25f 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -76,6 +76,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "step_decimals", "stepify", "lerp", + "lerp_angle", "inverse_lerp", "range_lerp", "smoothstep", @@ -383,6 +384,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; } } break; + case MATH_LERP_ANGLE: { + VALIDATE_ARG_COUNT(3); + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + r_ret = Math::lerp_angle((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]); + } break; case MATH_INVERSE_LERP: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); @@ -1676,6 +1684,11 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; return mi; } break; + case MATH_LERP_ANGLE: { + MethodInfo mi("lerp_angle", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight")); + mi.return_val.type = Variant::REAL; + return mi; + } break; case MATH_INVERSE_LERP: { MethodInfo mi("inverse_lerp", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight")); mi.return_val.type = Variant::REAL; diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h index d52b9118d3..8f7ba76d2c 100644 --- a/modules/gdscript/gdscript_functions.h +++ b/modules/gdscript/gdscript_functions.h @@ -67,6 +67,7 @@ public: MATH_STEP_DECIMALS, MATH_STEPIFY, MATH_LERP, + MATH_LERP_ANGLE, MATH_INVERSE_LERP, MATH_RANGE_LERP, MATH_SMOOTHSTEP, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index fa430b5364..f006d50a83 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -1766,8 +1766,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to cn->value = v; cn->datatype = _type_from_variant(v); return cn; - - } else if (op->arguments[0]->type == Node::TYPE_BUILT_IN_FUNCTION && last_not_constant == 0) { } return op; //don't reduce yet diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 994a84fbc4..bdecbbdbad 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -481,11 +481,6 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Transform xform; - if (clip && ((clip_above && cellpos[clip_axis] > clip_floor) || (!clip_above && cellpos[clip_axis] < clip_floor))) { - - } else { - } - xform.basis.set_orthogonal_index(c.rot); xform.set_origin(cellpos * cell_size + ofs); xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale)); diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 71ccdb7aab..4a6637434a 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -30,6 +30,8 @@ #include "class_db_api_json.h" +#ifdef DEBUG_METHODS_ENABLED + #include "core/io/json.h" #include "core/os/file_access.h" #include "core/project_settings.h" @@ -240,3 +242,5 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); } + +#endif // DEBUG_METHODS_ENABLED diff --git a/modules/mono/class_db_api_json.h b/modules/mono/class_db_api_json.h index 0aa9c20930..ddfe2debea 100644 --- a/modules/mono/class_db_api_json.h +++ b/modules/mono/class_db_api_json.h @@ -31,9 +31,16 @@ #ifndef CLASS_DB_API_JSON_H #define CLASS_DB_API_JSON_H +// 'core/method_bind.h' defines DEBUG_METHODS_ENABLED, but it looks like we +// cannot include it here. That's why we include it through 'core/class_db.h'. #include "core/class_db.h" + +#ifdef DEBUG_METHODS_ENABLED + #include "core/ustring.h" void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api); +#endif // DEBUG_METHODS_ENABLED + #endif // CLASS_DB_API_JSON_H diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index 2d8c63fe7f..6c1a51fcf9 100644 --- a/modules/mono/glue/Managed/Files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs @@ -185,6 +185,12 @@ namespace Godot return from + (to - from) * weight; } + public static real_t LerpAngle(real_t from, real_t to, real_t weight) { + real_t difference = (to - from) % Mathf.Tau; + real_t distance = ((2 * difference) % Mathf.Tau) - difference; + return from + distance * weight; + } + public static real_t Log(real_t s) { return (real_t)Math.Log(s); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 096ad0f5e3..571bf598f3 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -602,12 +602,12 @@ bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type) { String GDMono::update_api_assemblies_from_prebuilt() { -#define FAIL_REASON(m_out_of_sync, m_prebuilt_exist) \ +#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \ ( \ (m_out_of_sync ? \ String("The assembly is invalidated") : \ String("The assembly was not found")) + \ - (m_prebuilt_exist ? \ + (m_prebuilt_exists ? \ String(" and the prebuilt assemblies are missing") : \ String(" and we failed to copy the prebuilt assemblies"))) @@ -619,16 +619,18 @@ String GDMono::update_api_assemblies_from_prebuilt() { if (!api_assembly_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) return String(); // No update needed + print_verbose("Updating API assemblies"); + String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) - return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ false); + return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ false); // Copy the prebuilt Api if (!copy_prebuilt_api_assembly(APIAssembly::API_CORE) || !copy_prebuilt_api_assembly(APIAssembly::API_EDITOR)) - return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ true); + return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ true); return String(); // Updated successfully @@ -699,9 +701,6 @@ bool GDMono::_try_load_api_assemblies() { return false; } - if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) - return false; - #ifdef TOOLS_ENABLED if (!_load_editor_api_assembly()) { if (OS::get_singleton()->is_stdout_verbose()) @@ -713,12 +712,19 @@ bool GDMono::_try_load_api_assemblies() { return false; #endif + // Check if the core API assembly is out of sync only after trying to load the + // editor API assembly. Otherwise, if both assemblies are out of sync, we would + // only update the former as we won't know the latter also needs to be updated. + if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) + return false; + return true; } void GDMono::_load_api_assemblies() { if (!_try_load_api_assemblies()) { +#ifdef TOOLS_ENABLED // The API assemblies are out of sync. Fine, try one more time, but this time // update them from the prebuilt assemblies directory before trying to load them. @@ -752,11 +758,9 @@ void GDMono::_load_api_assemblies() { ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed"); } -#ifdef TOOLS_ENABLED if (editor_api_assembly_out_of_sync) { ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync"); } -#endif CRASH_NOW(); } else { @@ -764,6 +768,10 @@ void GDMono::_load_api_assemblies() { CRASH_NOW(); } } +#else + ERR_EXPLAIN("Failed to load one of the API assemblies"); + CRASH_NOW(); +#endif } } diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index ae542713ea..6a1b463305 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -499,7 +499,6 @@ void VideoStreamPlaybackTheora::update(float p_delta) { /*If we are too slow, reduce the pp level.*/ pp_inc = pp_level > 0 ? -1 : 0; } - } else { } } else { diff --git a/modules/vhacd/SCsub b/modules/vhacd/SCsub index e581fb7bb2..685976dc33 100644 --- a/modules/vhacd/SCsub +++ b/modules/vhacd/SCsub @@ -26,10 +26,6 @@ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "/inc"]) -# upstream uses c++11 -if not env.msvc: - env_vhacd.Append(CXXFLAGS="-std=c++11") - env_thirdparty = env_vhacd.Clone() env_thirdparty.disable_warnings() env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml index 470a3a5e35..9e3670ec35 100644 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml @@ -213,7 +213,11 @@ return t * t * (3.0 - 2.0 * t) [/codeblock] </constant> - <constant name="FUNC_MAX" value="65" enum="BuiltinFunc"> + <constant name="MATH_POSMOD" value="65" enum="BuiltinFunc"> + </constant> + <constant name="MATH_LERP_ANGLE" value="66" enum="BuiltinFunc"> + </constant> + <constant name="FUNC_MAX" value="67" enum="BuiltinFunc"> Represents the size of the [enum BuiltinFunc] enum. </constant> </constants> diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index b816e37936..4425565afa 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2629,8 +2629,6 @@ void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Varian } String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_node >= 0) - return ""; return ""; } diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 6c9c6b0fc8..8088a71198 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -105,6 +105,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "color_named", "smoothstep", "posmod", + "lerp_angle", }; VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String &p_string) { @@ -207,6 +208,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case COLORN: return 2; case MATH_LERP: + case MATH_LERP_ANGLE: case MATH_INVERSE_LERP: case MATH_SMOOTHSTEP: case MATH_MOVE_TOWARD: @@ -318,7 +320,9 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::REAL, "steps"); } break; case MATH_LERP: - case MATH_INVERSE_LERP: { + case MATH_LERP_ANGLE: + case MATH_INVERSE_LERP: + case MATH_SMOOTHSTEP: { if (p_idx == 0) return PropertyInfo(Variant::REAL, "from"); else if (p_idx == 1) @@ -338,14 +342,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const else return PropertyInfo(Variant::REAL, "ostop"); } break; - case MATH_SMOOTHSTEP: { - if (p_idx == 0) - return PropertyInfo(Variant::REAL, "from"); - else if (p_idx == 1) - return PropertyInfo(Variant::REAL, "to"); - else - return PropertyInfo(Variant::REAL, "weight"); - } break; case MATH_MOVE_TOWARD: { if (p_idx == 0) return PropertyInfo(Variant::REAL, "from"); @@ -532,6 +528,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } break; case MATH_STEPIFY: case MATH_LERP: + case MATH_LERP_ANGLE: case MATH_INVERSE_LERP: case MATH_RANGE_LERP: case MATH_SMOOTHSTEP: @@ -856,6 +853,13 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(2); *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; + case VisualScriptBuiltinFunc::MATH_LERP_ANGLE: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::lerp_angle((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; case VisualScriptBuiltinFunc::MATH_INVERSE_LERP: { VALIDATE_ARG_NUM(0); @@ -1316,7 +1320,6 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_SQRT); BIND_ENUM_CONSTANT(MATH_FMOD); BIND_ENUM_CONSTANT(MATH_FPOSMOD); - BIND_ENUM_CONSTANT(MATH_POSMOD); BIND_ENUM_CONSTANT(MATH_FLOOR); BIND_ENUM_CONSTANT(MATH_CEIL); BIND_ENUM_CONSTANT(MATH_ROUND); @@ -1369,6 +1372,8 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(BYTES_TO_VAR); BIND_ENUM_CONSTANT(COLORN); BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP); + BIND_ENUM_CONSTANT(MATH_POSMOD); + BIND_ENUM_CONSTANT(MATH_LERP_ANGLE); BIND_ENUM_CONSTANT(FUNC_MAX); } @@ -1422,6 +1427,7 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/stepify", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp_angle", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP_ANGLE>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/smoothstep", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SMOOTHSTEP>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index 7821e0eb2d..cf475d675d 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -105,6 +105,7 @@ public: COLORN, MATH_SMOOTHSTEP, MATH_POSMOD, + MATH_LERP_ANGLE, FUNC_MAX }; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 31d5e4665a..603c5a7f3c 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -3670,7 +3670,6 @@ VisualScriptEditor::VisualScriptEditor() { new_virtual_method_select = memnew(VisualScriptPropertySelector); add_child(new_virtual_method_select); new_virtual_method_select->connect("selected", this, "_selected_new_virtual_method"); - new_virtual_method_select->get_cancel(); member_popup = memnew(PopupMenu); add_child(member_popup); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 1b0e41b2de..3b0210597b 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -197,7 +197,6 @@ String VisualScriptFunction::get_output_sequence_port_text(int p_port) const { PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const { ERR_FAIL_V(PropertyInfo()); - return PropertyInfo(); } PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const { @@ -418,7 +417,7 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const { { Variant::NIL, Variant::NIL } //OP_IN, }; - ERR_FAIL_INDEX_V(p_idx, Variant::OP_MAX, PropertyInfo()); + ERR_FAIL_INDEX_V(p_idx, 2, PropertyInfo()); PropertyInfo pinfo; pinfo.name = p_idx == 0 ? "A" : "B"; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index 1e7ed3019c..41828f040e 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -405,7 +405,7 @@ void VisualScriptPropertySelector::_item_selected() { String name = item->get_metadata(0); String class_type; - if (type) { + if (type != Variant::NIL) { class_type = Variant::get_type_name(type); } else { diff --git a/modules/webm/SCsub b/modules/webm/SCsub index e57437229f..32e6727656 100644 --- a/modules/webm/SCsub +++ b/modules/webm/SCsub @@ -17,10 +17,6 @@ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_webm.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "libwebm/"]) -# upstream uses c++11 -if (not env_webm.msvc): - env_webm.Append(CXXFLAGS="-std=c++11") - # also requires libogg, libvorbis and libopus if env['builtin_libogg']: env_webm.Prepend(CPPPATH=["#thirdparty/libogg"]) diff --git a/modules/xatlas_unwrap/SCsub b/modules/xatlas_unwrap/SCsub index 50e3cb1551..b242fd4673 100644 --- a/modules/xatlas_unwrap/SCsub +++ b/modules/xatlas_unwrap/SCsub @@ -15,10 +15,6 @@ if env['builtin_xatlas']: env_xatlas_unwrap.Prepend(CPPPATH=[thirdparty_dir]) - # upstream uses c++11 - if (not env.msvc): - env_xatlas_unwrap.Append(CXXFLAGS="-std=c++11") - env_thirdparty = env_xatlas_unwrap.Clone() env_thirdparty.disable_warnings() env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) diff --git a/platform/SCsub b/platform/SCsub index aa83154ee0..20c89ae8c6 100644 --- a/platform/SCsub +++ b/platform/SCsub @@ -3,7 +3,8 @@ from compat import open_utf8 Import('env') -platform_sources = [] + +env.platform_sources = [] # Register platform-exclusive APIs reg_apis_inc = '#include "register_platform_apis.h"\n' @@ -11,7 +12,7 @@ reg_apis = 'void register_platform_apis() {\n' unreg_apis = 'void unregister_platform_apis() {\n' for platform in env.platform_apis: platform_dir = env.Dir(platform) - platform_sources.append(platform_dir.File('api/api.cpp')) + env.add_source_files(env.platform_sources, platform + '/api/api.cpp') reg_apis += '\tregister_' + platform + '_api();\n' unreg_apis += '\tunregister_' + platform + '_api();\n' reg_apis_inc += '#include "' + platform + '/api/api.h"\n' @@ -25,7 +26,7 @@ with open_utf8('register_platform_apis.gen.cpp', 'w') as f: f.write(reg_apis) f.write(unreg_apis) -platform_sources.append('register_platform_apis.gen.cpp') +env.add_source_files(env.platform_sources, 'register_platform_apis.gen.cpp') -lib = env.add_library('platform', platform_sources) +lib = env.add_library('platform', env.platform_sources) env.Prepend(LIBS=lib) diff --git a/platform/android/SCsub b/platform/android/SCsub index cf6752fa54..d772dc9d71 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -2,7 +2,6 @@ Import('env') -from compat import open_utf8 from distutils.version import LooseVersion from detect import get_ndk_version diff --git a/platform/iphone/camera_ios.mm b/platform/iphone/camera_ios.mm index 029ce6debf..ff84df66ff 100644 --- a/platform/iphone/camera_ios.mm +++ b/platform/iphone/camera_ios.mm @@ -158,7 +158,7 @@ } else if (dataCbCr == NULL) { print_line("Couldn't access CbCr pixel buffer data"); } else { - UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; Ref<Image> img[2]; { diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 85a45d62f8..a179b36bd5 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -768,7 +768,8 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir DirAccess *da = DirAccess::create_for_path(asset); if (!da) { memdelete(filesystem_da); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + ERR_EXPLAIN("Can't create directory: " + asset); + ERR_FAIL_V(ERR_CANT_CREATE); } bool file_exists = da->file_exists(asset); bool dir_exists = da->dir_exists(asset); diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 10680ad1f5..ac43392700 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -128,7 +128,6 @@ def configure(env): ## Link flags env.Append(LINKFLAGS=['-s', 'BINARYEN=1']) - env.Append(LINKFLAGS=['-s', 'BINARYEN_TRAP_MODE=\'clamp\'']) # Allow increasing memory buffer size during runtime. This is efficient # when using WebAssembly (in comparison to asm.js) and works well for diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 1bddc4d22f..4b309a93b5 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -995,9 +995,6 @@ void CPUParticles2D::_notification(int p_what) { _set_redraw(false); } - if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { - } - if (p_what == NOTIFICATION_DRAW) { if (!redraw) return; // don't add to render list diff --git a/scene/3d/SCsub b/scene/3d/SCsub index 200cf4316f..31a443bad1 100644 --- a/scene/3d/SCsub +++ b/scene/3d/SCsub @@ -3,10 +3,10 @@ Import('env') if env['disable_3d']: - env.scene_sources.append("3d/spatial.cpp") - env.scene_sources.append("3d/skeleton.cpp") - env.scene_sources.append("3d/particles.cpp") - env.scene_sources.append("3d/visual_instance.cpp") - env.scene_sources.append("3d/world_environment.cpp") + env.add_source_files(env.scene_sources, "spatial.cpp") + env.add_source_files(env.scene_sources, "skeleton.cpp") + env.add_source_files(env.scene_sources, "particles.cpp") + env.add_source_files(env.scene_sources, "visual_instance.cpp") + env.add_source_files(env.scene_sources, "world_environment.cpp") else: env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 054c211d23..27f16f7601 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -35,6 +35,99 @@ #include "scene/3d/listener.h" #include "scene/main/viewport.h" +// Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004) +// Speaker-Placement Correction Amplitude Panning (SPCAP) +class Spcap { +private: + struct Speaker { + Vector3 direction; + real_t effective_number_of_speakers; // precalculated + mutable real_t squared_gain; // temporary + }; + + PoolVector<Speaker> speakers; + +public: + Spcap(unsigned int speaker_count, const Vector3 *speaker_directions) { + this->speakers.resize(speaker_count); + PoolVector<Speaker>::Write w = this->speakers.write(); + for (unsigned int speaker_num = 0; speaker_num < speaker_count; speaker_num++) { + w[speaker_num].direction = speaker_directions[speaker_num]; + w[speaker_num].squared_gain = 0.0; + w[speaker_num].effective_number_of_speakers = 0.0; + for (unsigned int other_speaker_num = 0; other_speaker_num < speaker_count; other_speaker_num++) { + w[speaker_num].effective_number_of_speakers += 0.5 * (1.0 + w[speaker_num].direction.dot(w[other_speaker_num].direction)); + } + } + } + + unsigned int get_speaker_count() const { + return (unsigned int)this->speakers.size(); + } + + Vector3 get_speaker_direction(unsigned int index) const { + return this->speakers.read()[index].direction; + } + + void calculate(const Vector3 &source_direction, real_t tightness, unsigned int volume_count, real_t *volumes) const { + PoolVector<Speaker>::Read r = this->speakers.read(); + real_t sum_squared_gains = 0.0; + for (unsigned int speaker_num = 0; speaker_num < (unsigned int)this->speakers.size(); speaker_num++) { + real_t initial_gain = 0.5 * powf(1.0 + r[speaker_num].direction.dot(source_direction), tightness) / r[speaker_num].effective_number_of_speakers; + r[speaker_num].squared_gain = initial_gain * initial_gain; + sum_squared_gains += r[speaker_num].squared_gain; + } + + for (unsigned int speaker_num = 0; speaker_num < MIN(volume_count, (unsigned int)this->speakers.size()); speaker_num++) { + volumes[speaker_num] = sqrtf(r[speaker_num].squared_gain / sum_squared_gains); + } + } +}; + +//TODO: hardcoded main speaker directions for 2, 3.1, 5.1 and 7.1 setups - these are simplified and could also be made configurable +static const Vector3 speaker_directions[7] = { + Vector3(-1.0, 0.0, -1.0).normalized(), // front-left + Vector3(1.0, 0.0, -1.0).normalized(), // front-right + Vector3(0.0, 0.0, -1.0).normalized(), // center + Vector3(-1.0, 0.0, 1.0).normalized(), // rear-left + Vector3(1.0, 0.0, 1.0).normalized(), // rear-right + Vector3(-1.0, 0.0, 0.0).normalized(), // side-left + Vector3(1.0, 0.0, 0.0).normalized(), // side-right +}; + +void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, AudioStreamPlayer3D::Output &output) { + unsigned int speaker_count; // only main speakers (no LFE) + switch (AudioServer::get_singleton()->get_speaker_mode()) { + default: //fallthrough + case AudioServer::SPEAKER_MODE_STEREO: speaker_count = 2; break; + case AudioServer::SPEAKER_SURROUND_31: speaker_count = 3; break; + case AudioServer::SPEAKER_SURROUND_51: speaker_count = 5; break; + case AudioServer::SPEAKER_SURROUND_71: speaker_count = 7; break; + } + + Spcap spcap(speaker_count, speaker_directions); //TODO: should only be created/recreated once the speaker mode / speaker positions changes + real_t volumes[7]; + spcap.calculate(source_dir, tightness, speaker_count, volumes); + + switch (AudioServer::get_singleton()->get_speaker_mode()) { + case AudioServer::SPEAKER_SURROUND_71: + output.vol[3].l = volumes[5]; // side-left + output.vol[3].r = volumes[6]; // side-right + //fallthrough + case AudioServer::SPEAKER_SURROUND_51: + output.vol[2].l = volumes[3]; // rear-left + output.vol[2].r = volumes[4]; // rear-right + //fallthrough + case AudioServer::SPEAKER_SURROUND_31: + output.vol[1].r = 1.0; // LFE - always full power + output.vol[1].l = volumes[2]; // center + //fallthrough + case AudioServer::SPEAKER_MODE_STEREO: + output.vol[0].r = volumes[1]; // front-right + output.vol[0].l = volumes[0]; // front-left + } +} + void AudioStreamPlayer3D::_mix_audio() { if (!stream_playback.is_valid() || !active || @@ -381,59 +474,11 @@ void AudioStreamPlayer3D::_notification(int p_what) { output.filter_gain = Math::db2linear(db_att); - Vector3 flat_pos = local_pos; - flat_pos.y = 0; - flat_pos.normalize(); + //TODO: The lower the second parameter (tightness) the more the sound will "enclose" the listener (more undirected / playing from + // speakers not facing the source) - this could be made distance dependent. + _calc_output_vol(local_pos.normalized(), 4.0, output); unsigned int cc = AudioServer::get_singleton()->get_channel_count(); - if (cc == 1) { - // Stereo pair - float c = flat_pos.x * 0.5 + 0.5; - - output.vol[0].l = 1.0 - c; - output.vol[0].r = c; - } else { - Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin; - float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative - float angle = Math::rad2deg(Math::acos(c)); - float av = angle * (flat_pos.x < 0 ? -1 : 1) / 180.0; - - if (cc >= 1) { - // Stereo pair - float fl = Math::abs(1.0 - Math::abs(-0.8 - av)); - float fr = Math::abs(1.0 - Math::abs(0.8 - av)); - - output.vol[0].l = fl; - output.vol[0].r = fr; - } - - if (cc >= 2) { - // Center pair - float center = 1.0 - Math::sin(Math::acos(c)); - - output.vol[1].l = center; - output.vol[1].r = center; - } - - if (cc >= 3) { - // Side pair - float sleft = Math::abs(1.0 - Math::abs(-0.4 - av)); - float sright = Math::abs(1.0 - Math::abs(0.4 - av)); - - output.vol[2].l = sleft; - output.vol[2].r = sright; - } - - if (cc >= 4) { - // Rear pair - float rleft = Math::abs(1.0 - Math::abs(-0.2 - av)); - float rright = Math::abs(1.0 - Math::abs(0.2 - av)); - - output.vol[3].l = rleft; - output.vol[3].r = rright; - } - } - for (unsigned int k = 0; k < cc; k++) { output.vol[k] *= multiplier; } diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 93954e758a..494aa70097 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -115,6 +115,7 @@ private: bool stream_paused_fade_out; StringName bus; + static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Output &output); void _mix_audio(); static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_mix_audio(); } diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 7ab7363c7c..fc16bc36cb 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -1074,9 +1074,6 @@ void CPUParticles::_notification(int p_what) { _set_redraw(false); } - if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { - } - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { if (particles.size() == 0 || !is_visible_in_tree()) { diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 91595657b1..85ee925248 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -200,9 +200,6 @@ void Light::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { _update_visibility(); } - - if (p_what == NOTIFICATION_EXIT_TREE) { - } } void Light::set_editor_only(bool p_editor_only) { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 67c79d8b5a..2c315790ac 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -558,7 +558,7 @@ Rect2 Sprite3D::get_region_rect() const { void Sprite3D::set_frame(int p_frame) { - ERR_FAIL_INDEX(p_frame, vframes * hframes); + ERR_FAIL_INDEX(p_frame, int64_t(vframes) * hframes); if (frame != p_frame) diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 5141c84803..d1de0c56a7 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -215,17 +215,6 @@ float GeometryInstance::get_lod_max_hysteresis() const { } void GeometryInstance::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_WORLD) { - - if (flags[FLAG_USE_BAKED_LIGHT]) { - } - - } else if (p_what == NOTIFICATION_EXIT_WORLD) { - - if (flags[FLAG_USE_BAKED_LIGHT]) { - } - } } void GeometryInstance::set_flag(Flags p_flag, bool p_value) { @@ -236,8 +225,6 @@ void GeometryInstance::set_flag(Flags p_flag, bool p_value) { flags[p_flag] = p_value; VS::get_singleton()->instance_geometry_set_flag(get_instance(), (VS::InstanceFlags)p_flag, p_value); - if (p_flag == FLAG_USE_BAKED_LIGHT) { - } } bool GeometryInstance::get_flag(Flags p_flag) const { diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 52fcea2a71..4f71481280 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -115,9 +115,6 @@ void BaseButton::_notification(int p_what) { } } - if (p_what == NOTIFICATION_ENTER_TREE) { - } - if (p_what == NOTIFICATION_EXIT_TREE || (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree())) { if (!toggle_mode) { diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 4005505830..814100afdc 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2921,8 +2921,6 @@ void Tree::_notification(int p_what) { drag_touching = false; drag_touching_deaccel = false; } - - } else { } } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 06d6f0871c..caa0da5d1f 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -210,7 +210,7 @@ void Node::_propagate_enter_tree() { } data.viewport = Object::cast_to<Viewport>(this); - if (!data.viewport) + if (!data.viewport && data.parent) data.viewport = data.parent->data.viewport; data.inside_tree = true; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d147d43f50..9466b7c5c1 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -581,7 +581,7 @@ void Viewport::_notification(int p_what) { if (physics_object_capture != 0) { CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture)); - if (co) { + if (co && camera) { _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0); captured = true; if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 64051fe304..8c8552ac54 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1667,8 +1667,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a Vector2 pb = p_post_b; return a.cubic_interpolate(b, pa, pb, p_c); - - } break; + } case Variant::RECT2: { Rect2 a = p_a; @@ -1679,8 +1678,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a return Rect2( a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c), a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c)); - - } break; + } case Variant::VECTOR3: { Vector3 a = p_a; @@ -1689,8 +1687,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a Vector3 pb = p_post_b; return a.cubic_interpolate(b, pa, pb, p_c); - - } break; + } case Variant::QUAT: { Quat a = p_a; @@ -1699,8 +1696,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a Quat pb = p_post_b; return a.cubic_slerp(b, pa, pb, p_c); - - } break; + } case Variant::AABB: { AABB a = p_a; @@ -1711,14 +1707,12 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a return AABB( a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c), a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c)); - } break; + } default: { return _interpolate(p_a, p_b, p_c); } } - - return Variant(); } float Animation::_cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const { @@ -3028,7 +3022,6 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons //this could be done as a second pass and would be //able to optimize more erase = false; - } else { } } } diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py index bd5a723b23..cf0ccf1c3a 100755 --- a/scene/resources/default_theme/make_header.py +++ b/scene/resources/default_theme/make_header.py @@ -1,9 +1,14 @@ #!/usr/bin/env python import glob +import os enc = "utf-8" +# Change to the directory where the script is located, +# so that the script can be run from any location +os.chdir(os.path.dirname(os.path.realpath(__file__))) + # Generate include files f = open("theme_data.h", "wb") diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 5372a69079..44bc862198 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -2353,8 +2353,8 @@ SpatialMaterial::SpatialMaterial() : set_ao_light_affect(0.0); - set_metallic_texture_channel(TEXTURE_CHANNEL_BLUE); - set_roughness_texture_channel(TEXTURE_CHANNEL_GREEN); + set_metallic_texture_channel(TEXTURE_CHANNEL_RED); + set_roughness_texture_channel(TEXTURE_CHANNEL_RED); set_ao_texture_channel(TEXTURE_CHANNEL_RED); set_refraction_texture_channel(TEXTURE_CHANNEL_RED); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 12bf007bb1..6212066c3c 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1371,8 +1371,6 @@ String ResourceFormatSaverTextInstance::_write_resource(const RES &res) { //internal resource } } - - return "null"; } void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, bool p_main) { @@ -1514,8 +1512,6 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } } - ERR_FAIL_COND_V(err != OK, err); - { String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource "; if (packed_scene.is_null()) diff --git a/servers/physics/shape_sw.cpp b/servers/physics/shape_sw.cpp index 8a52f29729..f01caefdce 100644 --- a/servers/physics/shape_sw.cpp +++ b/servers/physics/shape_sw.cpp @@ -543,16 +543,6 @@ void CapsuleShapeSW::project_range(const Vector3 &p_normal, const Transform &p_t r_max = p_normal.dot(p_transform.xform(n)); r_min = p_normal.dot(p_transform.xform(-n)); - return; - - n = p_transform.basis.xform(n); - - real_t distance = p_normal.dot(p_transform.origin); - real_t length = Math::abs(p_normal.dot(n)); - r_min = distance - length; - r_max = distance + length; - - ERR_FAIL_COND(r_max < r_min); } Vector3 CapsuleShapeSW::get_support(const Vector3 &p_normal) const { diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index f4bff66389..9d75f71ff0 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -313,10 +313,12 @@ public: if (best_axis == Vector2(0.0, 0.0)) return; - callback->collided = true; + if (callback) { + callback->collided = true; - if (!callback->callback) - return; //only collide, no callback + if (!callback->callback) + return; //only collide, no callback + } static const int max_supports = 2; Vector2 supports_A[max_supports]; @@ -354,12 +356,13 @@ public: supports_B[i] += best_axis * margin_B; } } + if (callback) { + callback->normal = best_axis; + _generate_contacts_from_supports(supports_A, support_count_A, supports_B, support_count_B, callback); - callback->normal = best_axis; - _generate_contacts_from_supports(supports_A, support_count_A, supports_B, support_count_B, callback); - - if (callback && callback->sep_axis && *callback->sep_axis != Vector2()) - *callback->sep_axis = Vector2(); //invalidate previous axis (no test) + if (callback->sep_axis && *callback->sep_axis != Vector2()) + *callback->sep_axis = Vector2(); //invalidate previous axis (no test) + } } _FORCE_INLINE_ SeparatorAxisTest2D(const ShapeA *p_shape_A, const Transform2D &p_transform_a, const ShapeB *p_shape_B, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_A = Vector2(), const Vector2 &p_motion_B = Vector2(), real_t p_margin_A = 0, real_t p_margin_B = 0) { diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index f8ed035766..86c5227f30 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -63,7 +63,10 @@ static Transform2D _canvas_get_transform(VisualServerViewport::Viewport *p_viewp } void VisualServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { - Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + Ref<ARVRInterface> arvr_interface; + if (ARVRServer::get_singleton() != NULL) { + arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + } if (p_viewport->use_arvr && arvr_interface.is_valid()) { VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); @@ -260,11 +263,16 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E } void VisualServerViewport::draw_viewports() { + // get our arvr interface in case we need it - Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + Ref<ARVRInterface> arvr_interface; - // process all our active interfaces - ARVRServer::get_singleton()->_process(); + if (ARVRServer::get_singleton() != NULL) { + arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + + // process all our active interfaces + ARVRServer::get_singleton()->_process(); + } if (Engine::get_singleton()->is_editor_hint()) { clear_color = GLOBAL_GET("rendering/environment/default_clear_color"); diff --git a/thirdparty/README.md b/thirdparty/README.md index c6817e2389..81e30c3f6b 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -200,6 +200,7 @@ Important: Some files have Godot-made changes. They are marked with `// -- GODOT start --` and `// -- GODOT end --` comments. + ## libtheora - Upstream: https://www.theora.org @@ -262,18 +263,6 @@ changes to ensure they build for Javascript/HTML5. Those changes are marked with `// -- GODOT --` comments. -## wslay - -- Upstream: https://github.com/tatsuhiro-t/wslay -- Version: 1.1.0 -- License: MIT - -File extracted from upstream release tarball: - -- All `*.c` and `*.h` in `lib/` and `lib/includes/` -- `wslay.h` has a small Godot addition to fix MSVC build. - See `thirdparty/wslay/msvcfix.diff` - ## mbedtls - Upstream: https://tls.mbed.org/ @@ -508,6 +497,19 @@ They can be reapplied using the patches included in the `vhacd` folder. +## wslay + +- Upstream: https://github.com/tatsuhiro-t/wslay +- Version: 1.1.0 +- License: MIT + +File extracted from upstream release tarball: + +- All `*.c` and `*.h` in `lib/` and `lib/includes/` +- `wslay.h` has a small Godot addition to fix MSVC build. + See `thirdparty/wslay/msvcfix.diff` + + ## xatlas - Upstream: https://github.com/jpcy/xatlas @@ -536,7 +538,7 @@ Files extracted from upstream source: ## zstd - Upstream: https://github.com/facebook/zstd -- Version: 1.4.0 +- Version: 1.4.1 - License: BSD-3-Clause Files extracted from upstream source: diff --git a/thirdparty/zstd/common/compiler.h b/thirdparty/zstd/common/compiler.h index 0836e3ed27..87bf51ae8c 100644 --- a/thirdparty/zstd/common/compiler.h +++ b/thirdparty/zstd/common/compiler.h @@ -127,6 +127,13 @@ } \ } +/* vectorization */ +#if !defined(__clang__) && defined(__GNUC__) +# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) +#else +# define DONT_VECTORIZE +#endif + /* disable warnings */ #ifdef _MSC_VER /* Visual Studio */ # include <intrin.h> /* For Visual 2005 */ diff --git a/thirdparty/zstd/common/zstd_internal.h b/thirdparty/zstd/common/zstd_internal.h index 31f756ab58..81b16eac2e 100644 --- a/thirdparty/zstd/common/zstd_internal.h +++ b/thirdparty/zstd/common/zstd_internal.h @@ -34,7 +34,6 @@ #endif #include "xxhash.h" /* XXH_reset, update, digest */ - #if defined (__cplusplus) extern "C" { #endif @@ -193,19 +192,72 @@ static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG; * Shared functions to include for inlining *********************************************/ static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } + #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } +static void ZSTD_copy16(void* dst, const void* src) { memcpy(dst, src, 16); } +#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; } + +#define WILDCOPY_OVERLENGTH 8 +#define VECLEN 16 + +typedef enum { + ZSTD_no_overlap, + ZSTD_overlap_src_before_dst, + /* ZSTD_overlap_dst_before_src, */ +} ZSTD_overlap_e; /*! ZSTD_wildcopy() : * custom version of memcpy(), can overwrite up to WILDCOPY_OVERLENGTH bytes (if length==0) */ -#define WILDCOPY_OVERLENGTH 8 -MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length) +MEM_STATIC FORCE_INLINE_ATTR DONT_VECTORIZE +void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e ovtype) { + ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src; const BYTE* ip = (const BYTE*)src; BYTE* op = (BYTE*)dst; BYTE* const oend = op + length; - do - COPY8(op, ip) - while (op < oend); + + assert(diff >= 8 || (ovtype == ZSTD_no_overlap && diff < -8)); + if (length < VECLEN || (ovtype == ZSTD_overlap_src_before_dst && diff < VECLEN)) { + do + COPY8(op, ip) + while (op < oend); + } + else { + if ((length & 8) == 0) + COPY8(op, ip); + do { + COPY16(op, ip); + } + while (op < oend); + } +} + +/*! ZSTD_wildcopy_16min() : + * same semantics as ZSTD_wilcopy() except guaranteed to be able to copy 16 bytes at the start */ +MEM_STATIC FORCE_INLINE_ATTR DONT_VECTORIZE +void ZSTD_wildcopy_16min(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e ovtype) +{ + ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src; + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + BYTE* const oend = op + length; + + assert(length >= 8); + assert(diff >= 8 || (ovtype == ZSTD_no_overlap && diff < -8)); + + if (ovtype == ZSTD_overlap_src_before_dst && diff < VECLEN) { + do + COPY8(op, ip) + while (op < oend); + } + else { + if ((length & 8) == 0) + COPY8(op, ip); + do { + COPY16(op, ip); + } + while (op < oend); + } } MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd) /* should be faster for decoding, but strangely, not verified on all platform */ diff --git a/thirdparty/zstd/compress/zstd_compress.c b/thirdparty/zstd/compress/zstd_compress.c index 2e163c8bf3..1476512580 100644 --- a/thirdparty/zstd/compress/zstd_compress.c +++ b/thirdparty/zstd/compress/zstd_compress.c @@ -385,6 +385,11 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = ZSTD_lcm_uncompressed; return bounds; + case ZSTD_c_targetCBlockSize: + bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN; + bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX; + return bounds; + default: { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 }; return boundError; @@ -452,6 +457,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_ldmHashRateLog: case ZSTD_c_forceAttachDict: case ZSTD_c_literalCompressionMode: + case ZSTD_c_targetCBlockSize: default: return 0; } @@ -497,6 +503,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: case ZSTD_c_ldmBucketSizeLog: + case ZSTD_c_targetCBlockSize: break; default: RETURN_ERROR(parameter_unsupported); @@ -671,6 +678,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, CCtxParams->ldmParams.hashRateLog = value; return CCtxParams->ldmParams.hashRateLog; + case ZSTD_c_targetCBlockSize : + if (value!=0) /* 0 ==> default */ + BOUNDCHECK(ZSTD_c_targetCBlockSize, value); + CCtxParams->targetCBlockSize = value; + return CCtxParams->targetCBlockSize; + default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } } @@ -692,13 +705,13 @@ size_t ZSTD_CCtxParams_getParameter( *value = CCtxParams->compressionLevel; break; case ZSTD_c_windowLog : - *value = CCtxParams->cParams.windowLog; + *value = (int)CCtxParams->cParams.windowLog; break; case ZSTD_c_hashLog : - *value = CCtxParams->cParams.hashLog; + *value = (int)CCtxParams->cParams.hashLog; break; case ZSTD_c_chainLog : - *value = CCtxParams->cParams.chainLog; + *value = (int)CCtxParams->cParams.chainLog; break; case ZSTD_c_searchLog : *value = CCtxParams->cParams.searchLog; @@ -773,6 +786,9 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_ldmHashRateLog : *value = CCtxParams->ldmParams.hashRateLog; break; + case ZSTD_c_targetCBlockSize : + *value = (int)CCtxParams->targetCBlockSize; + break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } return 0; @@ -930,12 +946,12 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) @return : 0, or an error code if one value is beyond authorized range */ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) { - BOUNDCHECK(ZSTD_c_windowLog, cParams.windowLog); - BOUNDCHECK(ZSTD_c_chainLog, cParams.chainLog); - BOUNDCHECK(ZSTD_c_hashLog, cParams.hashLog); - BOUNDCHECK(ZSTD_c_searchLog, cParams.searchLog); - BOUNDCHECK(ZSTD_c_minMatch, cParams.minMatch); - BOUNDCHECK(ZSTD_c_targetLength,cParams.targetLength); + BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); + BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); + BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); + BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); + BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); + BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength); BOUNDCHECK(ZSTD_c_strategy, cParams.strategy); return 0; } @@ -951,7 +967,7 @@ ZSTD_clampCParams(ZSTD_compressionParameters cParams) if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ } -# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, int) +# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) CLAMP(ZSTD_c_windowLog, cParams.windowLog); CLAMP(ZSTD_c_chainLog, cParams.chainLog); CLAMP(ZSTD_c_hashLog, cParams.hashLog); @@ -1282,15 +1298,14 @@ static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) } /*! ZSTD_invalidateMatchState() - * Invalidate all the matches in the match finder tables. - * Requires nextSrc and base to be set (can be NULL). + * Invalidate all the matches in the match finder tables. + * Requires nextSrc and base to be set (can be NULL). */ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) { ZSTD_window_clear(&ms->window); ms->nextToUpdate = ms->window.dictLimit; - ms->nextToUpdate3 = ms->window.dictLimit; ms->loadedDictEnd = 0; ms->opt.litLengthSum = 0; /* force reset of btopt stats */ ms->dictMatchState = NULL; @@ -1327,15 +1342,17 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; +typedef enum { ZSTD_resetTarget_CDict, ZSTD_resetTarget_CCtx } ZSTD_resetTarget_e; + static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, const ZSTD_compressionParameters* cParams, - ZSTD_compResetPolicy_e const crp, U32 const forCCtx) + ZSTD_compResetPolicy_e const crp, ZSTD_resetTarget_e const forWho) { size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); size_t const hSize = ((size_t)1) << cParams->hashLog; - U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; + U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = ((size_t)1) << hashLog3; size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); @@ -1349,7 +1366,7 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_invalidateMatchState(ms); /* opt parser space */ - if (forCCtx && (cParams->strategy >= ZSTD_btopt)) { + if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { DEBUGLOG(4, "reserving optimal parser space"); ms->opt.litFreq = (unsigned*)ptr; ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits); @@ -1377,6 +1394,19 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, return ptr; } +/* ZSTD_indexTooCloseToMax() : + * minor optimization : prefer memset() rather than reduceIndex() + * which is measurably slow in some circumstances (reported for Visual Studio). + * Works when re-using a context for a lot of smallish inputs : + * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN, + * memset() will be triggered before reduceIndex(). + */ +#define ZSTD_INDEXOVERFLOW_MARGIN (16 MB) +static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) +{ + return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); +} + #define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */ #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large * during at least this number of times, @@ -1388,7 +1418,7 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, note : `params` are assumed fully validated at this stage */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, ZSTD_CCtx_params params, - U64 pledgedSrcSize, + U64 const pledgedSrcSize, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { @@ -1400,13 +1430,21 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, if (ZSTD_equivalentParams(zc->appliedParams, params, zc->inBuffSize, zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit, - zbuff, pledgedSrcSize)) { - DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)", - zc->appliedParams.cParams.windowLog, zc->blockSize); + zbuff, pledgedSrcSize) ) { + DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> consider continue mode"); zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */ - if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION) + if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION) { + DEBUGLOG(4, "continue mode confirmed (wLog1=%u, blockSize1=%zu)", + zc->appliedParams.cParams.windowLog, zc->blockSize); + if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { + /* prefer a reset, faster than a rescale */ + ZSTD_reset_matchState(&zc->blockState.matchState, + zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32, + ¶ms.cParams, + crp, ZSTD_resetTarget_CCtx); + } return ZSTD_continueCCtx(zc, params, pledgedSrcSize); - } } + } } } DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx"); if (params.ldmParams.enableLdm) { @@ -1449,7 +1487,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); if (workSpaceTooSmall || workSpaceWasteful) { - DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB", + DEBUGLOG(4, "Resize workSpaceSize from %zuKB to %zuKB", zc->workSpaceSize >> 10, neededSpace >> 10); @@ -1491,7 +1529,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); - ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32; + ptr = ZSTD_reset_matchState(&zc->blockState.matchState, + zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32, + ¶ms.cParams, + crp, ZSTD_resetTarget_CCtx); /* ldm hash table */ /* initialize bucketOffsets table later for pointer alignment */ @@ -1509,8 +1550,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, } assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ - ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* forCCtx */ 1); - /* sequences storage */ zc->seqStore.maxNbSeq = maxNbSeq; zc->seqStore.sequencesStart = (seqDef*)ptr; @@ -1587,15 +1626,14 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, * handled in _enforceMaxDist */ } -static size_t ZSTD_resetCCtx_byAttachingCDict( - ZSTD_CCtx* cctx, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, - U64 pledgedSrcSize, - ZSTD_buffered_policy_e zbuff) +static size_t +ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, + U64 pledgedSrcSize, + ZSTD_buffered_policy_e zbuff) { - { - const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; + { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Resize working context table params for input only, since the dict @@ -1607,8 +1645,7 @@ static size_t ZSTD_resetCCtx_byAttachingCDict( assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); } - { - const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc + { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc - cdict->matchState.window.base); const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; if (cdictLen == 0) { @@ -1625,9 +1662,9 @@ static size_t ZSTD_resetCCtx_byAttachingCDict( cctx->blockState.matchState.window.base + cdictEnd; ZSTD_window_clear(&cctx->blockState.matchState.window); } + /* loadedDictEnd is expressed within the referential of the active context */ cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; - } - } + } } cctx->dictID = cdict->dictID; @@ -1681,7 +1718,6 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; dstMatchState->window = srcMatchState->window; dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; - dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; } @@ -1761,7 +1797,6 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; dstMatchState->window = srcMatchState->window; dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; - dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; } dstCCtx->dictID = srcCCtx->dictID; @@ -1831,16 +1866,15 @@ static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const /*! ZSTD_reduceIndex() : * rescale all indexes to avoid future overflow (indexes are U32) */ -static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) +static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue) { - ZSTD_matchState_t* const ms = &zc->blockState.matchState; - { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog; + { U32 const hSize = (U32)1 << params->cParams.hashLog; ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); } - if (zc->appliedParams.cParams.strategy != ZSTD_fast) { - U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog; - if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2) + if (params->cParams.strategy != ZSTD_fast) { + U32 const chainSize = (U32)1 << params->cParams.chainLog; + if (params->cParams.strategy == ZSTD_btlazy2) ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); else ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); @@ -2524,6 +2558,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; + assert(op <= oend); if (nbSeq==0) { /* Copy the old tables over as if we repeated them */ memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); @@ -2532,6 +2567,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, /* seqHead : flags for FSE encoding type */ seqHead = op++; + assert(op <= oend); /* convert length/distances into codes */ ZSTD_seqToCodes(seqStorePtr); @@ -2555,6 +2591,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, if (LLtype == set_compressed) lastNCount = op; op += countSize; + assert(op <= oend); } } /* build CTable for Offsets */ { unsigned max = MaxOff; @@ -2577,6 +2614,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, if (Offtype == set_compressed) lastNCount = op; op += countSize; + assert(op <= oend); } } /* build CTable for MatchLengths */ { unsigned max = MaxML; @@ -2597,6 +2635,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, if (MLtype == set_compressed) lastNCount = op; op += countSize; + assert(op <= oend); } } *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); @@ -2610,6 +2649,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, longOffsets, bmi2); FORWARD_IF_ERROR(bitstreamSize); op += bitstreamSize; + assert(op <= oend); /* zstd versions <= 1.3.4 mistakenly report corruption when * FSE_readNCount() receives a buffer < 4 bytes. * Fixed by https://github.com/facebook/zstd/pull/1146. @@ -2721,30 +2761,24 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->longLengthID = 0; } -static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; + +static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) { ZSTD_matchState_t* const ms = &zc->blockState.matchState; - size_t cSize; - DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", - (unsigned)dstCapacity, (unsigned)ms->window.dictLimit, (unsigned)ms->nextToUpdate); + DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize); assert(srcSize <= ZSTD_BLOCKSIZE_MAX); - /* Assert that we have correctly flushed the ctx params into the ms's copy */ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); - if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); - cSize = 0; - goto out; /* don't even attempt compression below a certain srcSize */ + return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ } ZSTD_resetSeqStore(&(zc->seqStore)); /* required for optimal parser to read stats from dictionary */ ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; /* tell the optimal parser how we expect to compress literals */ ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode; - /* a gap between an attached dict and the current window is not safe, * they must remain adjacent, * and when that stops being the case, the dict must be unset */ @@ -2798,6 +2832,21 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); } } + return ZSTDbss_compress; +} + +static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + size_t cSize; + DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate); + + { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + FORWARD_IF_ERROR(bss); + if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } + } /* encode sequences and literals */ cSize = ZSTD_compressSequences(&zc->seqStore, @@ -2826,6 +2875,25 @@ out: } +static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, void const* ip, void const* iend) +{ + if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { + U32 const maxDist = (U32)1 << params->cParams.windowLog; + U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); + U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); + ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); + ZSTD_reduceIndex(ms, params, correction); + if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; + else ms->nextToUpdate -= correction; + /* invalidate dictionaries on overflow correction */ + ms->loadedDictEnd = 0; + ms->dictMatchState = NULL; + } +} + + /*! ZSTD_compress_frameChunk() : * Compress a chunk of data into one or multiple blocks. * All blocks will be terminated, all input will be consumed. @@ -2844,7 +2912,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; - assert(cctx->appliedParams.cParams.windowLog <= 31); + assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); if (cctx->appliedParams.fParams.checksumFlag && srcSize) @@ -2859,19 +2927,10 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, "not enough space to store compressed block"); if (remaining < blockSize) blockSize = remaining; - if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) { - U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); - U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); - ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); - ZSTD_reduceIndex(cctx, correction); - if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; - else ms->nextToUpdate -= correction; - ms->loadedDictEnd = 0; - ms->dictMatchState = NULL; - } - ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); + ZSTD_overflowCorrectIfNeeded(ms, &cctx->appliedParams, ip, ip + blockSize); + ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); + + /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; { size_t cSize = ZSTD_compressBlock_internal(cctx, @@ -2899,7 +2958,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, } } if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; - return op-ostart; + return (size_t)(op-ostart); } @@ -2991,6 +3050,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, cctx->pledgedSrcSizePlusOne-1, cctx->dictID); FORWARD_IF_ERROR(fhSize); + assert(fhSize <= dstCapacity); dstCapacity -= fhSize; dst = (char*)dst + fhSize; cctx->stage = ZSTDcs_ongoing; @@ -3007,18 +3067,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (!frame) { /* overflow check and correction for block mode */ - if (ZSTD_window_needOverflowCorrection(ms->window, (const char*)src + srcSize)) { - U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); - U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, 1 << cctx->appliedParams.cParams.windowLog, src); - ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); - ZSTD_reduceIndex(cctx, correction); - if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; - else ms->nextToUpdate -= correction; - ms->loadedDictEnd = 0; - ms->dictMatchState = NULL; - } + ZSTD_overflowCorrectIfNeeded(ms, &cctx->appliedParams, src, (BYTE const*)src + srcSize); } DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize); @@ -3074,7 +3123,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, const void* src, size_t srcSize, ZSTD_dictTableLoadMethod_e dtlm) { - const BYTE* const ip = (const BYTE*) src; + const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; ZSTD_window_update(&ms->window, src, srcSize); @@ -3085,32 +3134,42 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, if (srcSize <= HASH_READ_SIZE) return 0; - switch(params->cParams.strategy) - { - case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, dtlm); - break; - case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, iend, dtlm); - break; + while (iend - ip > HASH_READ_SIZE) { + size_t const remaining = iend - ip; + size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); + const BYTE* const ichunk = ip + chunk; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - if (srcSize >= HASH_READ_SIZE) - ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); - break; + ZSTD_overflowCorrectIfNeeded(ms, params, ip, ichunk); - case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - if (srcSize >= HASH_READ_SIZE) - ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); - break; + switch(params->cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(ms, ichunk, dtlm); + break; + case ZSTD_dfast: + ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); + break; - default: - assert(0); /* not possible : not a valid strategy id */ + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + if (chunk >= HASH_READ_SIZE) + ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); + break; + + case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + if (chunk >= HASH_READ_SIZE) + ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); + break; + + default: + assert(0); /* not possible : not a valid strategy id */ + } + + ip = ichunk; } ms->nextToUpdate = (U32)(iend - ms->window.base); @@ -3297,12 +3356,11 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, ZSTDcrp_continue, zbuff) ); - { - size_t const dictID = ZSTD_compress_insertDictionary( + { size_t const dictID = ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, ¶ms, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace); FORWARD_IF_ERROR(dictID); - assert(dictID <= (size_t)(U32)-1); + assert(dictID <= UINT_MAX); cctx->dictID = (U32)dictID; } return 0; @@ -3555,10 +3613,10 @@ static size_t ZSTD_initCDict_internal( /* Reset the state to no dictionary */ ZSTD_reset_compressedBlockState(&cdict->cBlockState); - { void* const end = ZSTD_reset_matchState( - &cdict->matchState, - (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32, - &cParams, ZSTDcrp_continue, /* forCCtx */ 0); + { void* const end = ZSTD_reset_matchState(&cdict->matchState, + (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32, + &cParams, + ZSTDcrp_continue, ZSTD_resetTarget_CDict); assert(end == (char*)cdict->workspace + cdict->workspaceSize); (void)end; } @@ -4068,7 +4126,7 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, case zcss_flush: DEBUGLOG(5, "flush stage"); { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; - size_t const flushed = ZSTD_limitCopy(op, oend-op, + size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), zcs->outBuff + zcs->outBuffFlushedSize, toFlush); DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); @@ -4262,7 +4320,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ /* single thread mode : attempt to calculate remaining to flush more precisely */ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; - size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4; + size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4); size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize; DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush); return toFlush; diff --git a/thirdparty/zstd/compress/zstd_compress_internal.h b/thirdparty/zstd/compress/zstd_compress_internal.h index cc3cbb9da9..5495899be3 100644 --- a/thirdparty/zstd/compress/zstd_compress_internal.h +++ b/thirdparty/zstd/compress/zstd_compress_internal.h @@ -33,13 +33,13 @@ extern "C" { ***************************************/ #define kSearchStrength 8 #define HASH_READ_SIZE 8 -#define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index 1 now means "unsorted". +#define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index ZSTD_DUBT_UNSORTED_MARK==1 means "unsorted". It could be confused for a real successor at index "1", if sorted as larger than its predecessor. It's not a big deal though : candidate will just be sorted again. Additionally, candidate position 1 will be lost. But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss. - The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy - Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */ + The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy. + This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */ /*-************************************* @@ -128,21 +128,20 @@ typedef struct { BYTE const* base; /* All regular indexes relative to this position */ BYTE const* dictBase; /* extDict indexes relative to this position */ U32 dictLimit; /* below that point, need extDict */ - U32 lowLimit; /* below that point, no more data */ + U32 lowLimit; /* below that point, no more valid data */ } ZSTD_window_t; typedef struct ZSTD_matchState_t ZSTD_matchState_t; struct ZSTD_matchState_t { ZSTD_window_t window; /* State for window round buffer management */ - U32 loadedDictEnd; /* index of end of dictionary */ + U32 loadedDictEnd; /* index of end of dictionary, within context's referential. When dict referential is copied into active context (i.e. not attached), effectively same value as dictSize, since referential starts from zero */ U32 nextToUpdate; /* index from which to continue table update */ - U32 nextToUpdate3; /* index from which to continue table update */ U32 hashLog3; /* dispatch table : larger == faster, more memory */ U32* hashTable; U32* hashTable3; U32* chainTable; optState_t opt; /* optimal parser state */ - const ZSTD_matchState_t * dictMatchState; + const ZSTD_matchState_t* dictMatchState; ZSTD_compressionParameters cParams; }; @@ -195,6 +194,9 @@ struct ZSTD_CCtx_params_s { int compressionLevel; int forceWindow; /* force back-references to respect limit of * 1<<wLog, even for dictionary */ + size_t targetCBlockSize; /* Tries to fit compressed block size to be around targetCBlockSize. + * No target when targetCBlockSize == 0. + * There is no guarantee on compressed block size */ ZSTD_dictAttachPref_e attachDictPref; ZSTD_literalCompressionMode_e literalCompressionMode; @@ -324,7 +326,7 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v /* copy Literals */ assert(seqStorePtr->maxNbLit <= 128 KB); assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit); - ZSTD_wildcopy(seqStorePtr->lit, literals, litLength); + ZSTD_wildcopy(seqStorePtr->lit, literals, litLength, ZSTD_no_overlap); seqStorePtr->lit += litLength; /* literal Length */ @@ -564,6 +566,9 @@ MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64 /*-************************************* * Round buffer management ***************************************/ +#if (ZSTD_WINDOWLOG_MAX_64 > 31) +# error "ZSTD_WINDOWLOG_MAX is too large : would overflow ZSTD_CURRENT_MAX" +#endif /* Max current allowed */ #define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX)) /* Maximum chunk size before overflow correction needs to be called again */ @@ -675,31 +680,49 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, * Updates lowLimit so that: * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd * - * This allows a simple check that index >= lowLimit to see if index is valid. - * This must be called before a block compression call, with srcEnd as the block - * source end. + * It ensures index is valid as long as index >= lowLimit. + * This must be called before a block compression call. + * + * loadedDictEnd is only defined if a dictionary is in use for current compression. + * As the name implies, loadedDictEnd represents the index at end of dictionary. + * The value lies within context's referential, it can be directly compared to blockEndIdx. * - * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit. - * This is because dictionaries are allowed to be referenced as long as the last - * byte of the dictionary is in the window, but once they are out of range, - * they cannot be referenced. If loadedDictEndPtr is NULL, we use - * loadedDictEnd == 0. + * If loadedDictEndPtr is NULL, no dictionary is in use, and we use loadedDictEnd == 0. + * If loadedDictEndPtr is not NULL, we set it to zero after updating lowLimit. + * This is because dictionaries are allowed to be referenced fully + * as long as the last byte of the dictionary is in the window. + * Once input has progressed beyond window size, dictionary cannot be referenced anymore. * - * In normal dict mode, the dict is between lowLimit and dictLimit. In - * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary - * is below them. forceWindow and dictMatchState are therefore incompatible. + * In normal dict mode, the dictionary lies between lowLimit and dictLimit. + * In dictMatchState mode, lowLimit and dictLimit are the same, + * and the dictionary is below them. + * forceWindow and dictMatchState are therefore incompatible. */ MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t* window, - void const* srcEnd, - U32 maxDist, - U32* loadedDictEndPtr, + const void* blockEnd, + U32 maxDist, + U32* loadedDictEndPtr, const ZSTD_matchState_t** dictMatchStatePtr) { - U32 const blockEndIdx = (U32)((BYTE const*)srcEnd - window->base); - U32 loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0; - DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u", - (unsigned)blockEndIdx, (unsigned)maxDist); + U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base); + U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0; + DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u", + (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd); + + /* - When there is no dictionary : loadedDictEnd == 0. + In which case, the test (blockEndIdx > maxDist) is merely to avoid + overflowing next operation `newLowLimit = blockEndIdx - maxDist`. + - When there is a standard dictionary : + Index referential is copied from the dictionary, + which means it starts from 0. + In which case, loadedDictEnd == dictSize, + and it makes sense to compare `blockEndIdx > maxDist + dictSize` + since `blockEndIdx` also starts from zero. + - When there is an attached dictionary : + loadedDictEnd is expressed within the referential of the context, + so it can be directly compared against blockEndIdx. + */ if (blockEndIdx > maxDist + loadedDictEnd) { U32 const newLowLimit = blockEndIdx - maxDist; if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit; @@ -708,10 +731,31 @@ ZSTD_window_enforceMaxDist(ZSTD_window_t* window, (unsigned)window->dictLimit, (unsigned)window->lowLimit); window->dictLimit = window->lowLimit; } - if (loadedDictEndPtr) - *loadedDictEndPtr = 0; - if (dictMatchStatePtr) - *dictMatchStatePtr = NULL; + /* On reaching window size, dictionaries are invalidated */ + if (loadedDictEndPtr) *loadedDictEndPtr = 0; + if (dictMatchStatePtr) *dictMatchStatePtr = NULL; + } +} + +/* Similar to ZSTD_window_enforceMaxDist(), + * but only invalidates dictionary + * when input progresses beyond window size. */ +MEM_STATIC void +ZSTD_checkDictValidity(ZSTD_window_t* window, + const void* blockEnd, + U32 maxDist, + U32* loadedDictEndPtr, + const ZSTD_matchState_t** dictMatchStatePtr) +{ + U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base); + U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0; + DEBUGLOG(5, "ZSTD_checkDictValidity: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u", + (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd); + + if (loadedDictEnd && (blockEndIdx > maxDist + loadedDictEnd)) { + /* On reaching window size, dictionaries are invalidated */ + if (loadedDictEndPtr) *loadedDictEndPtr = 0; + if (dictMatchStatePtr) *dictMatchStatePtr = NULL; } } diff --git a/thirdparty/zstd/compress/zstd_double_fast.c b/thirdparty/zstd/compress/zstd_double_fast.c index 47faf6d641..5957255d90 100644 --- a/thirdparty/zstd/compress/zstd_double_fast.c +++ b/thirdparty/zstd/compress/zstd_double_fast.c @@ -43,8 +43,7 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, /* Only load extra positions for ZSTD_dtlm_full */ if (dtlm == ZSTD_dtlm_fast) break; - } - } + } } } @@ -63,7 +62,10 @@ size_t ZSTD_compressBlock_doubleFast_generic( const BYTE* const istart = (const BYTE*)src; const BYTE* ip = istart; const BYTE* anchor = istart; - const U32 prefixLowestIndex = ms->window.dictLimit; + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 lowestValid = ms->window.dictLimit; + const U32 maxDistance = 1U << cParams->windowLog; + const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid; const BYTE* const prefixLowest = base + prefixLowestIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; @@ -95,8 +97,15 @@ size_t ZSTD_compressBlock_doubleFast_generic( dictCParams->chainLog : hBitsS; const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart); + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic"); + assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); + /* if a dictionary is attached, it must be within window range */ + if (dictMode == ZSTD_dictMatchState) { + assert(lowestValid + maxDistance >= endIndex); + } + /* init */ ip += (dictAndPrefixLength == 0); if (dictMode == ZSTD_noDict) { @@ -138,7 +147,7 @@ size_t ZSTD_compressBlock_doubleFast_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; ip++; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); goto _match_stored; } @@ -147,7 +156,7 @@ size_t ZSTD_compressBlock_doubleFast_generic( && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; ip++; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); goto _match_stored; } @@ -170,8 +179,7 @@ size_t ZSTD_compressBlock_doubleFast_generic( offset = (U32)(current - dictMatchIndexL - dictIndexDelta); while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */ goto _match_found; - } - } + } } if (matchIndexS > prefixLowestIndex) { /* check prefix short match */ @@ -186,16 +194,14 @@ size_t ZSTD_compressBlock_doubleFast_generic( if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) { goto _search_next_long; - } - } + } } ip += ((ip-anchor) >> kSearchStrength) + 1; continue; _search_next_long: - { - size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); + { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8); U32 const matchIndexL3 = hashLong[hl3]; const BYTE* matchL3 = base + matchIndexL3; @@ -221,9 +227,7 @@ _search_next_long: offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta); while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */ goto _match_found; - } - } - } + } } } /* if no long +1 match, explore the short match we found */ if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) { @@ -242,7 +246,7 @@ _match_found: offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); _match_stored: /* match found */ @@ -250,11 +254,14 @@ _match_stored: anchor = ip; if (ip <= ilimit) { - /* Fill Table */ - hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = - hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */ - hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = - hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base); + /* Complementary insertion */ + /* done after iLimit test, as candidates could be > iend-8 */ + { U32 const indexToInsert = current+2; + hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; + hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); + hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; + hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base); + } /* check immediate repcode */ if (dictMode == ZSTD_dictMatchState) { @@ -278,8 +285,7 @@ _match_stored: continue; } break; - } - } + } } if (dictMode == ZSTD_noDict) { while ( (ip <= ilimit) @@ -294,14 +300,15 @@ _match_stored: ip += rLength; anchor = ip; continue; /* faster when present ... (?) */ - } } } } + } } } + } /* while (ip < ilimit) */ /* save reps for next block */ rep[0] = offset_1 ? offset_1 : offsetSaved; rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ - return iend - anchor; + return (size_t)(iend - anchor); } @@ -360,10 +367,15 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; - const U32 prefixStartIndex = ms->window.dictLimit; const BYTE* const base = ms->window.base; + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 lowestValid = ms->window.lowLimit; + const U32 lowLimit = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid; + const U32 dictStartIndex = lowLimit; + const U32 dictLimit = ms->window.dictLimit; + const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit; const BYTE* const prefixStart = base + prefixStartIndex; - const U32 dictStartIndex = ms->window.lowLimit; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const dictStart = dictBase + dictStartIndex; const BYTE* const dictEnd = dictBase + prefixStartIndex; @@ -371,6 +383,10 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize); + /* if extDict is invalidated due to maxDistance, switch to "regular" variant */ + if (prefixStartIndex == dictStartIndex) + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict); + /* Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls); @@ -396,7 +412,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); } else { if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend; @@ -407,7 +423,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) { size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); @@ -432,23 +448,27 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( } offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } else { ip += ((ip-anchor) >> kSearchStrength) + 1; continue; } } - /* found a match : store it */ + /* move to next sequence start */ ip += mLength; anchor = ip; if (ip <= ilimit) { - /* Fill Table */ - hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; - hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2; - hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base); - hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); + /* Complementary insertion */ + /* done after iLimit test, as candidates could be > iend-8 */ + { U32 const indexToInsert = current+2; + hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; + hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); + hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; + hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base); + } + /* check immediate repcode */ while (ip <= ilimit) { U32 const current2 = (U32)(ip-base); @@ -475,7 +495,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( rep[1] = offset_2; /* Return the last literals size */ - return iend - anchor; + return (size_t)(iend - anchor); } diff --git a/thirdparty/zstd/compress/zstd_fast.c b/thirdparty/zstd/compress/zstd_fast.c index ed997b441c..a05b8a47f1 100644 --- a/thirdparty/zstd/compress/zstd_fast.c +++ b/thirdparty/zstd/compress/zstd_fast.c @@ -13,7 +13,8 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm) + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; @@ -41,6 +42,7 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms, } } } } } + FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_fast_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -58,7 +60,10 @@ size_t ZSTD_compressBlock_fast_generic( const BYTE* ip0 = istart; const BYTE* ip1; const BYTE* anchor = istart; - const U32 prefixStartIndex = ms->window.dictLimit; + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 validStartIndex = ms->window.dictLimit; + const U32 prefixStartIndex = (endIndex - validStartIndex > maxDistance) ? endIndex - maxDistance : validStartIndex; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; @@ -165,7 +170,7 @@ _match: /* Requires: ip0, match0, offcode */ rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ - return iend - anchor; + return (size_t)(iend - anchor); } @@ -222,8 +227,15 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); const U32 dictHLog = dictCParams->hashLog; - /* otherwise, we would get index underflow when translating a dict index - * into a local index */ + /* if a dictionary is still attached, it necessarily means that + * it is within window size. So we just check it. */ + const U32 maxDistance = 1U << cParams->windowLog; + const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); + assert(endIndex - prefixStartIndex <= maxDistance); + (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ + + /* ensure there will be no no underflow + * when translating a dict index into a local index */ assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); /* init */ @@ -251,7 +263,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); } else if ( (matchIndex <= prefixStartIndex) ) { size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); U32 const dictMatchIndex = dictHashTable[dictHash]; @@ -271,7 +283,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } } else if (MEM_read32(match) != MEM_read32(ip)) { /* it's not a match, and we're not going to check the dictionary */ @@ -286,7 +298,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } /* match found */ @@ -327,7 +339,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ - return iend - anchor; + return (size_t)(iend - anchor); } size_t ZSTD_compressBlock_fast_dictMatchState( @@ -366,15 +378,24 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* const istart = (const BYTE*)src; const BYTE* ip = istart; const BYTE* anchor = istart; - const U32 dictStartIndex = ms->window.lowLimit; + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 validLow = ms->window.lowLimit; + const U32 lowLimit = (endIndex - validLow > maxDistance) ? endIndex - maxDistance : validLow; + const U32 dictStartIndex = lowLimit; const BYTE* const dictStart = dictBase + dictStartIndex; - const U32 prefixStartIndex = ms->window.dictLimit; + const U32 dictLimit = ms->window.dictLimit; + const U32 prefixStartIndex = dictLimit < lowLimit ? lowLimit : dictLimit; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const dictEnd = dictBase + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; U32 offset_1=rep[0], offset_2=rep[1]; + /* switch to "regular" variant if extDict is invalidated due to maxDistance */ + if (prefixStartIndex == dictStartIndex) + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls); + /* Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ const size_t h = ZSTD_hashPtr(ip, hlog, mls); @@ -394,7 +415,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); } else { if ( (matchIndex < dictStartIndex) || (MEM_read32(match) != MEM_read32(ip)) ) { @@ -410,7 +431,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( offset = current - matchIndex; offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } } /* found a match : store it */ @@ -445,7 +466,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( rep[1] = offset_2; /* Return the last literals size */ - return iend - anchor; + return (size_t)(iend - anchor); } diff --git a/thirdparty/zstd/compress/zstd_lazy.c b/thirdparty/zstd/compress/zstd_lazy.c index 53f998a437..94d906c01f 100644 --- a/thirdparty/zstd/compress/zstd_lazy.c +++ b/thirdparty/zstd/compress/zstd_lazy.c @@ -83,7 +83,10 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, U32* largerPtr = smallerPtr + 1; U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */ U32 dummy32; /* to be nullified at the end */ - U32 const windowLow = ms->window.lowLimit; + U32 const windowValid = ms->window.lowLimit; + U32 const maxDistance = 1U << cParams->windowLog; + U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid; + DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)", current, dictLimit, windowLow); @@ -239,7 +242,9 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const BYTE* const base = ms->window.base; U32 const current = (U32)(ip-base); - U32 const windowLow = ms->window.lowLimit; + U32 const maxDistance = 1U << cParams->windowLog; + U32 const windowValid = ms->window.lowLimit; + U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid; U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; @@ -490,8 +495,10 @@ size_t ZSTD_HcFindBestMatch_generic ( const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; - const U32 lowLimit = ms->window.lowLimit; const U32 current = (U32)(ip-base); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 lowValid = ms->window.lowLimit; + const U32 lowLimit = (current - lowValid > maxDistance) ? current - maxDistance : lowValid; const U32 minChain = current > chainSize ? current - chainSize : 0; U32 nbAttempts = 1U << cParams->searchLog; size_t ml=4-1; @@ -653,7 +660,6 @@ size_t ZSTD_compressBlock_lazy_generic( /* init */ ip += (dictAndPrefixLength == 0); - ms->nextToUpdate3 = ms->nextToUpdate; if (dictMode == ZSTD_noDict) { U32 const maxRep = (U32)(ip - prefixLowest); if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; @@ -933,7 +939,6 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( U32 offset_1 = rep[0], offset_2 = rep[1]; /* init */ - ms->nextToUpdate3 = ms->nextToUpdate; ip += (ip == prefixStart); /* Match Loop */ diff --git a/thirdparty/zstd/compress/zstd_ldm.c b/thirdparty/zstd/compress/zstd_ldm.c index 784d20f3ab..3dcf86e6e8 100644 --- a/thirdparty/zstd/compress/zstd_ldm.c +++ b/thirdparty/zstd/compress/zstd_ldm.c @@ -447,7 +447,7 @@ size_t ZSTD_ldm_generateSequences( if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) { U32 const ldmHSize = 1U << params->hashLog; U32 const correction = ZSTD_window_correctOverflow( - &ldmState->window, /* cycleLog */ 0, maxDist, src); + &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart); ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction); } /* 2. We enforce the maximum offset allowed. diff --git a/thirdparty/zstd/compress/zstd_opt.c b/thirdparty/zstd/compress/zstd_opt.c index efb69d3267..e32e542e02 100644 --- a/thirdparty/zstd/compress/zstd_opt.c +++ b/thirdparty/zstd/compress/zstd_opt.c @@ -255,13 +255,13 @@ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optP * to provide a cost which is directly comparable to a match ending at same position */ static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel) { - if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel); + if (optPtr->priceType >= zop_predef) return (int)WEIGHT(litLength, optLevel); /* dynamic statistics */ { U32 const llCode = ZSTD_LLcode(litLength); - int const contribution = (LL_bits[llCode] * BITCOST_MULTIPLIER) - + WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */ - - WEIGHT(optPtr->litLengthFreq[llCode], optLevel); + int const contribution = (int)(LL_bits[llCode] * BITCOST_MULTIPLIER) + + (int)WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */ + - (int)WEIGHT(optPtr->litLengthFreq[llCode], optLevel); #if 1 return contribution; #else @@ -278,7 +278,7 @@ static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLe const optState_t* const optPtr, int optLevel) { - int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel) + int const contribution = (int)ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel) + ZSTD_litLengthContribution(litLength, optPtr, optLevel); return contribution; } @@ -372,13 +372,15 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) /* Update hashTable3 up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip) +static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip) { U32* const hashTable3 = ms->hashTable3; U32 const hashLog3 = ms->hashLog3; const BYTE* const base = ms->window.base; - U32 idx = ms->nextToUpdate3; - U32 const target = ms->nextToUpdate3 = (U32)(ip - base); + U32 idx = *nextToUpdate3; + U32 const target = (U32)(ip - base); size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3); assert(hashLog3 > 0); @@ -387,6 +389,7 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* idx++; } + *nextToUpdate3 = target; return hashTable3[hash3]; } @@ -503,9 +506,11 @@ static U32 ZSTD_insertBt1( } } *smallerPtr = *largerPtr = 0; - if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */ - assert(matchEndIdx > current + 8); - return matchEndIdx - (current + 8); + { U32 positions = 0; + if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */ + assert(matchEndIdx > current + 8); + return MAX(positions, matchEndIdx - (current + 8)); + } } FORCE_INLINE_TEMPLATE @@ -520,8 +525,13 @@ void ZSTD_updateTree_internal( DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)", idx, target, dictMode); - while(idx < target) - idx += ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); + while(idx < target) { + U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); + assert(idx < (U32)(idx + forward)); + idx += forward; + } + assert((size_t)(ip - base) <= (size_t)(U32)(-1)); + assert((size_t)(iend - base) <= (size_t)(U32)(-1)); ms->nextToUpdate = target; } @@ -531,16 +541,18 @@ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) { FORCE_INLINE_TEMPLATE U32 ZSTD_insertBtAndGetAllMatches ( + ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ ZSTD_matchState_t* ms, + U32* nextToUpdate3, const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode, - U32 rep[ZSTD_REP_NUM], + const U32 rep[ZSTD_REP_NUM], U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ - ZSTD_match_t* matches, const U32 lengthToBeat, U32 const mls /* template */) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); + U32 const maxDistance = 1U << cParams->windowLog; const BYTE* const base = ms->window.base; U32 const current = (U32)(ip-base); U32 const hashLog = cParams->hashLog; @@ -556,8 +568,9 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 const dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32 const btLow = btMask >= current ? 0 : current - btMask; - U32 const windowLow = ms->window.lowLimit; + U32 const btLow = (btMask >= current) ? 0 : current - btMask; + U32 const windowValid = ms->window.lowLimit; + U32 const windowLow = ((current - windowValid) > maxDistance) ? current - maxDistance : windowValid; U32 const matchLow = windowLow ? windowLow : 1; U32* smallerPtr = bt + 2*(current&btMask); U32* largerPtr = bt + 2*(current&btMask) + 1; @@ -627,7 +640,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( /* HC3 match finder */ if ((mls == 3) /*static*/ && (bestLength < mls)) { - U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip); + U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip); if ((matchIndex3 >= matchLow) & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { size_t mlen; @@ -653,9 +666,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( (ip+mlen == iLimit) ) { /* best possible length */ ms->nextToUpdate = current+1; /* skip insertion */ return 1; - } - } - } + } } } /* no dictMatchState lookup: dicts don't have a populated HC3 table */ } @@ -760,10 +771,13 @@ U32 ZSTD_insertBtAndGetAllMatches ( FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( + ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */ ZSTD_matchState_t* ms, + U32* nextToUpdate3, const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode, - U32 rep[ZSTD_REP_NUM], U32 const ll0, - ZSTD_match_t* matches, U32 const lengthToBeat) + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const matchLengthSearch = cParams->minMatch; @@ -772,12 +786,12 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode); switch(matchLengthSearch) { - case 3 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3); + case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3); default : - case 4 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 4); - case 5 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 5); + case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4); + case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5); case 7 : - case 6 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 6); + case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6); } } @@ -853,6 +867,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4; + U32 nextToUpdate3 = ms->nextToUpdate; ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_match_t* const matches = optStatePtr->matchTable; @@ -862,7 +877,6 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u", (U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate); assert(optLevel <= 2); - ms->nextToUpdate3 = ms->nextToUpdate; ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel); ip += (ip==prefixStart); @@ -873,7 +887,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* find first match */ { U32 const litlen = (U32)(ip - anchor); U32 const ll0 = !litlen; - U32 const nbMatches = ZSTD_BtGetAllMatches(ms, ip, iend, dictMode, rep, ll0, matches, minMatch); + U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch); if (!nbMatches) { ip++; continue; } /* initialize opt[0] */ @@ -970,7 +984,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; U32 const previousPrice = opt[cur].price; U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel); - U32 const nbMatches = ZSTD_BtGetAllMatches(ms, inr, iend, dictMode, opt[cur].rep, ll0, matches, minMatch); + U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch); U32 matchNb; if (!nbMatches) { DEBUGLOG(7, "rPos:%u : no match found", cur); @@ -1094,7 +1108,7 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ } /* while (ip < ilimit) */ /* Return the last literals size */ - return iend - anchor; + return (size_t)(iend - anchor); } @@ -1158,7 +1172,6 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, ms->window.dictLimit += (U32)srcSize; ms->window.lowLimit = ms->window.dictLimit; ms->nextToUpdate = ms->window.dictLimit; - ms->nextToUpdate3 = ms->window.dictLimit; /* re-inforce weight of collected statistics */ ZSTD_upscaleStats(&ms->opt); diff --git a/thirdparty/zstd/compress/zstdmt_compress.c b/thirdparty/zstd/compress/zstdmt_compress.c index 38fbb90768..9e537b8848 100644 --- a/thirdparty/zstd/compress/zstdmt_compress.c +++ b/thirdparty/zstd/compress/zstdmt_compress.c @@ -1129,9 +1129,14 @@ size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx) size_t const produced = ZSTD_isError(cResult) ? 0 : cResult; size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed; assert(flushed <= produced); + assert(jobPtr->consumed <= jobPtr->src.size); toFlush = produced - flushed; - if (toFlush==0 && (jobPtr->consumed >= jobPtr->src.size)) { - /* doneJobID is not-fully-flushed, but toFlush==0 : doneJobID should be compressing some more data */ + /* if toFlush==0, nothing is available to flush. + * However, jobID is expected to still be active: + * if jobID was already completed and fully flushed, + * ZSTDMT_flushProduced() should have already moved onto next job. + * Therefore, some input has not yet been consumed. */ + if (toFlush==0) { assert(jobPtr->consumed < jobPtr->src.size); } } @@ -1148,12 +1153,16 @@ size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx) static unsigned ZSTDMT_computeTargetJobLog(ZSTD_CCtx_params const params) { - if (params.ldmParams.enableLdm) + unsigned jobLog; + if (params.ldmParams.enableLdm) { /* In Long Range Mode, the windowLog is typically oversized. * In which case, it's preferable to determine the jobSize * based on chainLog instead. */ - return MAX(21, params.cParams.chainLog + 4); - return MAX(20, params.cParams.windowLog + 2); + jobLog = MAX(21, params.cParams.chainLog + 4); + } else { + jobLog = MAX(20, params.cParams.windowLog + 2); + } + return MIN(jobLog, (unsigned)ZSTDMT_JOBLOG_MAX); } static int ZSTDMT_overlapLog_default(ZSTD_strategy strat) @@ -1197,7 +1206,7 @@ static size_t ZSTDMT_computeOverlapSize(ZSTD_CCtx_params const params) ovLog = MIN(params.cParams.windowLog, ZSTDMT_computeTargetJobLog(params) - 2) - overlapRLog; } - assert(0 <= ovLog && ovLog <= 30); + assert(0 <= ovLog && ovLog <= ZSTD_WINDOWLOG_MAX); DEBUGLOG(4, "overlapLog : %i", params.overlapLog); DEBUGLOG(4, "overlap size : %i", 1 << ovLog); return (ovLog==0) ? 0 : (size_t)1 << ovLog; @@ -1391,7 +1400,7 @@ size_t ZSTDMT_initCStream_internal( FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) ); if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN; - if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = ZSTDMT_JOBSIZE_MAX; + if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = (size_t)ZSTDMT_JOBSIZE_MAX; mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */ if (mtctx->singleBlockingThread) { @@ -1432,6 +1441,8 @@ size_t ZSTDMT_initCStream_internal( if (mtctx->targetSectionSize == 0) { mtctx->targetSectionSize = 1ULL << ZSTDMT_computeTargetJobLog(params); } + assert(mtctx->targetSectionSize <= (size_t)ZSTDMT_JOBSIZE_MAX); + if (params.rsyncable) { /* Aim for the targetsectionSize as the average job size. */ U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20); diff --git a/thirdparty/zstd/compress/zstdmt_compress.h b/thirdparty/zstd/compress/zstdmt_compress.h index 12e6bcb3a3..12a526087d 100644 --- a/thirdparty/zstd/compress/zstdmt_compress.h +++ b/thirdparty/zstd/compress/zstdmt_compress.h @@ -50,6 +50,7 @@ #ifndef ZSTDMT_JOBSIZE_MIN # define ZSTDMT_JOBSIZE_MIN (1 MB) #endif +#define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30) #define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB)) diff --git a/thirdparty/zstd/decompress/zstd_decompress.c b/thirdparty/zstd/decompress/zstd_decompress.c index 675596f5aa..e42872ad96 100644 --- a/thirdparty/zstd/decompress/zstd_decompress.c +++ b/thirdparty/zstd/decompress/zstd_decompress.c @@ -360,8 +360,11 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize) sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, frameParameter_unsupported); - - return skippableHeaderSize + sizeU32; + { + size_t const skippableSize = skippableHeaderSize + sizeU32; + RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong); + return skippableSize; + } } /** ZSTD_findDecompressedSize() : @@ -378,11 +381,10 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { size_t const skippableSize = readSkippableFrameSize(src, srcSize); - if (ZSTD_isError(skippableSize)) - return skippableSize; - if (srcSize < skippableSize) { + if (ZSTD_isError(skippableSize)) { return ZSTD_CONTENTSIZE_ERROR; } + assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; srcSize -= skippableSize; @@ -467,6 +469,8 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE) && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize); + assert(ZSTD_isError(frameSizeInfo.compressedSize) || + frameSizeInfo.compressedSize <= srcSize); return frameSizeInfo; } else { const BYTE* ip = (const BYTE*)src; @@ -529,7 +533,6 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) return frameSizeInfo.compressedSize; } - /** ZSTD_decompressBound() : * compatible with legacy mode * `src` must point to the start of a ZSTD frame or a skippeable frame @@ -546,6 +549,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) return ZSTD_CONTENTSIZE_ERROR; + assert(srcSize >= compressedSize); src = (const BYTE*)src + compressedSize; srcSize -= compressedSize; bound += decompressedBound; @@ -738,9 +742,8 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, (unsigned)magicNumber, ZSTD_MAGICNUMBER); if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { size_t const skippableSize = readSkippableFrameSize(src, srcSize); - if (ZSTD_isError(skippableSize)) - return skippableSize; - RETURN_ERROR_IF(srcSize < skippableSize, srcSize_wrong); + FORWARD_IF_ERROR(skippableSize); + assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; srcSize -= skippableSize; diff --git a/thirdparty/zstd/decompress/zstd_decompress_block.c b/thirdparty/zstd/decompress/zstd_decompress_block.c index a2a7eedcf2..24f4859c56 100644 --- a/thirdparty/zstd/decompress/zstd_decompress_block.c +++ b/thirdparty/zstd/decompress/zstd_decompress_block.c @@ -505,7 +505,7 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, *nbSeqPtr = nbSeq; /* FSE table descriptors */ - RETURN_ERROR_IF(ip+4 > iend, srcSize_wrong); /* minimum possible size */ + RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong); /* minimum possible size: 1 byte for symbol encoding types */ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); @@ -637,9 +637,10 @@ size_t ZSTD_execSequence(BYTE* op, if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); /* copy Literals */ - ZSTD_copy8(op, *litPtr); if (sequence.litLength > 8) - ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ + ZSTD_wildcopy_16min(op, (*litPtr), sequence.litLength, ZSTD_no_overlap); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ + else + ZSTD_copy8(op, *litPtr); op = oLitEnd; *litPtr = iLitEnd; /* update for next sequence */ @@ -686,13 +687,13 @@ size_t ZSTD_execSequence(BYTE* op, if (oMatchEnd > oend-(16-MINMATCH)) { if (op < oend_w) { - ZSTD_wildcopy(op, match, oend_w - op); + ZSTD_wildcopy(op, match, oend_w - op, ZSTD_overlap_src_before_dst); match += oend_w - op; op = oend_w; } while (op < oMatchEnd) *op++ = *match++; } else { - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst); /* works even if matchLength < 8 */ } return sequenceLength; } @@ -717,9 +718,11 @@ size_t ZSTD_execSequenceLong(BYTE* op, if (oLitEnd > oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, dictStart, dictEnd); /* copy Literals */ - ZSTD_copy8(op, *litPtr); /* note : op <= oLitEnd <= oend_w == oend - 8 */ if (sequence.litLength > 8) - ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ + ZSTD_wildcopy_16min(op, *litPtr, sequence.litLength, ZSTD_no_overlap); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ + else + ZSTD_copy8(op, *litPtr); /* note : op <= oLitEnd <= oend_w == oend - 8 */ + op = oLitEnd; *litPtr = iLitEnd; /* update for next sequence */ @@ -766,13 +769,13 @@ size_t ZSTD_execSequenceLong(BYTE* op, if (oMatchEnd > oend-(16-MINMATCH)) { if (op < oend_w) { - ZSTD_wildcopy(op, match, oend_w - op); + ZSTD_wildcopy(op, match, oend_w - op, ZSTD_overlap_src_before_dst); match += oend_w - op; op = oend_w; } while (op < oMatchEnd) *op++ = *match++; } else { - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst); /* works even if matchLength < 8 */ } return sequenceLength; } @@ -889,6 +892,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) } FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, @@ -918,6 +922,11 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) { nbSeq--; { seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); @@ -930,6 +939,7 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, /* check if reached exact end */ DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); RETURN_ERROR_IF(nbSeq, corruption_detected); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected); /* save reps for next block */ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); } } @@ -1131,6 +1141,7 @@ ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG static TARGET_ATTRIBUTE("bmi2") size_t +DONT_VECTORIZE ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, diff --git a/thirdparty/zstd/zstd.h b/thirdparty/zstd/zstd.h index 53470c18f3..a1910ee223 100644 --- a/thirdparty/zstd/zstd.h +++ b/thirdparty/zstd/zstd.h @@ -71,7 +71,7 @@ extern "C" { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 #define ZSTD_VERSION_MINOR 4 -#define ZSTD_VERSION_RELEASE 0 +#define ZSTD_VERSION_RELEASE 1 #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */ @@ -82,16 +82,16 @@ ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library v #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ -/*************************************** -* Default constant -***************************************/ +/* ************************************* + * Default constant + ***************************************/ #ifndef ZSTD_CLEVEL_DEFAULT # define ZSTD_CLEVEL_DEFAULT 3 #endif -/*************************************** -* Constants -***************************************/ +/* ************************************* + * Constants + ***************************************/ /* All magic numbers are supposed read/written to/from files/memory using little-endian convention */ #define ZSTD_MAGICNUMBER 0xFD2FB528 /* valid since v0.8.0 */ @@ -183,9 +183,14 @@ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compres ***************************************/ /*= Compression context * When compressing many times, - * it is recommended to allocate a context just once, and re-use it for each successive compression operation. + * it is recommended to allocate a context just once, + * and re-use it for each successive compression operation. * This will make workload friendlier for system's memory. - * Use one context per thread for parallel execution in multi-threaded environments. */ + * Note : re-using context is just a speed / resource optimization. + * It doesn't change the compression ratio, which remains identical. + * Note 2 : In multi-threaded environments, + * use one different context per thread for parallel execution. + */ typedef struct ZSTD_CCtx_s ZSTD_CCtx; ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); @@ -380,6 +385,7 @@ typedef enum { * ZSTD_c_forceMaxWindow * ZSTD_c_forceAttachDict * ZSTD_c_literalCompressionMode + * ZSTD_c_targetCBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly; * also, the enums values themselves are unstable and can still change. @@ -389,6 +395,7 @@ typedef enum { ZSTD_c_experimentalParam3=1000, ZSTD_c_experimentalParam4=1001, ZSTD_c_experimentalParam5=1002, + ZSTD_c_experimentalParam6=1003, } ZSTD_cParameter; typedef struct { @@ -657,17 +664,33 @@ ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_inBuffer* input, ZSTD_EndDirective endOp); + +/* These buffer sizes are softly recommended. + * They are not required : ZSTD_compressStream*() happily accepts any buffer size, for both input and output. + * Respecting the recommended size just makes it a bit easier for ZSTD_compressStream*(), + * reducing the amount of memory shuffling and buffering, resulting in minor performance savings. + * + * However, note that these recommendations are from the perspective of a C caller program. + * If the streaming interface is invoked from some other language, + * especially managed ones such as Java or Go, through a foreign function interface such as jni or cgo, + * a major performance rule is to reduce crossing such interface to an absolute minimum. + * It's not rare that performance ends being spent more into the interface, rather than compression itself. + * In which cases, prefer using large buffers, as large as practical, + * for both input and output, to reduce the nb of roundtrips. + */ ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */ -ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */ +ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block. */ -/******************************************************************************* - * This is a legacy streaming API, and can be replaced by ZSTD_CCtx_reset() and - * ZSTD_compressStream2(). It is redundant, but is still fully supported. + +/* ***************************************************************************** + * This following is a legacy streaming API. + * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). + * It is redundant, but remains fully supported. * Advanced parameters and dictionary compression can only be used through the * new API. ******************************************************************************/ -/** +/*! * Equivalent to: * * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); @@ -675,16 +698,16 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); */ ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); -/** +/*! * Alternative for ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue). * NOTE: The return value is different. ZSTD_compressStream() returns a hint for * the next read size (if non-zero and not an error). ZSTD_compressStream2() - * returns the number of bytes left to flush (if non-zero and not an error). + * returns the minimum nb of bytes left to flush (if non-zero and not an error). */ ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input); -/** Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_flush). */ +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_flush). */ ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); -/** Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_end). */ +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_end). */ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); @@ -969,7 +992,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #endif /* ZSTD_H_235446 */ -/**************************************************************************************** +/* ************************************************************************************** * ADVANCED AND EXPERIMENTAL FUNCTIONS **************************************************************************************** * The definitions in the following section are considered experimental. @@ -1037,6 +1060,10 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); #define ZSTD_LDM_HASHRATELOG_MIN 0 #define ZSTD_LDM_HASHRATELOG_MAX (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) +/* Advanced parameter bounds */ +#define ZSTD_TARGETCBLOCKSIZE_MIN 64 +#define ZSTD_TARGETCBLOCKSIZE_MAX ZSTD_BLOCKSIZE_MAX + /* internal */ #define ZSTD_HASHLOG3_MAX 17 @@ -1162,7 +1189,7 @@ typedef enum { * however it does mean that all frame data must be present and valid. */ ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); -/** ZSTD_decompressBound() : +/*! ZSTD_decompressBound() : * `src` should point to the start of a series of ZSTD encoded and/or skippable frames * `srcSize` must be the _exact_ size of this series * (i.e. there should be a frame boundary at `src + srcSize`) @@ -1409,6 +1436,11 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre */ #define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 +/* Tries to fit compressed block size to be around targetCBlockSize. + * No target when targetCBlockSize == 0. + * There is no guarantee on compressed block size (default:0) */ +#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6 + /*! ZSTD_CCtx_getParameter() : * Get the requested compression parameter value, selected by enum ZSTD_cParameter, * and store it into int* value. @@ -1843,7 +1875,7 @@ typedef struct { unsigned checksumFlag; } ZSTD_frameHeader; -/** ZSTD_getFrameHeader() : +/*! ZSTD_getFrameHeader() : * decode Frame Header, or requires larger `srcSize`. * @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, value is wanted `srcSize` amount, |