diff options
213 files changed, 18221 insertions, 7137 deletions
diff --git a/.travis.yml b/.travis.yml index 6be9f1f603..12d49f5d5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: cpp +dist: trusty + sudo: false compiler: @@ -73,7 +75,6 @@ addons: # For style checks. - clang-format-3.9 - before_script: - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install scons; fi - if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then @@ -86,5 +87,9 @@ script: - if [ "$STATIC_CHECKS" = "yes" ]; then sh ./misc/travis/clang-format.sh; else - scons platform=$GODOT_TARGET CXX=$CXX openssl=builtin; + if [ "$TRAVIS_OS_NAME" = "windows" ]; then + scons platform=$GODOT_TARGET CXX=$CXX openssl=builtin; + else + scons platform=$GODOT_TARGET bits=64 CXX=$CXX openssl=builtin; + fi fi diff --git a/AUTHORS.md b/AUTHORS.md index 728ba5f6ee..84b0754929 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -10,17 +10,26 @@ source code. "Significant" is arbitrarily decided, but should be fair :) GitHub usernames are indicated in parentheses, or as sole entry when no other name is available. -## Original authors +## Project Founders Juan Linietsky (reduz) Ariel Manzur (punto-) +## Lead Developer + + Juan Linietsky (reduz) + +## Project Manager + + Rémi Verschelde (akien-mga) + ## Developers (in alphabetical order, with 10 commits or more excluding merges) Alexander Holland (AlexHolly) Alexey Velikiy (jonyrock) + Alket Rexhepi (alketii) Andreas Haas (Hinsbart) Anton Yabchinskiy (a12n) Aren Villanueva (kurikaesu) @@ -41,8 +50,10 @@ name is available. Guilherme Felipe (guilhermefelipecgs) Hein-Pieter van Braam (hpvb) Hubert Jarosz (Marqin) + Hugo Locurcio (Calinou) Ignacio Etcheverry (neikeq) J08nY + Jakub Grzesik (kubecz3k) Johan Manuel (29jm) Joshua Grams (JoshuaGrams) Juan Linietsky (reduz) @@ -55,17 +66,21 @@ name is available. Mario Schlack (hurikhan) Masoud BH (masoudbh3) Nathan Warden (NathanWarden) + Nuno Donato (nunodonato) Ovnuniarchos Patrick (firefly2442) Paul Batty (Paulb23) Pawel Kowal (pkowal1982) Pedro J. Estébanez (RandomShaper) + Poommetee Ketson (Noshyaar) Ralf Hölzemer (rollenrolm) Ramesh Ravone (RameshRavone) Ray Koopa (RayKoopa) Rémi Verschelde (akien-mga) SaracenOne + Theo Hallenius (TheoXD) Thomas Herzog (karroffel) + Timo (toger5) V. Vamsi Krishna (vkbsb) Vinzenz Feenstra (vinzenz) Zher Huei Lee (leezh) diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 2752391901..d81ccf0265 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -2532,6 +2532,10 @@ Dictionary _Engine::get_version_info() const { return Engine::get_singleton()->get_version_info(); } +bool _Engine::is_in_fixed_frame() const { + return Engine::get_singleton()->is_in_fixed_frame(); +} + void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_iterations_per_second", "iterations_per_second"), &_Engine::set_iterations_per_second); @@ -2550,6 +2554,8 @@ void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("get_main_loop:MainLoop"), &_Engine::get_main_loop); ClassDB::bind_method(D_METHOD("get_version_info"), &_Engine::get_version_info); + + ClassDB::bind_method(D_METHOD("is_in_fixed_frame"), &_Engine::is_in_fixed_frame); } _Engine *_Engine::singleton = NULL; diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index e48b5c85ad..a2fb6c966c 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -634,6 +634,8 @@ public: Dictionary get_version_info() const; + bool is_in_fixed_frame() const; + _Engine(); }; diff --git a/core/dvector.h b/core/dvector.h index 2e951b9661..4584a300f9 100644 --- a/core/dvector.h +++ b/core/dvector.h @@ -92,6 +92,7 @@ class PoolVector { // ERR_FAIL_COND(alloc->lock>0); should not be illegal to lock this for copy on write, as it's a copy on write after all + // Refcount should not be zero, otherwise it's a misuse of COW if (alloc->refcount.get() == 1) return; //nothing to do @@ -216,7 +217,12 @@ class PoolVector { { int cur_elements = alloc->size / sizeof(T); - Write w = write(); + + // Don't use write() here because it could otherwise provoke COW, + // which is not desirable here because we are destroying the last reference anyways + Write w; + // Reference to still prevent other threads from touching the alloc + w._ref(alloc); for (int i = 0; i < cur_elements; i++) { diff --git a/core/image.cpp b/core/image.cpp index 686735c906..380b307020 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1483,16 +1483,16 @@ Error Image::decompress() { _image_decompress_bc(this); else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc) _image_decompress_pvrtc(this); - else if (format == FORMAT_ETC && _image_decompress_etc) - _image_decompress_etc(this); - else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc) + else if (format == FORMAT_ETC && _image_decompress_etc1) + _image_decompress_etc1(this); + else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc1) _image_decompress_etc2(this); else return ERR_UNAVAILABLE; return OK; } -Error Image::compress(CompressMode p_mode, bool p_for_srgb) { +Error Image::compress(CompressMode p_mode, bool p_for_srgb, float p_lossy_quality) { switch (p_mode) { @@ -1513,13 +1513,13 @@ Error Image::compress(CompressMode p_mode, bool p_for_srgb) { } break; case COMPRESS_ETC: { - ERR_FAIL_COND_V(!_image_compress_etc_func, ERR_UNAVAILABLE); - _image_compress_etc_func(this); + ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE); + _image_compress_etc1_func(this, p_lossy_quality); } break; case COMPRESS_ETC2: { - ERR_FAIL_COND_V(!_image_compress_etc_func, ERR_UNAVAILABLE); - _image_compress_etc_func(this); + ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE); + _image_compress_etc2_func(this, p_lossy_quality); } break; } @@ -1612,11 +1612,11 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po ERR_FAIL_COND(srcdsize == 0); ERR_FAIL_COND(format != p_src->format); - Rect2i local_src_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest + p_src_rect.position, p_src_rect.size)); - - if (local_src_rect.size.x <= 0 || local_src_rect.size.y <= 0) + Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; - Rect2i src_rect(p_src_rect.position + (local_src_rect.position - p_dest), local_src_rect.size); + + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); PoolVector<uint8_t>::Write wp = data.write(); uint8_t *dst_data_ptr = wp.ptr(); @@ -1626,15 +1626,15 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po int pixel_size = get_format_pixel_size(format); - for (int i = 0; i < src_rect.size.y; i++) { + for (int i = 0; i < dest_rect.size.y; i++) { - for (int j = 0; j < src_rect.size.x; j++) { + for (int j = 0; j < dest_rect.size.x; j++) { - int src_x = src_rect.position.x + j; - int src_y = src_rect.position.y + i; + int src_x = clipped_src_rect.position.x + j; + int src_y = clipped_src_rect.position.y + i; - int dst_x = local_src_rect.position.x + j; - int dst_y = local_src_rect.position.y + i; + int dst_x = dest_rect.position.x + j; + int dst_y = dest_rect.position.y + i; const uint8_t *src = &src_data_ptr[(src_y * p_src->width + src_x) * pixel_size]; uint8_t *dst = &dst_data_ptr[(dst_y * width + dst_x) * pixel_size]; @@ -1652,11 +1652,11 @@ Ref<Image> (*Image::_jpg_mem_loader_func)(const uint8_t *, int) = NULL; void (*Image::_image_compress_bc_func)(Image *, bool) = NULL; void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL; void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL; -void (*Image::_image_compress_etc_func)(Image *) = NULL; -void (*Image::_image_compress_etc2_func)(Image *) = NULL; +void (*Image::_image_compress_etc1_func)(Image *, float) = NULL; +void (*Image::_image_compress_etc2_func)(Image *, float) = NULL; void (*Image::_image_decompress_pvrtc)(Image *) = NULL; void (*Image::_image_decompress_bc)(Image *) = NULL; -void (*Image::_image_decompress_etc)(Image *) = NULL; +void (*Image::_image_decompress_etc1)(Image *) = NULL; void (*Image::_image_decompress_etc2)(Image *) = NULL; PoolVector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = NULL; diff --git a/core/image.h b/core/image.h index e3174a2899..790c5de9f6 100644 --- a/core/image.h +++ b/core/image.h @@ -117,12 +117,12 @@ public: static void (*_image_compress_bc_func)(Image *, bool p_srgb); static void (*_image_compress_pvrtc2_func)(Image *); static void (*_image_compress_pvrtc4_func)(Image *); - static void (*_image_compress_etc_func)(Image *); - static void (*_image_compress_etc2_func)(Image *); + static void (*_image_compress_etc1_func)(Image *, float); + static void (*_image_compress_etc2_func)(Image *, float); static void (*_image_decompress_pvrtc)(Image *); static void (*_image_decompress_bc)(Image *); - static void (*_image_decompress_etc)(Image *); + static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc2)(Image *); static PoolVector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality); @@ -267,7 +267,7 @@ public: COMPRESS_ETC2, }; - Error compress(CompressMode p_mode = COMPRESS_S3TC, bool p_for_srgb = false); + Error compress(CompressMode p_mode = COMPRESS_S3TC, bool p_for_srgb = false, float p_lossy_quality = 0.7); Error decompress(); bool is_compressed() const; diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 899f3b3b2d..0c84a5213f 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -96,7 +96,12 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector }; String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; + if ((ssl && conn_port == 443) || (!ssl && conn_port == 80)) { + // don't append the standard ports + request += "Host: " + conn_host + "\r\n"; + } else { + request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; + } bool add_clen = p_body.size() > 0; for (int i = 0; i < p_headers.size(); i++) { request += p_headers[i] + "\r\n"; @@ -151,7 +156,12 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str }; String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; + if ((ssl && conn_port == 443) || (!ssl && conn_port == 80)) { + // don't append the standard ports + request += "Host: " + conn_host + "\r\n"; + } else { + request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; + } bool add_clen = p_body.length() > 0; for (int i = 0; i < p_headers.size(); i++) { request += p_headers[i] + "\r\n"; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 320990cc50..838fec22f0 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -401,7 +401,7 @@ void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStar::get_point_weight_scale); ClassDB::bind_method(D_METHOD("remove_point", "id"), &AStar::remove_point); - ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id"), &AStar::connect_points, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true)); ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points); ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar::are_points_connected); diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index ca960aabad..45509a0808 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -110,6 +110,15 @@ public: static _ALWAYS_INLINE_ bool is_inf(double p_val) { #ifdef _MSC_VER return !_finite(p_val); +// use an inline implementation of isinf as a workaround for problematic libstdc++ versions from gcc 5.x era +#elif defined(__GNUC__) && __GNUC__ < 6 + union { + uint64_t u; + double f; + } ieee754; + ieee754.f = p_val; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + ((unsigned)ieee754.u == 0); #else return isinf(p_val); #endif @@ -118,6 +127,14 @@ public: static _ALWAYS_INLINE_ bool is_inf(float p_val) { #ifdef _MSC_VER return !_finite(p_val); +// use an inline implementation of isinf as a workaround for problematic libstdc++ versions from gcc 5.x era +#elif defined(__GNUC__) && __GNUC__ < 6 + union { + uint32_t u; + float f; + } ieee754; + ieee754.f = p_val; + return (ieee754.u & 0x7fffffff) == 0x7f800000; #else return isinf(p_val); #endif diff --git a/core/script_language.h b/core/script_language.h index 115ab59dca..6e39593a89 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -196,6 +196,8 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0; virtual void get_string_delimiters(List<String> *p_delimiters) const = 0; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0; + virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {} + virtual bool is_using_templates() { return false; } virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const = 0; virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; diff --git a/core/translation.h b/core/translation.h index 577282b45f..8630b8a478 100644 --- a/core/translation.h +++ b/core/translation.h @@ -36,7 +36,7 @@ class Translation : public Resource { GDCLASS(Translation, Resource); OBJ_SAVE_TYPE(Translation); - RES_BASE_EXTENSION("xl"); + RES_BASE_EXTENSION("translation"); String locale; Map<StringName, StringName> translation_map; diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 20406bb483..f740f7fe90 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -1,15 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> <doc version="3.0.alpha.custom_build" name="Engine Types"> -<class name="@DLScript" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - </methods> - <constants> - </constants> -</class> <class name="@GDScript" category="Core"> <brief_description> Built-in GDScript functions. @@ -1914,45 +1904,49 @@ <constant name="TYPE_COLOR" value="14"> Variable is of type [Color]. </constant> - <constant name="TYPE_IMAGE" value="15"> - Variable is of type [Image]. - </constant> - <constant name="TYPE_NODE_PATH" value="16"> + <constant name="TYPE_NODE_PATH" value="15"> Variable is of type [NodePath]. </constant> - <constant name="TYPE_RID" value="17"> + <constant name="TYPE_RID" value="16"> Variable is of type [RID]. </constant> - <constant name="TYPE_OBJECT" value="18"> + <constant name="TYPE_OBJECT" value="17"> Variable is of type [Object]. </constant> - <constant name="TYPE_INPUT_EVENT" value="19"> - Variable is of type [InputEvent]. - </constant> - <constant name="TYPE_DICTIONARY" value="20"> + <constant name="TYPE_DICTIONARY" value="18"> Variable is of type [Dictionary]. </constant> - <constant name="TYPE_ARRAY" value="21"> + <constant name="TYPE_ARRAY" value="19"> Variable is of type [Array]. </constant> - <constant name="TYPE_RAW_ARRAY" value="22"> + <constant name="TYPE_RAW_ARRAY" value="20"> </constant> - <constant name="TYPE_INT_ARRAY" value="23"> + <constant name="TYPE_INT_ARRAY" value="21"> </constant> - <constant name="TYPE_REAL_ARRAY" value="24"> + <constant name="TYPE_REAL_ARRAY" value="22"> </constant> - <constant name="TYPE_STRING_ARRAY" value="25"> + <constant name="TYPE_STRING_ARRAY" value="23"> </constant> - <constant name="TYPE_VECTOR2_ARRAY" value="26"> + <constant name="TYPE_VECTOR2_ARRAY" value="24"> </constant> - <constant name="TYPE_VECTOR3_ARRAY" value="27"> + <constant name="TYPE_VECTOR3_ARRAY" value="25"> </constant> - <constant name="TYPE_COLOR_ARRAY" value="28"> + <constant name="TYPE_COLOR_ARRAY" value="26"> </constant> - <constant name="TYPE_MAX" value="29"> + <constant name="TYPE_MAX" value="27"> </constant> </constants> </class> +<class name="@Native" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + </methods> + <constants> + </constants> +</class> <class name="@VisualScript" category="Core"> <brief_description> </brief_description> @@ -1991,9 +1985,9 @@ <argument index="1" name="pos" type="Vector3"> </argument> <argument index="2" name="weight_scale" type="float" default="1"> - Weight scale has to be 1 or larger. </argument> <description> + Add a new point at the given position. The [code]weight_scale[/code] has to be 1 or larger. </description> </method> <method name="are_points_connected" qualifiers="const"> @@ -2015,6 +2009,8 @@ </argument> <argument index="1" name="to_id" type="int"> </argument> + <argument index="2" name="bidirectional" type="bool" default="true"> + </argument> <description> </description> </method> @@ -2986,7 +2982,7 @@ Return the default blend time between animations. </description> </method> - <method name="get_position" qualifiers="const"> + <method name="get_pos" qualifiers="const"> <return type="float"> </return> <description> @@ -3757,6 +3753,22 @@ Return the angular damp rate. </description> </method> + <method name="get_collision_layer" qualifiers="const"> + <return type="int"> + </return> + <description> + Return the physics layer this area is in. + </description> + </method> + <method name="get_collision_layer_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + Return an individual bit on the layer mask. + </description> + </method> <method name="get_collision_mask" qualifiers="const"> <return type="int"> </return> @@ -3794,22 +3806,6 @@ Return the gravity vector. If gravity is a point (see [method is_gravity_a_point]), this will be the attraction center. </description> </method> - <method name="get_layer_mask" qualifiers="const"> - <return type="int"> - </return> - <description> - Return the physics layer this area is in. - </description> - </method> - <method name="get_layer_mask_bit" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="bit" type="int"> - </argument> - <description> - Return an individual bit on the layer mask. - </description> - </method> <method name="get_linear_damp" qualifiers="const"> <return type="float"> </return> @@ -3892,6 +3888,24 @@ In practice, as the fraction of speed lost gets smaller with each frame, a value of 1.0 does not mean the object will stop in exactly one second. Only when the physics calculations are done at 1 frame per second, it does stop in a second. </description> </method> + <method name="set_collision_layer"> + <argument index="0" name="collision_layer" type="int"> + </argument> + <description> + Set the physics layers this area is in. + Collidable objects can exist in any of 32 different layers. These layers are not visual, but more of a tagging system instead. A collidable can use these layers/tags to select with which objects it can collide, using [method set_collision_mask]. + A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. + </description> + </method> + <method name="set_collision_layer_bit"> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier. + </description> + </method> <method name="set_collision_mask"> <argument index="0" name="collision_mask" type="int"> </argument> @@ -3938,24 +3952,6 @@ If gravity is a point (see [method is_gravity_a_point]), this will be the attraction center. </description> </method> - <method name="set_layer_mask"> - <argument index="0" name="layer_mask" type="int"> - </argument> - <description> - Set the physics layers this area is in. - Collidable objects can exist in any of 32 different layers. These layers are not visual, but more of a tagging system instead. A collidable can use these layers/tags to select with which objects it can collide, using [method set_collision_mask]. - A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. - </description> - </method> - <method name="set_layer_mask_bit"> - <argument index="0" name="bit" type="int"> - </argument> - <argument index="1" name="value" type="bool"> - </argument> - <description> - Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier. - </description> - </method> <method name="set_linear_damp"> <argument index="0" name="linear_damp" type="float"> </argument> @@ -4002,7 +3998,7 @@ <members> <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" brief=""> </member> - <member name="collision_layers" type="int" setter="set_layer_mask" getter="get_layer_mask" brief=""> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" brief=""> </member> <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" brief=""> </member> @@ -4125,6 +4121,22 @@ Return the angular damp rate. </description> </method> + <method name="get_collision_layer" qualifiers="const"> + <return type="int"> + </return> + <description> + Return the physics layer this area is in. + </description> + </method> + <method name="get_collision_layer_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + Return an individual bit on the layer mask. + </description> + </method> <method name="get_collision_mask" qualifiers="const"> <return type="int"> </return> @@ -4162,22 +4174,6 @@ Return the gravity vector. If gravity is a point (see [method is_gravity_a_point]), this will be the attraction center. </description> </method> - <method name="get_layer_mask" qualifiers="const"> - <return type="int"> - </return> - <description> - Return the physics layer this area is in. - </description> - </method> - <method name="get_layer_mask_bit" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="bit" type="int"> - </argument> - <description> - Return an individual bit on the layer mask. - </description> - </method> <method name="get_linear_damp" qualifiers="const"> <return type="float"> </return> @@ -4260,6 +4256,24 @@ In practice, as the fraction of speed lost gets smaller with each frame, a value of 1.0 does not mean the object will stop in exactly one second. Only when the physics calculations are done at 1 frame per second, it does stop in a second. </description> </method> + <method name="set_collision_layer"> + <argument index="0" name="collision_layer" type="int"> + </argument> + <description> + Set the physics layers this area is in. + Collidable objects can exist in any of 32 different layers. These layers are not visual, but more of a tagging system instead. A collidable can use these layers/tags to select with which objects it can collide, using [method set_collision_mask]. + A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. + </description> + </method> + <method name="set_collision_layer_bit"> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier. + </description> + </method> <method name="set_collision_mask"> <argument index="0" name="collision_mask" type="int"> </argument> @@ -4306,24 +4320,6 @@ If gravity is a point (see [method is_gravity_a_point]), this will be the attraction center. </description> </method> - <method name="set_layer_mask"> - <argument index="0" name="layer_mask" type="int"> - </argument> - <description> - Set the physics layers this area is in. - Collidable objects can exist in any of 32 different layers. These layers are not visual, but more of a tagging system instead. A collidable can use these layers/tags to select with which objects it can collide, using [method set_collision_mask]. - A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. - </description> - </method> - <method name="set_layer_mask_bit"> - <argument index="0" name="bit" type="int"> - </argument> - <argument index="1" name="value" type="bool"> - </argument> - <description> - Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier. - </description> - </method> <method name="set_linear_damp"> <argument index="0" name="linear_damp" type="float"> </argument> @@ -4370,7 +4366,7 @@ <members> <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" brief=""> </member> - <member name="collision_layers" type="int" setter="set_layer_mask" getter="get_layer_mask" brief=""> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" brief=""> </member> <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" brief=""> </member> @@ -4718,6 +4714,251 @@ <constants> </constants> </class> +<class name="ArrayMesh" inherits="Mesh" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="add_blend_shape"> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="add_surface_from_arrays"> + <argument index="0" name="primitive" type="int"> + </argument> + <argument index="1" name="arrays" type="Array"> + </argument> + <argument index="2" name="blend_shapes" type="Array" default="[]"> + </argument> + <argument index="3" name="compress_flags" type="int" default="97792"> + </argument> + <description> + Create a new surface ([method get_surface_count] that will become surf_idx for this. + Surfaces are created to be rendered using a "primitive", which may be PRIMITIVE_POINTS, PRIMITIVE_LINES, PRIMITIVE_LINE_STRIP, PRIMITIVE_LINE_LOOP, PRIMITIVE_TRIANGLES, PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_TRIANGLE_FAN. (As a note, when using indices, it is recommended to only use just points, lines or triangles). + </description> + </method> + <method name="center_geometry"> + <description> + </description> + </method> + <method name="clear_blend_shapes"> + <description> + </description> + </method> + <method name="get_blend_shape_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_blend_shape_mode" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_blend_shape_name" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_custom_aabb" qualifiers="const"> + <return type="Rect3"> + </return> + <description> + </description> + </method> + <method name="get_surface_count" qualifiers="const"> + <return type="int"> + </return> + <description> + Return the amount of surfaces that the [ArrayMesh] holds. + </description> + </method> + <method name="regen_normalmaps"> + <description> + </description> + </method> + <method name="set_blend_shape_mode"> + <argument index="0" name="mode" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_custom_aabb"> + <argument index="0" name="aabb" type="Rect3"> + </argument> + <description> + </description> + </method> + <method name="surface_get_array_index_len" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + Return the length in indices of the index array in the requested surface (see [method add_surface]). + </description> + </method> + <method name="surface_get_array_len" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + Return the length in vertices of the vertex array in the requested surface (see [method add_surface]). + </description> + </method> + <method name="surface_get_format" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + Return the format mask of the requested surface (see [method add_surface]). + </description> + </method> + <method name="surface_get_material" qualifiers="const"> + <return type="Material"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + Return a [Material] in a given surface. Surface is rendered using this material. + </description> + </method> + <method name="surface_get_name" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + </description> + </method> + <method name="surface_get_primitive_type" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + Return the primitive type of the requested surface (see [method add_surface]). + </description> + </method> + <method name="surface_remove"> + <argument index="0" name="surf_idx" type="int"> + </argument> + <description> + Remove a surface at position surf_idx, shifting greater surfaces one surf_idx slot down. + </description> + </method> + <method name="surface_set_material"> + <argument index="0" name="surf_idx" type="int"> + </argument> + <argument index="1" name="material" type="Material"> + </argument> + <description> + </description> + </method> + <method name="surface_set_name"> + <argument index="0" name="surf_idx" type="int"> + </argument> + <argument index="1" name="name" type="String"> + </argument> + <description> + Set a [Material] for a given surface. Surface will be rendered using this material. + </description> + </method> + </methods> + <constants> + <constant name="NO_INDEX_ARRAY" value="-1"> + Default value used for index_array_len when no indices are present. + </constant> + <constant name="ARRAY_WEIGHTS_SIZE" value="4"> + Amount of weights/bone indices per vertex (always 4). + </constant> + <constant name="ARRAY_VERTEX" value="0"> + Vertex array (array of [Vector3] vertices). + </constant> + <constant name="ARRAY_NORMAL" value="1"> + Normal array (array of [Vector3] normals). + </constant> + <constant name="ARRAY_TANGENT" value="2"> + Tangent array, array of groups of 4 floats. first 3 floats determine the tangent, and the last the binormal direction as -1 or 1. + </constant> + <constant name="ARRAY_COLOR" value="3"> + Vertex array (array of [Color] colors). + </constant> + <constant name="ARRAY_TEX_UV" value="4"> + UV array (array of [Vector3] UVs or float array of groups of 2 floats (u,v)). + </constant> + <constant name="ARRAY_TEX_UV2" value="5"> + Second UV array (array of [Vector3] UVs or float array of groups of 2 floats (u,v)). + </constant> + <constant name="ARRAY_BONES" value="6"> + Array of bone indices, as a float array. Each element in groups of 4 floats. + </constant> + <constant name="ARRAY_WEIGHTS" value="7"> + Array of bone weights, as a float array. Each element in groups of 4 floats. + </constant> + <constant name="ARRAY_INDEX" value="8"> + Array of integers, used as indices referencing vertices. No index can be beyond the vertex array size. + </constant> + <constant name="ARRAY_FORMAT_VERTEX" value="1"> + Array format will include vertices (mandatory). + </constant> + <constant name="ARRAY_FORMAT_NORMAL" value="2"> + Array format will include normals + </constant> + <constant name="ARRAY_FORMAT_TANGENT" value="4"> + Array format will include tangents + </constant> + <constant name="ARRAY_FORMAT_COLOR" value="8"> + Array format will include a color array. + </constant> + <constant name="ARRAY_FORMAT_TEX_UV" value="16"> + Array format will include UVs. + </constant> + <constant name="ARRAY_FORMAT_TEX_UV2" value="32"> + Array format will include another set of UVs. + </constant> + <constant name="ARRAY_FORMAT_BONES" value="64"> + Array format will include bone indices. + </constant> + <constant name="ARRAY_FORMAT_WEIGHTS" value="128"> + Array format will include bone weights. + </constant> + <constant name="ARRAY_FORMAT_INDEX" value="256"> + Index array will be used. + </constant> + <constant name="PRIMITIVE_POINTS" value="0"> + Render array as points (one vertex equals one point). + </constant> + <constant name="PRIMITIVE_LINES" value="1"> + Render array as lines (every two vertices a line is created). + </constant> + <constant name="PRIMITIVE_LINE_STRIP" value="2"> + Render array as line strip. + </constant> + <constant name="PRIMITIVE_LINE_LOOP" value="3"> + Render array as line loop (like line strip, but closed). + </constant> + <constant name="PRIMITIVE_TRIANGLES" value="4"> + Render array as triangles (every three vertices a triangle is created). + </constant> + <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5"> + Render array as triangle strips. + </constant> + <constant name="PRIMITIVE_TRIANGLE_FAN" value="6"> + Render array as triangle fans. + </constant> + </constants> +</class> <class name="AtlasTexture" inherits="Texture" category="Core"> <brief_description> </brief_description> @@ -6006,7 +6247,7 @@ <description> </description> </method> - <method name="get_position"> + <method name="get_pos"> <return type="float"> </return> <description> @@ -6595,58 +6836,6 @@ </constant> </constants> </class> -<class name="BakedLight" inherits="VisualInstance" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - <method name="bake"> - <description> - </description> - </method> - <method name="bake_lights"> - <description> - </description> - </method> - <method name="bake_radiance"> - <description> - </description> - </method> - <method name="debug_mesh_albedo"> - <description> - </description> - </method> - <method name="debug_mesh_light"> - <description> - </description> - </method> - <method name="get_cell_subdiv" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> - <method name="set_cell_subdiv"> - <argument index="0" name="steps" type="int"> - </argument> - <description> - </description> - </method> - </methods> - <members> - <member name="cell_subdiv" type="int" setter="set_cell_subdiv" getter="get_cell_subdiv" brief=""> - </member> - </members> - <signals> - <signal name="baked_light_changed"> - <description> - </description> - </signal> - </signals> - <constants> - </constants> -</class> <class name="BaseButton" inherits="Control" category="Core"> <brief_description> Provides a base class for different kinds of buttons. @@ -6858,21 +7047,21 @@ <method name="Basis"> <return type="Basis"> </return> - <argument index="0" name="axis" type="Vector3"> - </argument> - <argument index="1" name="phi" type="float"> + <argument index="0" name="euler" type="Vector3"> </argument> <description> - Create a rotation matrix which rotates around the given axis by the specified angle. The axis must be a normalized vector. + Create a rotation matrix (in the XYZ convention: first Z, then Y, and X last) from the specified Euler angles, given in the vector format as (third, second, first). </description> </method> <method name="Basis"> <return type="Basis"> </return> - <argument index="0" name="euler" type="Vector3"> + <argument index="0" name="axis" type="Vector3"> + </argument> + <argument index="1" name="phi" type="float"> </argument> <description> - Create a rotation matrix (in the XYZ convention: first Z, then Y, and X last) from the specified Euler angles, given in the vector format as (third,second,first). + Create a rotation matrix which rotates around the given axis by the specified angle. The axis must be a normalized vector. </description> </method> <method name="Basis"> @@ -6941,38 +7130,32 @@ Introduce an additional rotation around the given axis by phi (radians). Only relevant when the matrix is being used as a part of [Transform]. The axis must be a normalized vector. </description> </method> - <method name="set_rotation_euler"> + <method name="scaled"> <return type="Basis"> </return> - <argument index="0" name="euler" type="Vector3"> + <argument index="0" name="scale" type="Vector3"> </argument> <description> - Changes only the rotation part of the [Basis] to a rotation corresponding to given Euler angles, while preserving the scaling part (as determined by get_scale). + Introduce an additional scaling specified by the given 3D scaling factor. Only relevant when the matrix is being used as a part of [Transform]. </description> </method> <method name="set_rotation_axis_angle"> - <return type="Basis"> - </return> <argument index="0" name="axis" type="Vector3"> </argument> - <argument index="1" name="phi" type="float"> + <argument index="1" name="angle" type="float"> </argument> <description> Changes only the rotation part of the [Basis] to a rotation around given axis by phi, while preserving the scaling part (as determined by get_scale). </description> </method> - <method name="scaled"> - <return type="Basis"> - </return> - <argument index="0" name="scale" type="Vector3"> + <method name="set_rotation_euler"> + <argument index="0" name="euler" type="Vector3"> </argument> <description> - Introduce an additional scaling specified by the given 3D scaling factor. Only relevant when the matrix is being used as a part of [Transform]. + Changes only the rotation part of the [Basis] to a rotation corresponding to given Euler angles, while preserving the scaling part (as determined by get_scale). </description> </method> <method name="set_scale"> - <return type="Basis"> - </return> <argument index="0" name="scale" type="Vector3"> </argument> <description> @@ -7056,7 +7239,7 @@ </description> </method> <method name="create_from_image_alpha"> - <argument index="0" name="image" type="Image"> + <argument index="0" name="image" type="Object"> </argument> <description> </description> @@ -7473,173 +7656,6 @@ </theme_item> </theme_items> </class> -<class name="ButtonArray" inherits="Control" category="Core"> - <brief_description> - Array of Buttons. - </brief_description> - <description> - Array of Buttons. A ButtonArray is useful to have an array of buttons laid out vertically or horizontally. Only one button can be selected, and is referenced by its index in the array (first button is 0, second button is 1, etc.). - This is useful [i]e.g.[/i] for joypad-friendly interfaces and option menus. - </description> - <methods> - <method name="add_button"> - <argument index="0" name="text" type="String"> - </argument> - <argument index="1" name="tooltip" type="String" default=""""> - </argument> - <description> - Append a new button to the array, with the specified text and tooltip. - </description> - </method> - <method name="add_icon_button"> - <argument index="0" name="icon" type="Texture"> - </argument> - <argument index="1" name="text" type="String" default=""""> - </argument> - <argument index="2" name="tooltip" type="String" default=""""> - </argument> - <description> - Append a new button to the array, with the specified icon, text and tooltip. - </description> - </method> - <method name="clear"> - <description> - Remove all buttons from the array. - </description> - </method> - <method name="erase_button"> - <argument index="0" name="button_idx" type="int"> - </argument> - <description> - Remove the specified button in the array. - </description> - </method> - <method name="get_button_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Return the amount of buttons in the array. - </description> - </method> - <method name="get_button_icon" qualifiers="const"> - <return type="Texture"> - </return> - <argument index="0" name="button_idx" type="int"> - </argument> - <description> - Return the icon of the specified button. - </description> - </method> - <method name="get_button_text" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="button_idx" type="int"> - </argument> - <description> - Return the text of the specified button. - </description> - </method> - <method name="get_button_tooltip" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="button_idx" type="int"> - </argument> - <description> - Return the tooltip of the specified button. - </description> - </method> - <method name="get_hovered" qualifiers="const"> - <return type="int"> - </return> - <description> - Return the index of the currently hovered button in the array. - </description> - </method> - <method name="get_selected" qualifiers="const"> - <return type="int"> - </return> - <description> - Return the index of the currently selected button in the array. - </description> - </method> - <method name="is_flat" qualifiers="const"> - <return type="bool"> - </return> - <description> - </description> - </method> - <method name="set_button_icon"> - <argument index="0" name="button_idx" type="int"> - </argument> - <argument index="1" name="icon" type="Texture"> - </argument> - <description> - Set the icon of the specified button. - </description> - </method> - <method name="set_button_text"> - <argument index="0" name="button_idx" type="int"> - </argument> - <argument index="1" name="text" type="String"> - </argument> - <description> - Define the text of the specified button. - </description> - </method> - <method name="set_button_tooltip"> - <argument index="0" name="button_idx" type="int"> - </argument> - <argument index="1" name="text" type="String"> - </argument> - <description> - Define the tooltip of the specified button. - </description> - </method> - <method name="set_flat"> - <argument index="0" name="enabled" type="bool"> - </argument> - <description> - </description> - </method> - <method name="set_selected"> - <argument index="0" name="button_idx" type="int"> - </argument> - <description> - Select a button in the array based on the given index. - </description> - </method> - </methods> - <members> - <member name="flat" type="bool" setter="set_flat" getter="is_flat" brief=""> - </member> - </members> - <signals> - <signal name="button_selected"> - <argument index="0" name="button_idx" type="int"> - </argument> - <description> - A button has been selected, its index is given as the argument. - </description> - </signal> - </signals> - <constants> - <constant name="ALIGN_BEGIN" value="0"> - Align buttons at the beginning. - </constant> - <constant name="ALIGN_CENTER" value="1"> - Align buttons in the middle. - </constant> - <constant name="ALIGN_END" value="2"> - Align buttons at the end. - </constant> - <constant name="ALIGN_FILL" value="3"> - Spread the buttons, but keep them small. - </constant> - <constant name="ALIGN_EXPAND_FILL" value="4"> - Spread the buttons, but expand them. - </constant> - </constants> -</class> <class name="ButtonGroup" inherits="Resource" category="Core"> <brief_description> Group of Buttons. @@ -8553,12 +8569,11 @@ </description> </method> <method name="make_input_local" qualifiers="const"> - <return type="InputEvent"> + <return type="Object"> </return> - <argument index="0" name="event" type="InputEvent"> + <argument index="0" name="event" type="Object"> </argument> <description> - Takes a global input event and convert to this item's coordinate system. </description> </method> <method name="set_as_toplevel"> @@ -9169,6 +9184,16 @@ <description> </description> </method> + <method name="class_get_property" qualifiers="const"> + <return type="Variant"> + </return> + <argument index="0" name="object" type="Object"> + </argument> + <argument index="1" name="property" type="String"> + </argument> + <description> + </description> + </method> <method name="class_get_property_list" qualifiers="const"> <return type="Array"> </return> @@ -9231,6 +9256,18 @@ <description> </description> </method> + <method name="class_set_property" qualifiers="const"> + <return type="Error"> + </return> + <argument index="0" name="object" type="Object"> + </argument> + <argument index="1" name="property" type="String"> + </argument> + <argument index="2" name="value" type="Variant"> + </argument> + <description> + </description> + </method> <method name="get_class_list" qualifiers="const"> <return type="PoolStringArray"> </return> @@ -9416,7 +9453,7 @@ <signal name="input_event"> <argument index="0" name="camera" type="Object"> </argument> - <argument index="1" name="event" type="InputEvent"> + <argument index="1" name="event" type="Object"> </argument> <argument index="2" name="click_pos" type="Vector3"> </argument> @@ -9455,7 +9492,6 @@ <argument index="2" name="shape_idx" type="int"> </argument> <description> - This method can be used to override normal input processing. The first parameter is the viewport where the event took place. The second holds the input event received, and the third the shape of this object where it happened. </description> </method> <method name="add_shape"> @@ -9570,12 +9606,11 @@ <signal name="input_event"> <argument index="0" name="viewport" type="Object"> </argument> - <argument index="1" name="event" type="InputEvent"> + <argument index="1" name="event" type="Object"> </argument> <argument index="2" name="shape_idx" type="int"> </argument> <description> - This signal triggers when an input event fires over a shape. The first parameter is the viewport where the event took place. The second holds the input event received, and the third the shape of this object where it happened. </description> </signal> <signal name="mouse_entered"> @@ -10184,120 +10219,6 @@ </theme_item> </theme_items> </class> -<class name="ColorRamp" inherits="Resource" category="Core"> - <brief_description> - Color interpolator node - </brief_description> - <description> - Given a set of colors, this node will interpolate them in order, meaning, that if you have color 1, color 2 and color3, the ramp will interpolate (generate the colors between two colors) from color 1 to color 2 and from color 2 to color 3. Initially the ramp will have 2 colors (black and white), one (black) at ramp lower offset offset 0 and the other (white) at the ramp higher offset 1. - </description> - <methods> - <method name="add_point"> - <argument index="0" name="offset" type="float"> - </argument> - <argument index="1" name="color" type="Color"> - </argument> - <description> - Adds the specified color to the end of the ramp, with the specified offset - </description> - </method> - <method name="get_color" qualifiers="const"> - <return type="Color"> - </return> - <argument index="0" name="point" type="int"> - </argument> - <description> - Returns the color of the ramp color at index [i]point[/i] - </description> - </method> - <method name="get_colors" qualifiers="const"> - <return type="PoolColorArray"> - </return> - <description> - Returns the colors in the ramp - </description> - </method> - <method name="get_offset" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="point" type="int"> - </argument> - <description> - Returns the offset of the ramp color at index [i]point[/i] - </description> - </method> - <method name="get_offsets" qualifiers="const"> - <return type="PoolRealArray"> - </return> - <description> - Returns the offsets for the colors in this ramp - </description> - </method> - <method name="get_point_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the number of colors in the ramp - </description> - </method> - <method name="interpolate"> - <return type="Color"> - </return> - <argument index="0" name="offset" type="float"> - </argument> - <description> - Returns the interpolated color specified by [i]offset[/i] - </description> - </method> - <method name="remove_point"> - <argument index="0" name="offset" type="int"> - </argument> - <description> - Removes the color at the index [i]offset[/i] - </description> - </method> - <method name="set_color"> - <argument index="0" name="point" type="int"> - </argument> - <argument index="1" name="color" type="Color"> - </argument> - <description> - Sets the color of the ramp color at index [i]point[/i] - </description> - </method> - <method name="set_colors"> - <argument index="0" name="colors" type="PoolColorArray"> - </argument> - <description> - Sets the colors for the specified amount of elements. Calling this function with a different number of elements than previously defined causes the ramp to resize its colors and offsets array to accommodate the new elements. - </description> - </method> - <method name="set_offset"> - <argument index="0" name="point" type="int"> - </argument> - <argument index="1" name="offset" type="float"> - </argument> - <description> - Sets the offset for the ramp color at index [i]point[/i] - </description> - </method> - <method name="set_offsets"> - <argument index="0" name="offsets" type="PoolRealArray"> - </argument> - <description> - Sets the offset for the specified amount of elements. Calling this function with a different number of elements than previously defined causes the ramp to resize its colors and offsets array to accommodate the new elements, all new colors will be black by default. - </description> - </method> - </methods> - <members> - <member name="colors" type="float" setter="set_colors" getter="get_colors" brief=""> - </member> - <member name="offsets" type="float" setter="set_offsets" getter="get_offsets" brief=""> - </member> - </members> - <constants> - </constants> -</class> <class name="ColorRect" inherits="Control" category="Core"> <brief_description> </brief_description> @@ -10605,7 +10526,7 @@ Control is the base class Node for all the GUI components. Every GUI component inherits from it, directly or indirectly. In this way, sections of the scene tree made of contiguous control nodes, become user interfaces. Controls are relative to the parent position and size by using anchors and margins. This ensures that they can adapt easily in most situation to changing dialog and screen sizes. When more flexibility is desired, [Container] derived nodes can be used. Anchors work by defining which margin do they follow, and a value relative to it. Allowed anchoring modes are ANCHOR_BEGIN, where the margin is relative to the top or left margins of the parent (in pixels), ANCHOR_END for the right and bottom margins of the parent and ANCHOR_RATIO, which is a ratio from 0 to 1 in the parent range. - Input device events ([InputEvent]) are first sent to the root controls via the [method Node._input], which distribute it through the tree, then delivers them to the adequate one (under cursor or keyboard focus based) by calling [method MainLoop._input_event]. There is no need to enable input processing on controls to receive such events. To ensure that no one else will receive the event (not even [method Node._unhandled_input]), the control can accept it by calling [method accept_event]. + Input device events are first sent to the root controls via the [method Node._input], which distribute it through the tree, then delivers them to the adequate one (under cursor or keyboard focus based) by calling [method MainLoop._input_event]. There is no need to enable input processing on controls to receive such events. To ensure that no one else will receive the event (not even [method Node._unhandled_input]), the control can accept it by calling [method accept_event]. Only one control can hold the keyboard focus (receiving keyboard events), for that the control must define the focus mode with [method set_focus_mode]. Focus is lost when another control gains it, or the current focus owner is hidden. It is sometimes desired for a control to ignore mouse/pointer events. This is often the case when placing other controls on top of a button, in such cases. Calling [method set_ignore_mouse] enables this function. Finally, controls are skinned according to a [Theme]. Setting a [Theme] on a control will propagate all the skinning down the tree. Optionally, skinning can be overridden per each control by calling the add_*_override functions, or from the editor. @@ -10622,7 +10543,6 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> - Called when an input event reaches the control. </description> </method> <method name="accept_event"> @@ -10819,7 +10739,7 @@ <description> </description> </method> - <method name="get_global_pos" qualifiers="const"> + <method name="get_global_position" qualifiers="const"> <return type="Vector2"> </return> <description> @@ -11184,7 +11104,7 @@ Force a neighbour for moving the input focus to. When pressing TAB or directional/joypad directions focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function. </description> </method> - <method name="set_global_pos"> + <method name="set_global_position"> <argument index="0" name="pos" type="Vector2"> </argument> <description> @@ -11323,7 +11243,7 @@ </member> <member name="rect_min_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" brief=""> </member> - <member name="rect_pos" type="Vector2" setter="set_pos" getter="get_pos" brief=""> + <member name="rect_position" type="Vector2" setter="set_position" getter="get_position" brief=""> </member> <member name="rect_rotation" type="float" setter="set_rotation_deg" getter="get_rotation_deg" brief=""> </member> @@ -11352,10 +11272,9 @@ </description> </signal> <signal name="gui_input"> - <argument index="0" name="ev" type="InputEvent"> + <argument index="0" name="ev" type="Object"> </argument> <description> - Emitted when an input event is received. Connecting in realtime is recommended for accepting the events. </description> </signal> <signal name="minimum_size_changed"> @@ -11566,7 +11485,7 @@ </description> </method> <method name="get_side" qualifiers="const"> - <return type="Image"> + <return type="Object"> </return> <argument index="0" name="side" type="int"> </argument> @@ -11600,7 +11519,7 @@ <method name="set_side"> <argument index="0" name="side" type="int"> </argument> - <argument index="1" name="image" type="Image"> + <argument index="1" name="image" type="Object"> </argument> <description> </description> @@ -12091,72 +12010,6 @@ <constants> </constants> </class> -<class name="DLLibrary" inherits="Resource" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - <method name="get_platform_file" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="platform" type="String"> - </argument> - <description> - </description> - </method> - <method name="set_platform_file"> - <argument index="0" name="platform" type="String"> - </argument> - <argument index="1" name="file" type="String"> - </argument> - <description> - </description> - </method> - </methods> - <constants> - </constants> -</class> -<class name="DLScript" inherits="Script" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - <method name="get_library" qualifiers="const"> - <return type="Object"> - </return> - <description> - </description> - </method> - <method name="get_script_name" qualifiers="const"> - <return type="String"> - </return> - <description> - </description> - </method> - <method name="set_library"> - <argument index="0" name="library" type="Object"> - </argument> - <description> - </description> - </method> - <method name="set_script_name"> - <argument index="0" name="script_name" type="String"> - </argument> - <description> - </description> - </method> - </methods> - <members> - <member name="library" type="DLLibrary" setter="set_library" getter="get_library" brief=""> - </member> - <member name="script_name" type="String" setter="set_script_name" getter="get_script_name" brief=""> - </member> - </members> - <constants> - </constants> -</class> <class name="DampedSpringJoint2D" inherits="Joint2D" category="Core"> <brief_description> Damped spring constraint for 2D physics. @@ -12346,8 +12199,6 @@ </method> </methods> <members> - <member name="directional_shadow_bias_split_scale" type="float" setter="set_param" getter="get_param" brief=""> - </member> <member name="directional_shadow_blend_splits" type="bool" setter="set_blend_splits" getter="is_blend_splits_enabled" brief=""> </member> <member name="directional_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" brief=""> @@ -13051,6 +12902,94 @@ <constants> </constants> </class> +<class name="EditorImportPlugin" inherits="Reference" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_import_options" qualifiers="virtual"> + <return type="Array"> + </return> + <argument index="0" name="preset" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_importer_name" qualifiers="virtual"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_option_visibility" qualifiers="virtual"> + <return type="bool"> + </return> + <argument index="0" name="option" type="String"> + </argument> + <argument index="1" name="options" type="Dictionary"> + </argument> + <description> + </description> + </method> + <method name="get_preset_count" qualifiers="virtual"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_preset_name" qualifiers="virtual"> + <return type="String"> + </return> + <argument index="0" name="preset" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_recognized_extensions" qualifiers="virtual"> + <return type="Array"> + </return> + <description> + </description> + </method> + <method name="get_resource_type" qualifiers="virtual"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_save_extension" qualifiers="virtual"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_visible_name" qualifiers="virtual"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="import" qualifiers="virtual"> + <return type="int"> + </return> + <argument index="0" name="source_file" type="String"> + </argument> + <argument index="1" name="save_path" type="String"> + </argument> + <argument index="2" name="options" type="Dictionary"> + </argument> + <argument index="3" name="r_platform_variants" type="Array"> + </argument> + <argument index="4" name="r_gen_files" type="Array"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + </constants> +</class> <class name="EditorPlugin" inherits="Node" category="Core"> <brief_description> Used by the editor to extend its functionality. @@ -13108,6 +13047,12 @@ During run-time, this will be a simple object with a script so this function does not need to be called then. </description> </method> + <method name="add_import_plugin"> + <argument index="0" name="arg0" type="Object"> + </argument> + <description> + </description> + </method> <method name="add_tool_submenu_item"> <argument index="0" name="name" type="String"> </argument> @@ -13157,7 +13102,6 @@ <argument index="1" name="event" type="InputEvent"> </argument> <description> - If your plugin is active (because handles() returned true to the object), any input interaction with the 2D canvas editor will be first forwarded here. The canvas transform (containing zoom and offset to transform to edited world coordinates) is provided, but the input supplied is in untransformed coordinates to the canvas editor. Return true if you want to eat this event and not pass it to the canvas editor. </description> </method> <method name="forward_draw_over_canvas" qualifiers="virtual"> @@ -13177,9 +13121,6 @@ <argument index="1" name="event" type="InputEvent"> </argument> <description> - This is a low level function for plugins that edit a given objet type derived from Spatial to capture the input of the viewport. The function is only being called if your object is being edited. - By using the [InputEvent] and the [Camera] arguments it's pretty easy to do raycasts into space using Camera functions. - Return true if you want to capture the input, otherwise false. </description> </method> <method name="get_base_control"> @@ -13328,6 +13269,12 @@ Remove a custom type added by [method EditorPlugin.add_custom_type] </description> </method> + <method name="remove_import_plugin"> + <argument index="0" name="arg0" type="Object"> + </argument> + <description> + </description> + </method> <method name="save_external_data" qualifiers="virtual"> <description> This method is called after the editor saves the project or when it's closed. It asks the plugin to save edited external scenes/resources. @@ -13723,7 +13670,7 @@ </argument> <argument index="1" name="billboard" type="bool" default="false"> </argument> - <argument index="2" name="skeleton" type="RID" default="RID()"> + <argument index="2" name="skeleton" type="RID" default="[RID]"> </argument> <description> Add a mesh to the gizmo, this is used for visualization. Call this function during [method redraw]. @@ -13868,6 +13815,12 @@ "string" - major + minor + patch + status + revision in a single String </description> </method> + <method name="is_in_fixed_frame" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="set_iterations_per_second"> <argument index="0" name="iterations_per_second" type="int"> </argument> @@ -13933,7 +13886,7 @@ <description> </description> </method> - <method name="get_ambient_light_skybox_contribution" qualifiers="const"> + <method name="get_ambient_light_sky_contribution" qualifiers="const"> <return type="float"> </return> <description> @@ -14011,6 +13964,60 @@ <description> </description> </method> + <method name="get_fog_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_fog_depth_begin" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_fog_depth_curve" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_fog_height_curve" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_fog_height_max" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_fog_height_min" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_fog_sun_amount" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_fog_sun_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_fog_transmit_curve" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_glow_blend_mode" qualifiers="const"> <return type="int"> </return> @@ -14047,13 +14054,13 @@ <description> </description> </method> - <method name="get_skybox" qualifiers="const"> + <method name="get_sky" qualifiers="const"> <return type="CubeMap"> </return> <description> </description> </method> - <method name="get_skybox_scale" qualifiers="const"> + <method name="get_sky_scale" qualifiers="const"> <return type="float"> </return> <description> @@ -14191,6 +14198,30 @@ <description> </description> </method> + <method name="is_fog_depth_enabled" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_fog_enabled" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_fog_height_enabled" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_fog_transmit_enabled" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="is_glow_bicubic_upscale_enabled" qualifiers="const"> <return type="bool"> </return> @@ -14283,7 +14314,7 @@ <description> </description> </method> - <method name="set_ambient_light_skybox_contribution"> + <method name="set_ambient_light_sky_contribution"> <argument index="0" name="energy" type="float"> </argument> <description> @@ -14373,6 +14404,84 @@ <description> </description> </method> + <method name="set_fog_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_fog_depth_begin"> + <argument index="0" name="distance" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_depth_curve"> + <argument index="0" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_depth_enabled"> + <argument index="0" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_fog_enabled"> + <argument index="0" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_fog_height_curve"> + <argument index="0" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_height_enabled"> + <argument index="0" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_fog_height_max"> + <argument index="0" name="height" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_height_min"> + <argument index="0" name="height" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_sun_amount"> + <argument index="0" name="amount" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_sun_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_fog_transmit_curve"> + <argument index="0" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_fog_transmit_enabled"> + <argument index="0" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> <method name="set_glow_bicubic_upscale"> <argument index="0" name="enabled" type="bool"> </argument> @@ -14429,13 +14538,13 @@ <description> </description> </method> - <method name="set_skybox"> - <argument index="0" name="skybox" type="CubeMap"> + <method name="set_sky"> + <argument index="0" name="sky" type="CubeMap"> </argument> <description> </description> </method> - <method name="set_skybox_scale"> + <method name="set_sky_scale"> <argument index="0" name="scale" type="float"> </argument> <description> @@ -14601,17 +14710,17 @@ </member> <member name="ambient_light_energy" type="float" setter="set_ambient_light_energy" getter="get_ambient_light_energy" brief=""> </member> - <member name="ambient_light_skybox_contribution" type="float" setter="set_ambient_light_skybox_contribution" getter="get_ambient_light_skybox_contribution" brief=""> + <member name="ambient_light_sky_contribution" type="float" setter="set_ambient_light_sky_contribution" getter="get_ambient_light_sky_contribution" brief=""> </member> - <member name="auto_expoure_enabled" type="bool" setter="set_tonemap_auto_exposure" getter="get_tonemap_auto_exposure" brief=""> + <member name="auto_exposure_enabled" type="bool" setter="set_tonemap_auto_exposure" getter="get_tonemap_auto_exposure" brief=""> </member> - <member name="auto_expoure_max_luma" type="float" setter="set_tonemap_auto_exposure_max" getter="get_tonemap_auto_exposure_max" brief=""> + <member name="auto_exposure_max_luma" type="float" setter="set_tonemap_auto_exposure_max" getter="get_tonemap_auto_exposure_max" brief=""> </member> - <member name="auto_expoure_min_luma" type="float" setter="set_tonemap_auto_exposure_min" getter="get_tonemap_auto_exposure_min" brief=""> + <member name="auto_exposure_min_luma" type="float" setter="set_tonemap_auto_exposure_min" getter="get_tonemap_auto_exposure_min" brief=""> </member> - <member name="auto_expoure_scale" type="float" setter="set_tonemap_auto_exposure_grey" getter="get_tonemap_auto_exposure_grey" brief=""> + <member name="auto_exposure_scale" type="float" setter="set_tonemap_auto_exposure_grey" getter="get_tonemap_auto_exposure_grey" brief=""> </member> - <member name="auto_expoure_speed" type="float" setter="set_tonemap_auto_exposure_speed" getter="get_tonemap_auto_exposure_speed" brief=""> + <member name="auto_exposure_speed" type="float" setter="set_tonemap_auto_exposure_speed" getter="get_tonemap_auto_exposure_speed" brief=""> </member> <member name="background_canvas_max_layer" type="int" setter="set_canvas_max_layer" getter="get_canvas_max_layer" brief=""> </member> @@ -14621,9 +14730,9 @@ </member> <member name="background_mode" type="int" setter="set_background" getter="get_background" brief=""> </member> - <member name="background_skybox" type="SkyBox" setter="set_skybox" getter="get_skybox" brief=""> + <member name="background_sky" type="Sky" setter="set_sky" getter="get_sky" brief=""> </member> - <member name="background_skybox_scale" type="float" setter="set_skybox_scale" getter="get_skybox_scale" brief=""> + <member name="background_sky_scale" type="float" setter="set_sky_scale" getter="get_sky_scale" brief=""> </member> <member name="dof_blur_far_amount" type="float" setter="set_dof_blur_far_amount" getter="get_dof_blur_far_amount" brief=""> </member> @@ -14645,6 +14754,32 @@ </member> <member name="dof_blur_near_transition" type="float" setter="set_dof_blur_near_transition" getter="get_dof_blur_near_transition" brief=""> </member> + <member name="fog_color" type="Color" setter="set_fog_color" getter="get_fog_color" brief=""> + </member> + <member name="fog_depth_begin" type="float" setter="set_fog_depth_begin" getter="get_fog_depth_begin" brief=""> + </member> + <member name="fog_depth_curve" type="float" setter="set_fog_depth_curve" getter="get_fog_depth_curve" brief=""> + </member> + <member name="fog_depth_enabled" type="bool" setter="set_fog_depth_enabled" getter="is_fog_depth_enabled" brief=""> + </member> + <member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" brief=""> + </member> + <member name="fog_height_curve" type="float" setter="set_fog_height_curve" getter="get_fog_height_curve" brief=""> + </member> + <member name="fog_height_enabled" type="bool" setter="set_fog_height_enabled" getter="is_fog_height_enabled" brief=""> + </member> + <member name="fog_height_max" type="float" setter="set_fog_height_max" getter="get_fog_height_max" brief=""> + </member> + <member name="fog_height_min" type="float" setter="set_fog_height_min" getter="get_fog_height_min" brief=""> + </member> + <member name="fog_sun_amount" type="float" setter="set_fog_sun_amount" getter="get_fog_sun_amount" brief=""> + </member> + <member name="fog_sun_color" type="Color" setter="set_fog_sun_color" getter="get_fog_sun_color" brief=""> + </member> + <member name="fog_transmit_curve" type="float" setter="set_fog_transmit_curve" getter="get_fog_transmit_curve" brief=""> + </member> + <member name="fog_transmit_enabled" type="bool" setter="set_fog_transmit_enabled" getter="is_fog_transmit_enabled" brief=""> + </member> <member name="glow_bicubic_upscale" type="bool" setter="set_glow_bicubic_upscale" getter="is_glow_bicubic_upscale_enabled" brief=""> </member> <member name="glow_blend_mode" type="int" setter="set_glow_blend_mode" getter="get_glow_blend_mode" brief=""> @@ -14721,7 +14856,7 @@ </constant> <constant name="BG_COLOR" value="1"> </constant> - <constant name="BG_SKYBOX" value="2"> + <constant name="BG_SKY" value="2"> </constant> <constant name="BG_CANVAS" value="3"> </constant> @@ -14914,7 +15049,7 @@ Get a [String] saved in Pascal format from the file. </description> </method> - <method name="get_position" qualifiers="const"> + <method name="get_pos" qualifiers="const"> <return type="int"> </return> <description> @@ -15435,11 +15570,10 @@ <return type="bool"> </return> <argument index="0" name="extended_check" type="bool" default="false"> - If true, also check if the associated script and object still exists. - The extended check is done in debug mode as part of [method GDFunctionState.resume], but you can use this if you know you may be trying to resume without knowing for sure the object and/or script have survived up to that point. </argument> <description> Check whether the function call may be resumed. This is not the case if the function state was already resumed. + If [code]extended_check[/code] is enabled, it also checks if the associated script and object still exist. The extended check is done in debug mode as part of [method GDFunctionState.resume], but you can use this if you know you may be trying to resume without knowing for sure the object and/or script have survived up to that point. </description> </method> <method name="resume"> @@ -15471,6 +15605,78 @@ <constants> </constants> </class> +<class name="GDNativeLibrary" inherits="Resource" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_platform_file" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="platform" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_platform_file"> + <argument index="0" name="platform" type="String"> + </argument> + <argument index="1" name="file" type="String"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + </constants> +</class> +<class name="GDNativeScript" inherits="Script" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_library" qualifiers="const"> + <return type="Object"> + </return> + <description> + </description> + </method> + <method name="get_script_name" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="new" qualifiers="vararg"> + <return type="Object"> + </return> + <description> + </description> + </method> + <method name="set_library"> + <argument index="0" name="library" type="Object"> + </argument> + <description> + </description> + </method> + <method name="set_script_name"> + <argument index="0" name="script_name" type="String"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library" brief=""> + </member> + <member name="script_name" type="String" setter="set_script_name" getter="get_script_name" brief=""> + </member> + </members> + <constants> + </constants> +</class> <class name="GDScript" inherits="Script" category="Core"> <brief_description> </brief_description> @@ -16599,6 +16805,120 @@ <constants> </constants> </class> +<class name="Gradient" inherits="Resource" category="Core"> + <brief_description> + Color interpolator node + </brief_description> + <description> + Given a set of colors, this node will interpolate them in order, meaning, that if you have color 1, color 2 and color3, the ramp will interpolate (generate the colors between two colors) from color 1 to color 2 and from color 2 to color 3. Initially the ramp will have 2 colors (black and white), one (black) at ramp lower offset offset 0 and the other (white) at the ramp higher offset 1. + </description> + <methods> + <method name="add_point"> + <argument index="0" name="offset" type="float"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <description> + Adds the specified color to the end of the ramp, with the specified offset + </description> + </method> + <method name="get_color" qualifiers="const"> + <return type="Color"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + Returns the color of the ramp color at index [i]point[/i] + </description> + </method> + <method name="get_colors" qualifiers="const"> + <return type="PoolColorArray"> + </return> + <description> + Returns the colors in the ramp + </description> + </method> + <method name="get_offset" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + Returns the offset of the ramp color at index [i]point[/i] + </description> + </method> + <method name="get_offsets" qualifiers="const"> + <return type="PoolRealArray"> + </return> + <description> + Returns the offsets for the colors in this ramp + </description> + </method> + <method name="get_point_count" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the number of colors in the ramp + </description> + </method> + <method name="interpolate"> + <return type="Color"> + </return> + <argument index="0" name="offset" type="float"> + </argument> + <description> + Returns the interpolated color specified by [i]offset[/i] + </description> + </method> + <method name="remove_point"> + <argument index="0" name="offset" type="int"> + </argument> + <description> + Removes the color at the index [i]offset[/i] + </description> + </method> + <method name="set_color"> + <argument index="0" name="point" type="int"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <description> + Sets the color of the ramp color at index [i]point[/i] + </description> + </method> + <method name="set_colors"> + <argument index="0" name="colors" type="PoolColorArray"> + </argument> + <description> + Sets the colors for the specified amount of elements. Calling this function with a different number of elements than previously defined causes the ramp to resize its colors and offsets array to accommodate the new elements. + </description> + </method> + <method name="set_offset"> + <argument index="0" name="point" type="int"> + </argument> + <argument index="1" name="offset" type="float"> + </argument> + <description> + Sets the offset for the ramp color at index [i]point[/i] + </description> + </method> + <method name="set_offsets"> + <argument index="0" name="offsets" type="PoolRealArray"> + </argument> + <description> + Sets the offset for the specified amount of elements. Calling this function with a different number of elements than previously defined causes the ramp to resize its colors and offsets array to accommodate the new elements, all new colors will be black by default. + </description> + </method> + </methods> + <members> + <member name="colors" type="float" setter="set_colors" getter="get_colors" brief=""> + </member> + <member name="offsets" type="float" setter="set_offsets" getter="get_offsets" brief=""> + </member> + </members> + <constants> + </constants> +</class> <class name="GradientTexture" inherits="Texture" category="Core"> <brief_description> </brief_description> @@ -17620,40 +17940,6 @@ </theme_item> </theme_items> </class> -<class name="HButtonArray" inherits="ButtonArray" category="Core"> - <brief_description> - Horizontal button array. - </brief_description> - <description> - Horizontal button array. See [ButtonArray]. - </description> - <methods> - </methods> - <constants> - </constants> - <theme_items> - <theme_item name="button_separator" type="int"> - </theme_item> - <theme_item name="focus" type="StyleBox"> - </theme_item> - <theme_item name="font" type="Font"> - </theme_item> - <theme_item name="font_color" type="Color"> - </theme_item> - <theme_item name="font_color_selected" type="Color"> - </theme_item> - <theme_item name="font_selected" type="Font"> - </theme_item> - <theme_item name="hover" type="StyleBox"> - </theme_item> - <theme_item name="icon_separator" type="int"> - </theme_item> - <theme_item name="normal" type="StyleBox"> - </theme_item> - <theme_item name="selected" type="StyleBox"> - </theme_item> - </theme_items> -</class> <class name="HScrollBar" inherits="ScrollBar" category="Core"> <brief_description> Horizontal scroll bar. @@ -17668,15 +17954,15 @@ <theme_items> <theme_item name="decrement" type="Texture"> </theme_item> - <theme_item name="decrement_hilite" type="Texture"> + <theme_item name="decrement_highlight" type="Texture"> </theme_item> <theme_item name="grabber" type="StyleBox"> </theme_item> - <theme_item name="grabber_hilite" type="StyleBox"> + <theme_item name="grabber_highlight" type="StyleBox"> </theme_item> <theme_item name="increment" type="Texture"> </theme_item> - <theme_item name="increment_hilite" type="Texture"> + <theme_item name="increment_highlight" type="Texture"> </theme_item> <theme_item name="scroll" type="StyleBox"> </theme_item> @@ -17718,9 +18004,9 @@ </theme_item> <theme_item name="grabber" type="Texture"> </theme_item> - <theme_item name="grabber_hilite" type="Texture"> + <theme_item name="grabber_highlight" type="Texture"> </theme_item> - <theme_item name="grabber_hilite" type="StyleBox"> + <theme_item name="grabber_highlight" type="StyleBox"> </theme_item> <theme_item name="slider" type="StyleBox"> </theme_item> @@ -18451,22 +18737,59 @@ <constants> </constants> </class> -<class name="Image" category="Built-In Types"> +<class name="Image" inherits="Resource" category="Core"> <brief_description> Image datatype. </brief_description> <description> - Built in native image datatype. Contains image data, which can be converted to a texture, and several functions to interact with it. + Native image datatype. Contains image data, which can be converted to a texture, and several functions to interact with it. </description> <methods> - <method name="Image"> - <return type="Image"> + <method name="blit_rect"> + <argument index="0" name="src" type="Image"> + </argument> + <argument index="1" name="src_rect" type="Rect2"> + </argument> + <argument index="2" name="dst" type="Vector2"> + </argument> + <description> + Copy a "src_rect" [Rect2] from "src" [Image] to this [Image] on coordinates "dest". + </description> + </method> + <method name="clear_mipmaps"> + <description> + </description> + </method> + <method name="compress"> + <return type="int"> </return> + <argument index="0" name="mode" type="int"> + </argument> + <argument index="1" name="arg1" type="bool"> + </argument> + <argument index="2" name="arg2" type="float"> + </argument> + <description> + </description> + </method> + <method name="convert"> + <argument index="0" name="format" type="int"> + </argument> + <description> + </description> + </method> + <method name="copy_from"> + <argument index="0" name="src" type="Image"> + </argument> + <description> + </description> + </method> + <method name="create"> <argument index="0" name="width" type="int"> </argument> <argument index="1" name="height" type="int"> </argument> - <argument index="2" name="mipmaps" type="bool"> + <argument index="2" name="use_mipmaps" type="bool"> </argument> <argument index="3" name="format" type="int"> </argument> @@ -18474,142 +18797,222 @@ Create an empty image of a specific size and format. </description> </method> - <method name="blit_rect"> - <argument index="0" name="src" type="Image"> + <method name="create_from_data"> + <argument index="0" name="width" type="int"> </argument> - <argument index="1" name="src_rect" type="Rect2"> + <argument index="1" name="height" type="int"> + </argument> + <argument index="2" name="use_mipmaps" type="bool"> + </argument> + <argument index="3" name="format" type="int"> </argument> - <argument index="2" name="dest" type="Vector2" default="0"> + <argument index="4" name="data" type="PoolByteArray"> </argument> <description> - Copy a "src_rect" [Rect2] from "src" [Image] to this [Image] on coordinates "dest". </description> </method> - <method name="compressed"> - <return type="Image"> - </return> - <argument index="0" name="format" type="int" default="0"> + <method name="crop"> + <argument index="0" name="width" type="int"> + </argument> + <argument index="1" name="height" type="int"> </argument> <description> - Return a new compressed [Image] from this [Image] using one of [Image].COMPRESS_*. </description> </method> - <method name="converted"> - <return type="Image"> + <method name="decompress"> + <return type="int"> </return> - <argument index="0" name="format" type="int" default="0"> - </argument> <description> - Return a new [Image] from this [Image] with a different format. </description> </method> - <method name="decompressed"> - <return type="Image"> + <method name="detect_alpha" qualifiers="const"> + <return type="int"> </return> <description> - Return a new decompressed [Image]. </description> </method> - <method name="empty"> - <return type="bool"> - </return> + <method name="expand_x2_hq2x"> <description> - Return whether this [Image] is empty(no data). </description> </method> <method name="fix_alpha_edges"> <description> </description> </method> - <method name="get_data"> + <method name="flip_x"> + <description> + </description> + </method> + <method name="flip_y"> + <description> + </description> + </method> + <method name="generate_mipmaps"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_data" qualifiers="const"> <return type="PoolByteArray"> </return> <description> Return the raw data of the [Image]. </description> </method> - <method name="get_format"> + <method name="get_format" qualifiers="const"> <return type="int"> </return> <description> Return the format of the [Image], one of [Image].FORMAT_*. </description> </method> - <method name="get_height"> + <method name="get_height" qualifiers="const"> <return type="int"> </return> <description> Return the height of the [Image]. </description> </method> - <method name="get_rect"> + <method name="get_mipmap_offset" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="mipmap" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_pixel"> + <return type="Color"> + </return> + <argument index="0" name="x" type="int"> + </argument> + <argument index="1" name="y" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_rect" qualifiers="const"> <return type="Image"> </return> - <argument index="0" name="area" type="Rect2" default="0"> + <argument index="0" name="rect" type="Rect2"> </argument> <description> Return a new [Image] that is a copy of "area" in this [Image]. </description> </method> - <method name="get_used_rect"> + <method name="get_used_rect" qualifiers="const"> <return type="Rect2"> </return> <description> Return the area of this [Image] that is used/visibly colored/opaque. </description> </method> - <method name="get_width"> + <method name="get_width" qualifiers="const"> <return type="int"> </return> <description> Return the width of the [Image]. </description> </method> + <method name="has_mipmaps" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_compressed" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_empty" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_invisible" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="load"> <return type="int"> </return> - <argument index="0" name="path" type="String" default="0"> + <argument index="0" name="path" type="String"> </argument> <description> Load an [Image]. </description> </method> - <method name="resized"> - <return type="Image"> - </return> + <method name="lock"> + <description> + </description> + </method> + <method name="normalmap_to_xy"> + <description> + </description> + </method> + <method name="premultiply_alpha"> + <description> + </description> + </method> + <method name="put_pixel"> <argument index="0" name="x" type="int"> </argument> <argument index="1" name="y" type="int"> </argument> + <argument index="2" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="resize"> + <argument index="0" name="width" type="int"> + </argument> + <argument index="1" name="height" type="int"> + </argument> <argument index="2" name="interpolation" type="int" default="1"> </argument> <description> - Return a new [Image] from this [Image] that is resized to size "x,y" using [Image].INTERPOLATE_*. </description> </method> - <method name="save_png"> + <method name="resize_to_po2"> + <argument index="0" name="square" type="bool" default=""false""> + </argument> + <description> + </description> + </method> + <method name="save_png" qualifiers="const"> <return type="int"> </return> - <argument index="0" name="path" type="String" default="0"> + <argument index="0" name="path" type="String"> </argument> <description> Save this [Image] as a png. </description> </method> + <method name="shrink_x2"> + <description> + </description> + </method> + <method name="srgb_to_linear"> + <description> + </description> + </method> + <method name="unlock"> + <description> + </description> + </method> </methods> + <members> + <member name="data" type="Dictionary" setter="_set_data" getter="_get_data" brief=""> + </member> + </members> <constants> - <constant name="COMPRESS_16BIT" value="0"> - </constant> - <constant name="COMPRESS_S3TC" value="1"> - </constant> - <constant name="COMPRESS_PVRTC2" value="2"> - </constant> - <constant name="COMPRESS_PVRTC4" value="3"> - </constant> - <constant name="COMPRESS_ETC" value="4"> - </constant> - <constant name="COMPRESS_ETC2" value="5"> - </constant> <constant name="FORMAT_L8" value="0"> </constant> <constant name="FORMAT_LA8" value="1"> @@ -18622,27 +19025,27 @@ </constant> <constant name="FORMAT_RGBA8" value="5"> </constant> - <constant name="FORMAT_RGB565" value="6"> + <constant name="FORMAT_RGBA4444" value="6"> </constant> - <constant name="FORMAT_RGBA4444" value="7"> + <constant name="FORMAT_RGBA5551" value="7"> </constant> - <constant name="FORMAT_RGBA5551" value="17"> + <constant name="FORMAT_RF" value="8"> </constant> - <constant name="FORMAT_RF" value="9"> + <constant name="FORMAT_RGF" value="9"> </constant> - <constant name="FORMAT_RGF" value="10"> + <constant name="FORMAT_RGBF" value="10"> </constant> - <constant name="FORMAT_RGBF" value="11"> + <constant name="FORMAT_RGBAF" value="11"> </constant> - <constant name="FORMAT_RGBAF" value="12"> + <constant name="FORMAT_RH" value="12"> </constant> - <constant name="FORMAT_RH" value="13"> + <constant name="FORMAT_RGH" value="13"> </constant> - <constant name="FORMAT_RGH" value="14"> + <constant name="FORMAT_RGBH" value="14"> </constant> - <constant name="FORMAT_RGBH" value="15"> + <constant name="FORMAT_RGBAH" value="15"> </constant> - <constant name="FORMAT_RGBAH" value="16"> + <constant name="FORMAT_RGBE9995" value="16"> </constant> <constant name="FORMAT_DXT1" value="17"> </constant> @@ -18650,9 +19053,9 @@ </constant> <constant name="FORMAT_DXT5" value="19"> </constant> - <constant name="FORMAT_ATI1" value="20"> + <constant name="FORMAT_RGTC_R" value="20"> </constant> - <constant name="FORMAT_ATI2" value="21"> + <constant name="FORMAT_RGTC_RG" value="21"> </constant> <constant name="FORMAT_BPTC_RGBA" value="22"> </constant> @@ -18692,59 +19095,21 @@ </constant> <constant name="INTERPOLATE_CUBIC" value="2"> </constant> - </constants> -</class> -<class name="ImageSkyBox" inherits="SkyBox" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - <method name="get_image_path" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="image" type="int"> - </argument> - <description> - </description> - </method> - <method name="set_image_path"> - <argument index="0" name="image" type="int"> - </argument> - <argument index="1" name="path" type="String"> - </argument> - <description> - </description> - </method> - </methods> - <members> - <member name="image_path_negative_x" type="String" setter="set_image_path" getter="get_image_path" brief=""> - </member> - <member name="image_path_negative_y" type="String" setter="set_image_path" getter="get_image_path" brief=""> - </member> - <member name="image_path_negative_z" type="String" setter="set_image_path" getter="get_image_path" brief=""> - </member> - <member name="image_path_positive_x" type="String" setter="set_image_path" getter="get_image_path" brief=""> - </member> - <member name="image_path_positive_y" type="String" setter="set_image_path" getter="get_image_path" brief=""> - </member> - <member name="image_path_positive_z" type="String" setter="set_image_path" getter="get_image_path" brief=""> - </member> - </members> - <constants> - <constant name="IMAGE_PATH_NEGATIVE_X" value="0"> + <constant name="ALPHA_NONE" value="0"> + </constant> + <constant name="ALPHA_BIT" value="1"> </constant> - <constant name="IMAGE_PATH_POSITIVE_X" value="1"> + <constant name="ALPHA_BLEND" value="2"> </constant> - <constant name="IMAGE_PATH_NEGATIVE_Y" value="2"> + <constant name="COMPRESS_S3TC" value="0"> </constant> - <constant name="IMAGE_PATH_POSITIVE_Y" value="3"> + <constant name="COMPRESS_PVRTC2" value="1"> </constant> - <constant name="IMAGE_PATH_NEGATIVE_Z" value="4"> + <constant name="COMPRESS_PVRTC4" value="2"> </constant> - <constant name="IMAGE_PATH_POSITIVE_Z" value="5"> + <constant name="COMPRESS_ETC" value="3"> </constant> - <constant name="IMAGE_PATH_MAX" value="6"> + <constant name="COMPRESS_ETC2" value="4"> </constant> </constants> </class> @@ -18780,10 +19145,6 @@ Create a new [ImageTexture] from an [Image] with "flags" from [Texture].FLAG_*. </description> </method> - <method name="fix_alpha_edges"> - <description> - </description> - </method> <method name="get_data" qualifiers="const"> <return type="Image"> </return> @@ -18819,14 +19180,6 @@ Load an [ImageTexure]. </description> </method> - <method name="normal_to_xy"> - <description> - </description> - </method> - <method name="premultiply_alpha"> - <description> - </description> - </method> <method name="set_data"> <argument index="0" name="image" type="Image"> </argument> @@ -18854,10 +19207,6 @@ Set the storage type. One of [ImageTexture].STORAGE_*. </description> </method> - <method name="shrink_x2_and_keep_size"> - <description> - </description> - </method> </methods> <constants> <constant name="STORAGE_RAW" value="0"> @@ -19186,7 +19535,7 @@ </description> </method> <method name="parse_input_event"> - <argument index="0" name="event" type="InputEvent"> + <argument index="0" name="event" type="Object"> </argument> <description> </description> @@ -19280,15 +19629,39 @@ <constants> </constants> </class> -<class name="InputEvent" category="Built-In Types"> +<class name="InputEvent" inherits="Resource" category="Core"> <brief_description> - Built-in input event data. </brief_description> <description> - Built-in input event data. InputEvent is a built-in engine datatype, given that it's passed around and used so much. Depending on its type, the members contained can be different, so read the documentation well! Input events can also represent actions (editable from the project settings). </description> <methods> - <method name="is_action"> + <method name="action_match" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="event" type="InputEvent"> + </argument> + <description> + </description> + </method> + <method name="as_text" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_device" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_id" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="is_action" qualifiers="const"> <return type="bool"> </return> <argument index="0" name="action" type="String"> @@ -19297,7 +19670,7 @@ Return if this input event matches a pre-defined action, no matter the type. </description> </method> - <method name="is_action_pressed"> + <method name="is_action_pressed" qualifiers="const"> <return type="bool"> </return> <argument index="0" name="action" type="String"> @@ -19306,7 +19679,7 @@ Return whether the given action is being pressed (and is not an echo event for KEY events). Not relevant for the event types MOUSE_MOTION, SCREEN_DRAG and NONE. </description> </method> - <method name="is_action_released"> + <method name="is_action_released" qualifiers="const"> <return type="bool"> </return> <argument index="0" name="action" type="String"> @@ -19315,1045 +19688,627 @@ Return whether the given action is released (i.e. not pressed). Not relevant for the event types MOUSE_MOTION, SCREEN_DRAG and NONE. </description> </method> - <method name="is_echo"> + <method name="is_action_type" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_echo" qualifiers="const"> <return type="bool"> </return> <description> Return if this input event is an echo event (only for events of type KEY, it will return false for other types). </description> </method> - <method name="is_pressed"> + <method name="is_pressed" qualifiers="const"> <return type="bool"> </return> <description> Return if this input event is pressed. Not relevant for the event types MOUSE_MOTION, SCREEN_DRAG and NONE. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> + <method name="set_device"> + <argument index="0" name="device" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_id"> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="xformed_by" qualifiers="const"> + <return type="InputEvent"> + </return> + <argument index="0" name="xform" type="Transform2D"> </argument> - <argument index="1" name="pressed" type="bool"> + <argument index="1" name="local_ofs" type="Vector2" default="Vector2(0, 0)"> </argument> <description> - Change the input event to an action event of the given name, regardless of its initial type, with the pressed status passed as argument. </description> </method> </methods> - <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). - </member> - </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventAction" category="Built-In Types"> +<class name="InputEventAction" inherits="InputEvent" category="Core"> <brief_description> - Built-in input event type for actions. + Input event type for actions. </brief_description> <description> - Input event type for actions that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_action" qualifiers="const"> + <return type="String"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action, i.e. always true for InputEventAction. </description> </method> - <method name="is_action_pressed"> - <return type="bool"> - </return> - <argument index="0" name="action" type="String"> - </argument> - <description> - Return whether the given action is being pressed. - </description> - </method> - <method name="is_action_released"> - <return type="bool"> - </return> + <method name="set_action"> <argument index="0" name="action" type="String"> </argument> <description> - Return whether the given action is released (i.e. not pressed). - </description> - </method> - <method name="is_echo"> - <return type="bool"> - </return> - <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). </description> </method> - <method name="is_pressed"> - <return type="bool"> - </return> - <description> - Return if this input event is pressed. - </description> - </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> - </argument> - <argument index="1" name="pressed" type="bool"> + <method name="set_pressed"> + <argument index="0" name="pressed" type="bool"> </argument> <description> - Change the input event to an action event of the given name with the pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. + <member name="action" type="String" setter="set_action" getter="get_action" brief=""> </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). + <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" brief=""> </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventJoypadButton" category="Built-In Types"> +<class name="InputEventJoypadButton" inherits="InputEvent" category="Core"> <brief_description> - Built-in input event type for joypad button events. + Input event type for joypad button events. </brief_description> <description> - Input event type for joypad button events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_button_index" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action. </description> </method> - <method name="is_action_pressed"> - <return type="bool"> + <method name="get_pressure" qualifiers="const"> + <return type="float"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. </description> </method> - <method name="is_action_released"> - <return type="bool"> - </return> - <argument index="0" name="action" type="String"> + <method name="set_button_index"> + <argument index="0" name="button_index" type="int"> </argument> <description> - Return whether the given action is released (i.e. not pressed). </description> </method> - <method name="is_echo"> - <return type="bool"> - </return> - <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). - </description> - </method> - <method name="is_pressed"> - <return type="bool"> - </return> + <method name="set_pressed"> + <argument index="0" name="pressed" type="bool"> + </argument> <description> - Return if this input event is pressed. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> - </argument> - <argument index="1" name="pressed" type="bool"> + <method name="set_pressure"> + <argument index="0" name="pressure" type="float"> </argument> <description> - Change the input event to an action event of the given name with the pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="button_index" type="int" setter="" getter="" brief=""> + <member name="button_index" type="int" setter="set_button_index" getter="get_button_index" brief=""> Joypad button identifier, one of the JOY_BUTTON_* constants in [@Global Scope]. </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="pressed" type="bool" setter="" getter="" brief=""> + <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" brief=""> Pressed state of the joypad button. </member> - <member name="pressure" type="float" setter="" getter="" brief=""> + <member name="pressure" type="float" setter="set_pressure" getter="get_pressure" brief=""> Intensity of the button pressure, ranges from 0 to 1.0. </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). - </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventJoypadMotion" category="Built-In Types"> +<class name="InputEventJoypadMotion" inherits="InputEvent" category="Core"> <brief_description> - Built-in input event type for joypad motion/axis events. + Input event type for joypad motion/axis events. </brief_description> <description> - Input event type for joypad motion/axis events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_axis" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> </description> </method> - <method name="is_action_pressed"> - <return type="bool"> + <method name="get_axis_value" qualifiers="const"> + <return type="float"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. </description> </method> - <method name="is_action_released"> - <return type="bool"> - </return> - <argument index="0" name="action" type="String"> + <method name="set_axis"> + <argument index="0" name="axis" type="int"> </argument> <description> - Return whether the given action is released (i.e. not pressed). - </description> - </method> - <method name="is_echo"> - <return type="bool"> - </return> - <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). - </description> - </method> - <method name="is_pressed"> - <return type="bool"> - </return> - <description> - Return if this input event is pressed. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> - </argument> - <argument index="1" name="pressed" type="bool"> + <method name="set_axis_value"> + <argument index="0" name="axis_value" type="float"> </argument> <description> - Change the input event to an action event of the given name with the pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="axis" type="int" setter="" getter="" brief=""> + <member name="axis" type="int" setter="set_axis" getter="get_axis" brief=""> Joypad axis identifier, one of the JOY_AXIS_* constants in [@Global Scope]. </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). - </member> - <member name="value" type="float" setter="" getter="" brief=""> + <member name="axis_value" type="float" setter="set_axis_value" getter="get_axis_value" brief=""> Position of the axis, ranging from -1.0 to 1.0. A value of 0 means that the axis is in its neutral position. </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventKey" category="Built-In Types"> +<class name="InputEventKey" inherits="InputEventWithModifiers" category="Core"> <brief_description> - Built-in input event type for keyboard events. + Input event type for keyboard events. </brief_description> <description> - Input event type for keyboard events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_scancode" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action. </description> </method> - <method name="is_action_pressed"> - <return type="bool"> + <method name="get_scancode_with_modifiers" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. </description> </method> - <method name="is_action_released"> - <return type="bool"> + <method name="get_unicode" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is released (i.e. not pressed). </description> </method> - <method name="is_echo"> - <return type="bool"> - </return> + <method name="set_echo"> + <argument index="0" name="echo" type="bool"> + </argument> <description> - Return if this input event is an echo event. </description> </method> - <method name="is_pressed"> - <return type="bool"> - </return> + <method name="set_pressed"> + <argument index="0" name="pressed" type="bool"> + </argument> <description> - Return if this input event is pressed. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> + <method name="set_scancode"> + <argument index="0" name="scancode" type="int"> </argument> - <argument index="1" name="pressed" type="bool"> + <description> + </description> + </method> + <method name="set_unicode"> + <argument index="0" name="unicode" type="int"> </argument> <description> - Change the input event to an action event of the given name with the pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="alt" type="bool" setter="" getter="" brief=""> - State of the Alt modifier. - </member> - <member name="control" type="bool" setter="" getter="" brief=""> - State of the Ctrl modifier. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="echo" type="bool" setter="" getter="" brief=""> + <member name="echo" type="int" setter="set_echo" getter="is_echo" brief=""> Echo state of the key, i.e. whether it's a repeat event or not. </member> - <member name="meta" type="bool" setter="" getter="" brief=""> - State of the Meta modifier. - </member> - <member name="pressed" type="bool" setter="" getter="" brief=""> + <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" brief=""> Pressed state of the key. </member> - <member name="scancode" type="int" setter="" getter="" brief=""> + <member name="scancode" type="int" setter="set_scancode" getter="get_scancode" brief=""> Scancode of the key, one of the KEY_* constants in [@Global Scope]. </member> - <member name="shift" type="bool" setter="" getter="" brief=""> - State of the Shift modifier. - </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). - </member> - <member name="unicode" type="int" setter="" getter="" brief=""> + <member name="unicode" type="int" setter="set_unicode" getter="get_unicode" brief=""> Unicode identifier of the key (when relevant). </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventMouseButton" category="Built-In Types"> +<class name="InputEventMouse" inherits="InputEventWithModifiers" category="Core"> <brief_description> - Built-in input event type for mouse button events. + Base input event type for mouse events. </brief_description> <description> - Input event type for mouse button events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_button_mask" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action. </description> </method> - <method name="is_action_pressed"> - <return type="bool"> + <method name="get_global_position" qualifiers="const"> + <return type="Vector2"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. </description> </method> - <method name="is_action_released"> - <return type="bool"> + <method name="get_position" qualifiers="const"> + <return type="Vector2"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is released (i.e. not pressed). </description> </method> - <method name="is_echo"> - <return type="bool"> - </return> + <method name="set_button_mask"> + <argument index="0" name="button_mask" type="int"> + </argument> <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). </description> </method> - <method name="is_pressed"> - <return type="bool"> - </return> + <method name="set_global_position"> + <argument index="0" name="global_position" type="Vector2"> + </argument> <description> - Return if this input event is pressed. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> - </argument> - <argument index="1" name="pressed" type="bool"> + <method name="set_position"> + <argument index="0" name="position" type="Vector2"> </argument> <description> - Change the input event to an action event of the given name with the pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="alt" type="bool" setter="" getter="" brief=""> - State of the Alt modifier. - </member> - <member name="button_index" type="int" setter="" getter="" brief=""> - Mouse button identifier, one of the BUTTON_* or BUTTON_WHEEL_* constants in [@Global Scope]. - </member> - <member name="button_mask" type="int" setter="" getter="" brief=""> + <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" brief=""> Mouse button mask identifier, one of or a bitwise combination of the BUTTON_MASK_* constants in [@Global Scope]. </member> - <member name="control" type="bool" setter="" getter="" brief=""> - State of the Control modifier. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="doubleclick" type="bool" setter="" getter="" brief=""> - Whether the event is a double-click. - </member> - <member name="global_pos" type="Vector2" setter="" getter="" brief=""> + <member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position" brief=""> Global position of the mouse click. </member> - <member name="global_x" type="float" setter="" getter="" brief=""> - Global X coordinate of the mouse click. - </member> - <member name="global_y" type="float" setter="" getter="" brief=""> - Global Y coordinate of the mouse click. - </member> - <member name="meta" type="bool" setter="" getter="" brief=""> - State of the Meta modifier. - </member> - <member name="pos" type="Vector2" setter="" getter="" brief=""> + <member name="position" type="Vector2" setter="set_position" getter="get_position" brief=""> Local position of the mouse click. </member> - <member name="pressed" type="bool" setter="" getter="" brief=""> - Pressed state of the mouse button. - </member> - <member name="shift" type="bool" setter="" getter="" brief=""> - State of the Shift modifier. - </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). - </member> - <member name="x" type="float" setter="" getter="" brief=""> - Local X coordinate of the mouse click. - </member> - <member name="y" type="float" setter="" getter="" brief=""> - Local Y coordinate of the mouse click. - </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventMouseMotion" category="Built-In Types"> +<class name="InputEventMouseButton" inherits="InputEventMouse" category="Core"> <brief_description> - Built-in input event type for mouse motion events. + Input event type for mouse button events. </brief_description> <description> - Input event type for mouse motion events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_button_index" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action. </description> </method> - <method name="is_action_pressed"> - <return type="bool"> + <method name="get_factor"> + <return type="float"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. Not relevant for MOUSE_MOTION events, always false. </description> </method> - <method name="is_action_released"> + <method name="is_doubleclick" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is released (i.e. not pressed). Not relevant for MOUSE_MOTION events, can be true or false depending on whether [method is_action] is true. </description> </method> - <method name="is_echo"> - <return type="bool"> - </return> + <method name="set_button_index"> + <argument index="0" name="button_index" type="int"> + </argument> <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). </description> </method> - <method name="is_pressed"> - <return type="bool"> - </return> + <method name="set_doubleclick"> + <argument index="0" name="doubleclick" type="bool"> + </argument> <description> - Return if this input event is pressed. Not relevant for MOUSE_MOTION events, always false. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> + <method name="set_factor"> + <argument index="0" name="factor" type="float"> </argument> - <argument index="1" name="pressed" type="bool"> + <description> + </description> + </method> + <method name="set_pressed"> + <argument index="0" name="pressed" type="bool"> </argument> <description> - Change the input event to an action event of the given name with the (irrelevant for this type) pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="alt" type="bool" setter="" getter="" brief=""> - State of the Alt modifier. - </member> - <member name="button_mask" type="int" setter="" getter="" brief=""> - Mouse button mask identifier, one of or a bitwise combination of the BUTTON_MASK_* constants in [@Global Scope]. - </member> - <member name="control" type="bool" setter="" getter="" brief=""> - State of the Ctrl modifier. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="global_pos" type="Vector2" setter="" getter="" brief=""> - Global position of the mouse pointer. - </member> - <member name="global_x" type="float" setter="" getter="" brief=""> - Global X coordinate of the mouse pointer. + <member name="button_index" type="int" setter="set_button_index" getter="get_button_index" brief=""> + Mouse button identifier, one of the BUTTON_* or BUTTON_WHEEL_* constants in [@Global Scope]. </member> - <member name="global_y" type="float" setter="" getter="" brief=""> - Global Y coordinate of the mouse pointer. + <member name="doubleclick" type="bool" setter="set_doubleclick" getter="is_doubleclick" brief=""> + Whether the event is a double-click. </member> - <member name="meta" type="bool" setter="" getter="" brief=""> - State of the Meta modifier. + <member name="factor" type="float" setter="set_factor" getter="get_factor" brief=""> </member> - <member name="pos" type="Vector2" setter="" getter="" brief=""> - Local position of the mouse pointer. + <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" brief=""> + Pressed state of the mouse button. </member> - <member name="relative_pos" type="Vector2" setter="" getter="" brief=""> + </members> + <constants> + </constants> +</class> +<class name="InputEventMouseMotion" inherits="InputEventMouse" category="Core"> + <brief_description> + Input event type for mouse motion events. + </brief_description> + <description> + </description> + <methods> + <method name="get_relative" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="get_speed" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="set_relative"> + <argument index="0" name="relative" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="set_speed"> + <argument index="0" name="speed" type="Vector2"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" brief=""> Position of the mouse pointer relative to the previous mouse position. </member> - <member name="relative_x" type="float" setter="" getter="" brief=""> - X coordinate of the mouse pointer relative to the previous mouse position. - </member> - <member name="relative_y" type="float" setter="" getter="" brief=""> - Y coordinate of the mouse pointer relative to the previous mouse position. - </member> - <member name="shift" type="bool" setter="" getter="" brief=""> - State of the Shift modifier. - </member> - <member name="speed" type="Vector2" setter="" getter="" brief=""> + <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" brief=""> Speed of the mouse pointer. </member> - <member name="speed_x" type="float" setter="" getter="" brief=""> - Speed of the mouse pointer on the X axis. - </member> - <member name="speed_y" type="float" setter="" getter="" brief=""> - Speed of the mouse pointer on the Y axis. - </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). - </member> - <member name="x" type="float" setter="" getter="" brief=""> - Local X coordinate of the mouse pointer. - </member> - <member name="y" type="float" setter="" getter="" brief=""> - Local Y coordinate of the mouse pointer. - </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventScreenDrag" category="Built-In Types"> +<class name="InputEventScreenDrag" inherits="InputEvent" category="Core"> <brief_description> - Built-in input event type for screen drag events. + Input event type for screen drag events. </brief_description> <description> - Input event type for screen drag events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> - <return type="bool"> + <method name="get_index" qualifiers="const"> + <return type="int"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action. </description> </method> - <method name="is_action_pressed"> - <return type="bool"> + <method name="get_position" qualifiers="const"> + <return type="Vector2"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. Not relevant for SCREEN_DRAG events, always false. </description> </method> - <method name="is_action_released"> - <return type="bool"> + <method name="get_relative" qualifiers="const"> + <return type="Vector2"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is released (i.e. not pressed). Not relevant for SCREEN_DRAG events, can be true or false depending on whether [method is_action] is true. </description> </method> - <method name="is_echo"> - <return type="bool"> + <method name="get_speed" qualifiers="const"> + <return type="Vector2"> </return> <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). </description> </method> - <method name="is_pressed"> - <return type="bool"> - </return> + <method name="set_index"> + <argument index="0" name="index" type="int"> + </argument> <description> - Return if this input event is pressed. Not relevant for SCREEN_DRAG events, always false. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> + <method name="set_position"> + <argument index="0" name="position" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="set_relative"> + <argument index="0" name="relative" type="Vector2"> </argument> - <argument index="1" name="pressed" type="bool"> + <description> + </description> + </method> + <method name="set_speed"> + <argument index="0" name="speed" type="Vector2"> </argument> <description> - Change the input event to an action event of the given name with the (irrelevant for this type) pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="index" type="int" setter="" getter="" brief=""> + <member name="index" type="int" setter="set_index" getter="get_index" brief=""> Drag event index in the case of a multi-drag event. </member> - <member name="pos" type="Vector2" setter="" getter="" brief=""> + <member name="position" type="Vector2" setter="set_position" getter="get_position" brief=""> Position of the drag event. </member> - <member name="relative_pos" type="Vector2" setter="" getter="" brief=""> + <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" brief=""> Position of the drag event relative to its start position. </member> - <member name="relative_x" type="float" setter="" getter="" brief=""> - X coordinate of the drag event relative to its start position. - </member> - <member name="relative_y" type="float" setter="" getter="" brief=""> - Y coordinate of the drag event relative to its start position. - </member> - <member name="speed" type="Vector2" setter="" getter="" brief=""> + <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" brief=""> Speed of the drag event. </member> - <member name="speed_x" type="float" setter="" getter="" brief=""> - Speed of the drag event on the X axis. - </member> - <member name="speed_y" type="float" setter="" getter="" brief=""> - Speed of the drag event on the Y axis. - </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). + </members> + <constants> + </constants> +</class> +<class name="InputEventScreenTouch" inherits="InputEvent" category="Core"> + <brief_description> + Input event type for screen touch events. + </brief_description> + <description> + </description> + <methods> + <method name="get_index" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_position" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="set_index"> + <argument index="0" name="index" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_position"> + <argument index="0" name="pos" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="set_pressed"> + <argument index="0" name="pressed" type="bool"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="index" type="int" setter="set_index" getter="get_index" brief=""> + Touch event index in the case of a multi-touch event. </member> - <member name="x" type="float" setter="" getter="" brief=""> - X coordinate of the drag event. + <member name="position" type="Vector2" setter="set_position" getter="get_position" brief=""> + Position of the touch event. </member> - <member name="y" type="float" setter="" getter="" brief=""> - Y coordinate of the drag event. + <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" brief=""> + Pressed state of the touch event. </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> -<class name="InputEventScreenTouch" category="Built-In Types"> +<class name="InputEventWithModifiers" inherits="InputEvent" category="Core"> <brief_description> - Built-in input event type for touchscreen drag events. + Base class for input events with modifiers. </brief_description> <description> - Input event type for touchscreen drag events that extends the global [InputEvent] type. </description> <methods> - <method name="is_action"> + <method name="get_alt" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return if this input event matches a pre-defined action. </description> </method> - <method name="is_action_pressed"> + <method name="get_command" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is being pressed. </description> </method> - <method name="is_action_released"> + <method name="get_control" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="action" type="String"> - </argument> <description> - Return whether the given action is released (i.e. not pressed). </description> </method> - <method name="is_echo"> + <method name="get_metakey" qualifiers="const"> <return type="bool"> </return> <description> - Return if this input event is an echo event (only for events of type KEY, i.e. always false for this type). </description> </method> - <method name="is_pressed"> + <method name="get_shift" qualifiers="const"> <return type="bool"> </return> <description> - Return if this input event is pressed. </description> </method> - <method name="set_as_action"> - <argument index="0" name="action" type="String"> + <method name="set_alt"> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_command"> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_control"> + <argument index="0" name="enable" type="bool"> </argument> - <argument index="1" name="pressed" type="bool"> + <description> + </description> + </method> + <method name="set_metakey"> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_shift"> + <argument index="0" name="enable" type="bool"> </argument> <description> - Change the input event to an action event of the given name with the pressed status passed as argument. </description> </method> </methods> <members> - <member name="ID" type="int" setter="" getter="" brief=""> - Event identifier, positive integer increased at each new event. - </member> - <member name="device" type="int" setter="" getter="" brief=""> - Device identifier. - </member> - <member name="index" type="int" setter="" getter="" brief=""> - Touch event index in the case of a multi-touch event. - </member> - <member name="pos" type="Vector2" setter="" getter="" brief=""> - Position of the touch event. + <member name="alt" type="bool" setter="set_alt" getter="get_alt" brief=""> + State of the Alt modifier. </member> - <member name="pressed" type="bool" setter="" getter="" brief=""> - Pressed state of the touch event. + <member name="command" type="bool" setter="set_command" getter="get_command" brief=""> + State of the Command modifier. </member> - <member name="type" type="int" setter="" getter="" brief=""> - Type of event (one of the [InputEvent] constants). + <member name="control" type="bool" setter="set_control" getter="get_control" brief=""> + State of the Ctrl modifier. </member> - <member name="x" type="float" setter="" getter="" brief=""> - X coordinate of the touch event. + <member name="meta" type="bool" setter="set_metakey" getter="get_metakey" brief=""> + State of the Meta modifier. </member> - <member name="y" type="float" setter="" getter="" brief=""> - Y coordinate of the touch event. + <member name="shift" type="bool" setter="set_shift" getter="get_shift" brief=""> + State of the Shift modifier. </member> </members> <constants> - <constant name="NONE" value="0"> - Empty input event. - </constant> - <constant name="KEY" value="1"> - Key event. - </constant> - <constant name="MOUSE_MOTION" value="2"> - Mouse motion event. - </constant> - <constant name="MOUSE_BUTTON" value="3"> - Mouse button event. - </constant> - <constant name="JOYPAD_MOTION" value="4"> - Joypad motion event. - </constant> - <constant name="JOYPAD_BUTTON" value="5"> - Joypad button event. - </constant> - <constant name="SCREEN_TOUCH" value="6"> - Screen touch event. - </constant> - <constant name="SCREEN_DRAG" value="7"> - Screen drag event. - </constant> - <constant name="ACTION" value="8"> - Pre-defined action event (see [InputMap]). - </constant> </constants> </class> <class name="InputMap" inherits="Object" category="Core"> @@ -20361,13 +20316,12 @@ Singleton that manages actions. </brief_description> <description> - Singleton that manages actions. InputMap has a list of the actions used in Ref<InputEvent>, which can be modified. </description> <methods> <method name="action_add_event"> <argument index="0" name="action" type="String"> </argument> - <argument index="1" name="event" type="InputEvent"> + <argument index="1" name="event" type="Object"> </argument> <description> Add an [InputEvent] to an action. This [InputEvent] will trigger the action. @@ -20376,7 +20330,7 @@ <method name="action_erase_event"> <argument index="0" name="action" type="String"> </argument> - <argument index="1" name="event" type="InputEvent"> + <argument index="1" name="event" type="Object"> </argument> <description> Remove an [InputEvent] from an action. @@ -20387,7 +20341,7 @@ </return> <argument index="0" name="action" type="String"> </argument> - <argument index="1" name="event" type="InputEvent"> + <argument index="1" name="event" type="Object"> </argument> <description> Whether an action has an [InputEvent] associated with it. @@ -20410,7 +20364,7 @@ <method name="event_is_action" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="event" type="InputEvent"> + <argument index="0" name="event" type="Object"> </argument> <argument index="1" name="action" type="String"> </argument> @@ -20418,24 +20372,6 @@ Return whether the given event is part of an existing action. This method ignores keyboard modifiers if the given [InputEvent] is not pressed (for proper release detection). See [method action_has_event] if you don't want this behavior. </description> </method> - <method name="get_action_from_id" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <description> - Return the action corresponding to the identifier. - </description> - </method> - <method name="get_action_id" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="action" type="String"> - </argument> - <description> - Return the identifier of the given action. - </description> - </method> <method name="get_action_list"> <return type="Array"> </return> @@ -21259,6 +21195,18 @@ Return the point in space where the body is touching another. If there is no collision, this method will return (0,0,0), so collisions must be checked first with [method is_colliding]. </description> </method> + <method name="get_move_and_slide_colliders" qualifiers="const"> + <return type="Array"> + </return> + <description> + </description> + </method> + <method name="get_travel" qualifiers="const"> + <return type="Vector3"> + </return> + <description> + </description> + </method> <method name="is_colliding" qualifiers="const"> <return type="bool"> </return> @@ -21266,6 +21214,24 @@ Return whether the body is colliding with another. </description> </method> + <method name="is_move_and_slide_on_ceiling" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_move_and_slide_on_floor" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="is_move_and_slide_on_wall" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="move"> <return type="Vector3"> </return> @@ -21275,6 +21241,26 @@ Move the body in the given direction, stopping if there is an obstacle. The returned vector is how much movement was remaining before being stopped. </description> </method> + <method name="move_and_slide"> + <return type="Vector3"> + </return> + <argument index="0" name="linear_velocity" type="Vector3"> + </argument> + <argument index="1" name="floor_normal" type="Vector3" default="Vector3(0, 0, 0)"> + </argument> + <argument index="2" name="ceil_normal" type="Vector3" default="Vector3(0, 0, 0)"> + </argument> + <argument index="3" name="slope_stop_min_velocity" type="float" default="5"> + </argument> + <argument index="4" name="max_bounces" type="int" default="4"> + </argument> + <argument index="5" name="floor_max_angle" type="float" default="0.785398"> + </argument> + <argument index="6" name="ceil_max_angle" type="float" default="0.785398"> + </argument> + <description> + </description> + </method> <method name="move_to"> <return type="Vector3"> </return> @@ -21284,6 +21270,10 @@ Move the body to the given position. This is not a teleport, and the body will stop if there is an obstacle. The returned vector is how much movement was remaining before being stopped. </description> </method> + <method name="revert_motion"> + <description> + </description> + </method> <method name="set_collide_with_character_bodies"> <argument index="0" name="enable" type="bool"> </argument> @@ -21968,9 +21958,7 @@ </constant> <constant name="PARAM_SHADOW_BIAS" value="12"> </constant> - <constant name="PARAM_SHADOW_BIAS_SPLIT_SCALE" value="13"> - </constant> - <constant name="PARAM_MAX" value="14"> + <constant name="PARAM_MAX" value="13"> </constant> </constants> </class> @@ -22062,6 +22050,12 @@ <description> </description> </method> + <method name="get_shadow_smooth" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_texture" qualifiers="const"> <return type="Object"> </return> @@ -22219,6 +22213,12 @@ <description> </description> </method> + <method name="set_shadow_smooth"> + <argument index="0" name="smooth" type="float"> + </argument> + <description> + </description> + </method> <method name="set_texture"> <argument index="0" name="texture" type="Object"> </argument> @@ -22290,6 +22290,8 @@ </member> <member name="shadow_filter" type="float" setter="set_shadow_filter" getter="get_shadow_filter" brief=""> </member> + <member name="shadow_filter_smooth" type="float" setter="set_shadow_smooth" getter="get_shadow_smooth" brief=""> + </member> <member name="shadow_gradient_length" type="float" setter="set_shadow_gradient_length" getter="get_shadow_gradient_length" brief=""> </member> <member name="shadow_item_cull_mask" type="int" setter="set_item_shadow_cull_mask" getter="get_item_shadow_cull_mask" brief=""> @@ -22538,7 +22540,7 @@ </member> <member name="end_cap_mode" type="int" setter="set_end_cap_mode" getter="get_end_cap_mode" brief=""> </member> - <member name="gradient" type="ColorRamp" setter="set_gradient" getter="get_gradient" brief=""> + <member name="gradient" type="Gradient" setter="set_gradient" getter="get_gradient" brief=""> </member> <member name="joint_mode" type="int" setter="set_joint_mode" getter="get_joint_mode" brief=""> </member> @@ -23059,7 +23061,7 @@ </description> </method> <method name="input_event"> - <argument index="0" name="ev" type="InputEvent"> + <argument index="0" name="ev" type="Object"> </argument> <description> </description> @@ -23249,244 +23251,40 @@ Mesh is a type of [Resource] that contains vertex-array based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials. </description> <methods> - <method name="add_blend_shape"> - <argument index="0" name="name" type="String"> - </argument> - <description> - </description> - </method> - <method name="add_surface_from_arrays"> - <argument index="0" name="primitive" type="int"> - </argument> - <argument index="1" name="arrays" type="Array"> - </argument> - <argument index="2" name="blend_shapes" type="Array" default="Array()"> - </argument> - <argument index="3" name="compress_flags" type="int" default="97792"> - </argument> - <description> - Create a new surface ([method get_surface_count] that will become surf_idx for this. - Surfaces are created to be rendered using a "primitive", which may be PRIMITIVE_POINTS, PRIMITIVE_LINES, PRIMITIVE_LINE_STRIP, PRIMITIVE_LINE_LOOP, PRIMITIVE_TRIANGLES, PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_TRIANGLE_FAN. (As a note, when using indices, it is recommended to only use just points, lines or triangles). - (might be obsolete) The format of a surface determines which arrays it will allocate and hold, so "format" is a combination of ARRAY_FORMAT_* mask constants ORed together. ARRAY_FORMAT_VERTEX must be always present. "array_len" determines the amount of vertices in the array (not primitives!). if ARRAY_FORMAT_INDEX is in the format mask, then it means that an index array will be allocated and "index_array_len" must be passed - </description> - </method> - <method name="center_geometry"> - <description> - </description> - </method> - <method name="clear_blend_shapes"> - <description> - </description> - </method> - <method name="get_blend_shape_count" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> - <method name="get_blend_shape_mode" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> - <method name="get_blend_shape_name" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <description> - </description> - </method> - <method name="get_custom_aabb" qualifiers="const"> - <return type="Rect3"> - </return> - <description> - </description> - </method> - <method name="get_surface_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Return the amount of surfaces that the [Mesh] holds. - </description> - </method> - <method name="regen_normalmaps"> - <description> - </description> - </method> - <method name="set_blend_shape_mode"> - <argument index="0" name="mode" type="int"> - </argument> - <description> - </description> - </method> - <method name="set_custom_aabb"> - <argument index="0" name="aabb" type="Rect3"> - </argument> - <description> - </description> - </method> - <method name="surface_get_array_index_len" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="surf_idx" type="int"> - </argument> - <description> - Return the length in indices of the index array in the requested surface (see [method add_surface]). - </description> - </method> - <method name="surface_get_array_len" qualifiers="const"> - <return type="int"> + <method name="create_convex_shape" qualifiers="const"> + <return type="Shape"> </return> - <argument index="0" name="surf_idx" type="int"> - </argument> <description> - Return the length in vertices of the vertex array in the requested surface (see [method add_surface]). </description> </method> - <method name="surface_get_format" qualifiers="const"> - <return type="int"> + <method name="create_outline" qualifiers="const"> + <return type="ArrayMesh"> </return> - <argument index="0" name="surf_idx" type="int"> + <argument index="0" name="margin" type="float"> </argument> <description> - Return the format mask of the requested surface (see [method add_surface]). </description> </method> - <method name="surface_get_material" qualifiers="const"> - <return type="Material"> + <method name="create_trimesh_shape" qualifiers="const"> + <return type="Shape"> </return> - <argument index="0" name="surf_idx" type="int"> - </argument> <description> - Return a [Material] in a given surface. Surface is rendered using this material. </description> </method> - <method name="surface_get_name" qualifiers="const"> - <return type="String"> + <method name="generate_triangle_mesh" qualifiers="const"> + <return type="TriangleMesh"> </return> - <argument index="0" name="surf_idx" type="int"> - </argument> <description> </description> </method> - <method name="surface_get_primitive_type" qualifiers="const"> - <return type="int"> + <method name="get_faces" qualifiers="const"> + <return type="PoolVector3Array"> </return> - <argument index="0" name="surf_idx" type="int"> - </argument> - <description> - Return the primitive type of the requested surface (see [method add_surface]). - </description> - </method> - <method name="surface_remove"> - <argument index="0" name="surf_idx" type="int"> - </argument> - <description> - Remove a surface at position surf_idx, shifting greater surfaces one surf_idx slot down. - </description> - </method> - <method name="surface_set_material"> - <argument index="0" name="surf_idx" type="int"> - </argument> - <argument index="1" name="material" type="Material"> - </argument> - <description> - Set a [Material] for a given surface. Surface will be rendered using this material. - </description> - </method> - <method name="surface_set_name"> - <argument index="0" name="surf_idx" type="int"> - </argument> - <argument index="1" name="name" type="String"> - </argument> <description> </description> </method> </methods> <constants> - <constant name="NO_INDEX_ARRAY" value="-1"> - Default value used for index_array_len when no indices are present. - </constant> - <constant name="ARRAY_WEIGHTS_SIZE" value="4"> - Amount of weights/bone indices per vertex (always 4). - </constant> - <constant name="ARRAY_VERTEX" value="0"> - Vertex array (array of [Vector3] vertices). - </constant> - <constant name="ARRAY_NORMAL" value="1"> - Normal array (array of [Vector3] normals). - </constant> - <constant name="ARRAY_TANGENT" value="2"> - Tangent array, array of groups of 4 floats. first 3 floats determine the tangent, and the last the binormal direction as -1 or 1. - </constant> - <constant name="ARRAY_COLOR" value="3"> - Vertex array (array of [Color] colors). - </constant> - <constant name="ARRAY_TEX_UV" value="4"> - UV array (array of [Vector3] UVs or float array of groups of 2 floats (u,v)). - </constant> - <constant name="ARRAY_TEX_UV2" value="5"> - Second UV array (array of [Vector3] UVs or float array of groups of 2 floats (u,v)). - </constant> - <constant name="ARRAY_BONES" value="6"> - Array of bone indices, as a float array. Each element in groups of 4 floats. - </constant> - <constant name="ARRAY_WEIGHTS" value="7"> - Array of bone weights, as a float array. Each element in groups of 4 floats. - </constant> - <constant name="ARRAY_INDEX" value="8"> - Array of integers, used as indices referencing vertices. No index can be beyond the vertex array size. - </constant> - <constant name="ARRAY_FORMAT_VERTEX" value="1"> - Array format will include vertices (mandatory). - </constant> - <constant name="ARRAY_FORMAT_NORMAL" value="2"> - Array format will include normals - </constant> - <constant name="ARRAY_FORMAT_TANGENT" value="4"> - Array format will include tangents - </constant> - <constant name="ARRAY_FORMAT_COLOR" value="8"> - Array format will include a color array. - </constant> - <constant name="ARRAY_FORMAT_TEX_UV" value="16"> - Array format will include UVs. - </constant> - <constant name="ARRAY_FORMAT_TEX_UV2" value="32"> - Array format will include another set of UVs. - </constant> - <constant name="ARRAY_FORMAT_BONES" value="64"> - Array format will include bone indices. - </constant> - <constant name="ARRAY_FORMAT_WEIGHTS" value="128"> - Array format will include bone weights. - </constant> - <constant name="ARRAY_FORMAT_INDEX" value="256"> - Index array will be used. - </constant> - <constant name="PRIMITIVE_POINTS" value="0"> - Render array as points (one vertex equals one point). - </constant> - <constant name="PRIMITIVE_LINES" value="1"> - Render array as lines (every two vertices a line is created). - </constant> - <constant name="PRIMITIVE_LINE_STRIP" value="2"> - Render array as line strip. - </constant> - <constant name="PRIMITIVE_LINE_LOOP" value="3"> - Render array as line loop (like line strip, but closed). - </constant> - <constant name="PRIMITIVE_TRIANGLES" value="4"> - Render array as triangles (every three vertices a triangle is created). - </constant> - <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5"> - Render array as triangle strips. - </constant> - <constant name="PRIMITIVE_TRIANGLE_FAN" value="6"> - Render array as triangle fans. - </constant> </constants> </class> <class name="MeshDataTool" inherits="Reference" category="Core"> @@ -24779,12 +24577,6 @@ </description> </method> <method name="Nil"> - <argument index="0" name="from" type="InputEvent"> - </argument> - <description> - </description> - </method> - <method name="Nil"> <argument index="0" name="from" type="Object"> </argument> <description> @@ -24803,12 +24595,6 @@ </description> </method> <method name="Nil"> - <argument index="0" name="from" type="Image"> - </argument> - <description> - </description> - </method> - <method name="Nil"> <argument index="0" name="from" type="Color"> </argument> <description> @@ -25022,8 +24808,6 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> - Called for every input event. - It has to be enabled with [method set_process_input] or the corresponding property in the inspector. </description> </method> <method name="_process" qualifiers="virtual"> @@ -25045,16 +24829,12 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> - Called for every input event that has not already been handled by another node. - It has to be enabled with [method set_process_unhandled_input] or the corresponding property in the inspector. </description> </method> <method name="_unhandled_key_input" qualifiers="virtual"> - <argument index="0" name="key_event" type="InputEvent"> + <argument index="0" name="event" type="InputEventKey"> </argument> <description> - Called for every [i]key[/i] input event that has not already been handled by another node. - It has to be enabled with [method set_process_unhandled_key_input] or the corresponding property in the inspector. </description> </method> <method name="add_child"> @@ -26138,7 +25918,7 @@ </argument> <argument index="2" name="blocking" type="bool"> </argument> - <argument index="3" name="output" type="Array" default="Array()"> + <argument index="3" name="output" type="Array" default="[]"> </argument> <description> Execute the binary file in given path, optionally blocking until it returns. A process ID is returned. @@ -26652,7 +26432,7 @@ </description> </method> <method name="set_icon"> - <argument index="0" name="icon" type="Image"> + <argument index="0" name="icon" type="Object"> </argument> <description> </description> @@ -26902,7 +26682,7 @@ <method name="add_user_signal"> <argument index="0" name="signal" type="String"> </argument> - <argument index="1" name="arguments" type="Array" default="Array()"> + <argument index="1" name="arguments" type="Array" default="[]"> </argument> <description> Add a user signal (can be added anytime). Arguments are optional, but can be added as an array of dictionaries, each containing "name" and "type" (from [@Global Scope] TYPE_*). @@ -26948,7 +26728,7 @@ </argument> <argument index="2" name="method" type="String"> </argument> - <argument index="3" name="binds" type="Array" default="Array()"> + <argument index="3" name="binds" type="Array" default="[]"> </argument> <argument index="4" name="flags" type="int" default="0"> </argument> @@ -27260,7 +27040,7 @@ OmniDirectional Light, such as a light bulb or a candle. </brief_description> <description> - An OmniDirectional light is a type of [Light] node that emits lights in all directions. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light]. TODO: Image of an omnilight. + An OmniDirectional light is a type of [Light] node that emits lights in all directions. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light]. </description> <methods> <method name="get_shadow_detail" qualifiers="const"> @@ -27629,7 +27409,7 @@ <method name="instance" qualifiers="const"> <return type="Node"> </return> - <argument index="0" name="edit_state" type="int" default="false"> + <argument index="0" name="edit_state" type="int" default="0"> </argument> <description> </description> @@ -27842,6 +27622,32 @@ </theme_item> </theme_items> </class> +<class name="PanoramaSky" inherits="Sky" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_panorama" qualifiers="const"> + <return type="Texture"> + </return> + <description> + </description> + </method> + <method name="set_panorama"> + <argument index="0" name="texture" type="Texture"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="panorama" type="Texture" setter="set_panorama" getter="get_panorama" brief=""> + </member> + </members> + <constants> + </constants> +</class> <class name="ParallaxBackground" inherits="CanvasLayer" category="Core"> <brief_description> A node used to create a parallax scrolling background. @@ -28112,14 +27918,14 @@ <description> </description> <methods> - <method name="get_amount" qualifiers="const"> - <return type="int"> + <method name="capture_aabb" qualifiers="const"> + <return type="Rect3"> </return> <description> </description> </method> - <method name="get_custom_aabb" qualifiers="const"> - <return type="Rect3"> + <method name="get_amount" qualifiers="const"> + <return type="int"> </return> <description> </description> @@ -28162,12 +27968,6 @@ <description> </description> </method> - <method name="get_gravity" qualifiers="const"> - <return type="Vector3"> - </return> - <description> - </description> - </method> <method name="get_lifetime" qualifiers="const"> <return type="float"> </return> @@ -28192,12 +27992,24 @@ <description> </description> </method> + <method name="get_speed_scale" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_use_local_coordinates" qualifiers="const"> <return type="bool"> </return> <description> </description> </method> + <method name="get_visibility_aabb" qualifiers="const"> + <return type="Rect3"> + </return> + <description> + </description> + </method> <method name="is_emitting" qualifiers="const"> <return type="bool"> </return> @@ -28210,12 +28022,6 @@ <description> </description> </method> - <method name="set_custom_aabb"> - <argument index="0" name="aabb" type="Rect3"> - </argument> - <description> - </description> - </method> <method name="set_draw_order"> <argument index="0" name="order" type="int"> </argument> @@ -28260,12 +28066,6 @@ <description> </description> </method> - <method name="set_gravity"> - <argument index="0" name="accel_vec" type="Vector3"> - </argument> - <description> - </description> - </method> <method name="set_lifetime"> <argument index="0" name="secs" type="float"> </argument> @@ -28290,18 +28090,28 @@ <description> </description> </method> + <method name="set_speed_scale"> + <argument index="0" name="scale" type="float"> + </argument> + <description> + </description> + </method> <method name="set_use_local_coordinates"> <argument index="0" name="enable" type="bool"> </argument> <description> </description> </method> + <method name="set_visibility_aabb"> + <argument index="0" name="aabb" type="Rect3"> + </argument> + <description> + </description> + </method> </methods> <members> <member name="amount" type="int" setter="set_amount" getter="get_amount" brief=""> </member> - <member name="custom_aabb" type="Rect3" setter="set_custom_aabb" getter="get_custom_aabb" brief=""> - </member> <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" brief=""> </member> <member name="draw_pass_1" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh" brief=""> @@ -28322,8 +28132,6 @@ </member> <member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" brief=""> </member> - <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" brief=""> - </member> <member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" brief=""> </member> <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" brief=""> @@ -28334,6 +28142,10 @@ </member> <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" brief=""> </member> + <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" brief=""> + </member> + <member name="visibility_aabb" type="Rect3" setter="set_visibility_aabb" getter="get_visibility_aabb" brief=""> + </member> </members> <constants> <constant name="DRAW_ORDER_INDEX" value="0"> @@ -28390,13 +28202,6 @@ <description> </description> </method> - <method name="get_color_ramp" qualifiers="const"> - <return type="ColorRamp"> - </return> - <description> - Returns the [ColorRamp] used to tint each particle - </description> - </method> <method name="get_emission_half_extents" qualifiers="const"> <return type="Vector2"> </return> @@ -28430,6 +28235,13 @@ <description> </description> </method> + <method name="get_gradient" qualifiers="const"> + <return type="Gradient"> + </return> + <description> + Returns the [Gradient] used to tint each particle. + </description> + </method> <method name="get_h_frames" qualifiers="const"> <return type="int"> </return> @@ -28570,15 +28382,6 @@ <description> </description> </method> - <method name="set_color_ramp"> - <return type="ColorRamp"> - </return> - <argument index="0" name="color_ramp" type="Object"> - </argument> - <description> - Sets the [ColorRamp] used to tint each particle. Particle will be tinted according to their lifetimes. - </description> - </method> <method name="set_emission_half_extents"> <argument index="0" name="extents" type="Vector2"> </argument> @@ -28631,6 +28434,15 @@ <description> </description> </method> + <method name="set_gradient"> + <return type="Gradient"> + </return> + <argument index="0" name="gradient" type="Object"> + </argument> + <description> + Sets the [Gradient] used to tint each particle. Particle will be tinted according to their lifetimes. + </description> + </method> <method name="set_h_frames"> <argument index="0" name="enable" type="int"> </argument> @@ -28712,7 +28524,7 @@ <members> <member name="color/color" type="Color" setter="set_color" getter="get_color" brief=""> </member> - <member name="color/color_ramp" type="ColorRamp" setter="set_color_ramp" getter="get_color_ramp" brief=""> + <member name="color/color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp" brief=""> </member> <member name="color_phases/count" type="int" setter="set_color_phases" getter="get_color_phases" brief=""> </member> @@ -28954,6 +28766,12 @@ <description> </description> </method> + <method name="get_gravity" qualifiers="const"> + <return type="Vector3"> + </return> + <description> + </description> + </method> <method name="get_param" qualifiers="const"> <return type="float"> </return> @@ -29064,6 +28882,12 @@ <description> </description> </method> + <method name="set_gravity"> + <argument index="0" name="accel_vec" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="set_param"> <argument index="0" name="param" type="int"> </argument> @@ -29166,6 +28990,8 @@ </member> <member name="flatness" type="float" setter="set_flatness" getter="get_flatness" brief=""> </member> + <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" brief=""> + </member> <member name="hue_variation" type="float" setter="set_param" getter="get_param" brief=""> </member> <member name="hue_variation_curve" type="CurveTexture" setter="set_param_texture" getter="get_param_texture" brief=""> @@ -29919,9 +29745,9 @@ </argument> <argument index="1" name="max_results" type="int" default="32"> </argument> - <argument index="2" name="exclude" type="Array" default="Array()"> + <argument index="2" name="exclude" type="Array" default="[]"> </argument> - <argument index="3" name="layer_mask" type="int" default="2147483647"> + <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> <argument index="4" name="type_mask" type="int" default="15"> </argument> @@ -29942,9 +29768,9 @@ </argument> <argument index="1" name="to" type="Vector2"> </argument> - <argument index="2" name="exclude" type="Array" default="Array()"> + <argument index="2" name="exclude" type="Array" default="[]"> </argument> - <argument index="3" name="layer_mask" type="int" default="2147483647"> + <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> <argument index="4" name="type_mask" type="int" default="15"> </argument> @@ -30127,22 +29953,22 @@ Remove a shape from an area. It does not delete the shape, so it can be reassigned later. </description> </method> - <method name="area_set_collision_mask"> + <method name="area_set_collision_layer"> <argument index="0" name="area" type="RID"> </argument> - <argument index="1" name="mask" type="int"> + <argument index="1" name="layer" type="int"> </argument> <description> - Set which physics layers the area will monitor. + Assign the area to one or many physics layers. </description> </method> - <method name="area_set_layer_mask"> + <method name="area_set_collision_mask"> <argument index="0" name="area" type="RID"> </argument> <argument index="1" name="mask" type="int"> </argument> <description> - Assign the area to one or many physics layers. + Set which physics layers the area will monitor. </description> </method> <method name="area_set_monitor_callback"> @@ -30290,31 +30116,31 @@ Create a physics body. The first parameter can be any value from constants BODY_MODE*, for the type of body created. Additionally, the body can be created in sleeping state to save processing time. </description> </method> - <method name="body_get_collision_mask" qualifiers="const"> + <method name="body_get_collision_layer" qualifiers="const"> <return type="int"> </return> <argument index="0" name="body" type="RID"> </argument> <description> - Return the physics layer or layers a body can collide with. + Return the physics layer or layers a body belongs to. </description> </method> - <method name="body_get_continuous_collision_detection_mode" qualifiers="const"> + <method name="body_get_collision_mask" qualifiers="const"> <return type="int"> </return> <argument index="0" name="body" type="RID"> </argument> <description> - Return the continuous collision detection mode. + Return the physics layer or layers a body can collide with. </description> </method> - <method name="body_get_layer_mask" qualifiers="const"> + <method name="body_get_continuous_collision_detection_mode" qualifiers="const"> <return type="int"> </return> <argument index="0" name="body" type="RID"> </argument> <description> - Return the physics layer or layers a body belongs to. + Return the continuous collision detection mode. </description> </method> <method name="body_get_max_contacts_reported" qualifiers="const"> @@ -30478,6 +30304,15 @@ Set an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior. </description> </method> + <method name="body_set_collision_layer"> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="layer" type="int"> + </argument> + <description> + Set the physics layer or layers a body belongs to. + </description> + </method> <method name="body_set_collision_mask"> <argument index="0" name="body" type="RID"> </argument> @@ -30510,15 +30345,6 @@ Set the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force integration]). </description> </method> - <method name="body_set_layer_mask"> - <argument index="0" name="body" type="RID"> - </argument> - <argument index="1" name="mask" type="int"> - </argument> - <description> - Set the physics layer or layers a body belongs to. - </description> - </method> <method name="body_set_max_contacts_reported"> <argument index="0" name="body" type="RID"> </argument> @@ -30665,7 +30491,7 @@ </argument> <argument index="2" name="body_a" type="RID"> </argument> - <argument index="3" name="body_b" type="RID" default="RID()"> + <argument index="3" name="body_b" type="RID" default="[RID]"> </argument> <description> Create a damped spring joint between two bodies. If not specified, the second body is assumed to be the joint itself. @@ -30718,9 +30544,9 @@ </argument> <argument index="2" name="anchor_b" type="Vector2"> </argument> - <argument index="3" name="body_a" type="RID" default="RID()"> + <argument index="3" name="body_a" type="RID" default="[RID]"> </argument> - <argument index="4" name="body_b" type="RID" default="RID()"> + <argument index="4" name="body_b" type="RID" default="[RID]"> </argument> <description> Create a groove joint between two bodies. If not specified, the bodyies are assumed to be the joint itself. @@ -30764,7 +30590,7 @@ </argument> <argument index="1" name="body_a" type="RID"> </argument> - <argument index="2" name="body_b" type="RID" default="RID()"> + <argument index="2" name="body_b" type="RID" default="[RID]"> </argument> <description> Create a pin joint between two bodies. If not specified, the second body is assumed to be the joint itself. @@ -31068,18 +30894,18 @@ This class contains the shape and other parameters for intersection/collision queries. </description> <methods> - <method name="get_exclude" qualifiers="const"> - <return type="Array"> + <method name="get_collision_layer" qualifiers="const"> + <return type="int"> </return> <description> - Return the list of objects, or object [RID]s, that will be excluded from collisions. + Return the physics layer the shape belongs to. </description> </method> - <method name="get_layer_mask" qualifiers="const"> - <return type="int"> + <method name="get_exclude" qualifiers="const"> + <return type="Array"> </return> <description> - Return the physics layer(s) the shape belongs to. + Return the list of objects, or object [RID]s, that will be excluded from collisions. </description> </method> <method name="get_margin" qualifiers="const"> @@ -31117,18 +30943,18 @@ Return the transform matrix of the shape queried. </description> </method> - <method name="set_exclude"> - <argument index="0" name="exclude" type="Array"> + <method name="set_collision_layer"> + <argument index="0" name="collision_layer" type="int"> </argument> <description> - Set the list of objects, or object [RID]s, that will be excluded from collisions. + Set the physics layer the shape belongs to. </description> </method> - <method name="set_layer_mask"> - <argument index="0" name="layer_mask" type="int"> + <method name="set_exclude"> + <argument index="0" name="exclude" type="Array"> </argument> <description> - Set the physics layer(s) the shape belongs to. + Set the list of objects, or object [RID]s, that will be excluded from collisions. </description> </method> <method name="set_margin"> @@ -31444,7 +31270,7 @@ </description> </method> <method name="set_collision_layer"> - <argument index="0" name="mask" type="int"> + <argument index="0" name="layer" type="int"> </argument> <description> Set the physics layers this area is in. @@ -31774,9 +31600,9 @@ </argument> <argument index="1" name="to" type="Vector3"> </argument> - <argument index="2" name="exclude" type="Array" default="Array()"> + <argument index="2" name="exclude" type="Array" default="[]"> </argument> - <argument index="3" name="layer_mask" type="int" default="2147483647"> + <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> <argument index="4" name="type_mask" type="int" default="15"> </argument> @@ -31929,15 +31755,15 @@ <description> </description> </method> - <method name="area_set_collision_mask"> + <method name="area_set_collision_layer"> <argument index="0" name="area" type="RID"> </argument> - <argument index="1" name="mask" type="int"> + <argument index="1" name="layer" type="int"> </argument> <description> </description> </method> - <method name="area_set_layer_mask"> + <method name="area_set_collision_mask"> <argument index="0" name="area" type="RID"> </argument> <argument index="1" name="mask" type="int"> @@ -32085,23 +31911,19 @@ <description> </description> </method> - <method name="body_get_collision_mask" qualifiers="const"> + <method name="body_get_collision_layer" qualifiers="const"> <return type="int"> </return> <argument index="0" name="body" type="RID"> </argument> - <argument index="1" name="arg1" type="int"> - </argument> <description> </description> </method> - <method name="body_get_layer_mask" qualifiers="const"> + <method name="body_get_collision_mask" qualifiers="const"> <return type="int"> </return> <argument index="0" name="body" type="RID"> </argument> - <argument index="1" name="arg1" type="int"> - </argument> <description> </description> </method> @@ -32239,6 +32061,14 @@ <description> </description> </method> + <method name="body_set_collision_layer"> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="layer" type="int"> + </argument> + <description> + </description> + </method> <method name="body_set_collision_mask"> <argument index="0" name="body" type="RID"> </argument> @@ -32267,14 +32097,6 @@ <description> </description> </method> - <method name="body_set_layer_mask"> - <argument index="0" name="body" type="RID"> - </argument> - <argument index="1" name="mask" type="int"> - </argument> - <description> - </description> - </method> <method name="body_set_max_contacts_reported"> <argument index="0" name="body" type="RID"> </argument> @@ -32966,14 +32788,14 @@ <description> </description> <methods> - <method name="get_exclude" qualifiers="const"> - <return type="Array"> + <method name="get_collision_layer" qualifiers="const"> + <return type="int"> </return> <description> </description> </method> - <method name="get_layer_mask" qualifiers="const"> - <return type="int"> + <method name="get_exclude" qualifiers="const"> + <return type="Array"> </return> <description> </description> @@ -33002,14 +32824,14 @@ <description> </description> </method> - <method name="set_exclude"> - <argument index="0" name="exclude" type="Array"> + <method name="set_collision_layer"> + <argument index="0" name="collision_layer" type="int"> </argument> <description> </description> </method> - <method name="set_layer_mask"> - <argument index="0" name="layer_mask" type="int"> + <method name="set_exclude"> + <argument index="0" name="exclude" type="Array"> </argument> <description> </description> @@ -34907,6 +34729,242 @@ <constants> </constants> </class> +<class name="ProceduralSky" inherits="Sky" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_ground_bottom_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_ground_curve" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_ground_energy" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_ground_horizon_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_sky_curve" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sky_energy" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sky_horizon_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_sky_top_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_sun_angle_max" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sun_angle_min" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sun_color" qualifiers="const"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="get_sun_curve" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sun_energy" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sun_latitude" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_sun_longitude" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="get_texture_size" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="set_ground_bottom_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_ground_curve"> + <argument index="0" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_ground_energy"> + <argument index="0" name="energy" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_ground_horizon_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_sky_curve"> + <argument index="0" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sky_energy"> + <argument index="0" name="energy" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sky_horizon_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_sky_top_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_sun_angle_max"> + <argument index="0" name="degrees" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sun_angle_min"> + <argument index="0" name="degrees" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sun_color"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="set_sun_curve"> + <argument index="0" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sun_energy"> + <argument index="0" name="energy" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sun_latitude"> + <argument index="0" name="degrees" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_sun_longitude"> + <argument index="0" name="degrees" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_texture_size"> + <argument index="0" name="size" type="int"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color" brief=""> + </member> + <member name="ground_curve" type="float" setter="set_ground_curve" getter="get_ground_curve" brief=""> + </member> + <member name="ground_energy" type="float" setter="set_ground_energy" getter="get_ground_energy" brief=""> + </member> + <member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color" brief=""> + </member> + <member name="sky_curve" type="float" setter="set_sky_curve" getter="get_sky_curve" brief=""> + </member> + <member name="sky_energy" type="float" setter="set_sky_energy" getter="get_sky_energy" brief=""> + </member> + <member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color" brief=""> + </member> + <member name="sky_top_color" type="Color" setter="set_sky_top_color" getter="get_sky_top_color" brief=""> + </member> + <member name="sun_angle_max" type="float" setter="set_sun_angle_max" getter="get_sun_angle_max" brief=""> + </member> + <member name="sun_angle_min" type="float" setter="set_sun_angle_min" getter="get_sun_angle_min" brief=""> + </member> + <member name="sun_color" type="Color" setter="set_sun_color" getter="get_sun_color" brief=""> + </member> + <member name="sun_curve" type="float" setter="set_sun_curve" getter="get_sun_curve" brief=""> + </member> + <member name="sun_energy" type="float" setter="set_sun_energy" getter="get_sun_energy" brief=""> + </member> + <member name="sun_latitude" type="float" setter="set_sun_latitude" getter="get_sun_latitude" brief=""> + </member> + <member name="sun_longitude" type="float" setter="set_sun_longitude" getter="get_sun_longitude" brief=""> + </member> + <member name="texture_size" type="int" setter="set_texture_size" getter="get_texture_size" brief=""> + </member> + </members> + <constants> + </constants> +</class> <class name="ProgressBar" inherits="Range" category="Core"> <brief_description> General purpose progress bar. @@ -35073,32 +35131,6 @@ <constants> </constants> </class> -<class name="QuadMesh" inherits="Mesh" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - <method name="get_material" qualifiers="const"> - <return type="Material"> - </return> - <description> - </description> - </method> - <method name="set_material"> - <argument index="0" name="material" type="Material"> - </argument> - <description> - </description> - </method> - </methods> - <members> - <member name="material" type="Material" setter="set_material" getter="get_material" brief=""> - </member> - </members> - <constants> - </constants> -</class> <class name="Quat" category="Built-In Types"> <brief_description> Quaternion. @@ -35171,6 +35203,13 @@ Returns the inverse of the quaternion. </description> </method> + <method name="is_normalized"> + <return type="bool"> + </return> + <description> + Returns whether the quaternion is normalized or not. + </description> + </method> <method name="length"> <return type="float"> </return> @@ -35192,13 +35231,6 @@ Returns a copy of the quaternion, normalized to unit length. </description> </method> - <method name="is_normalized"> - <return type="bool"> - </return> - <description> - Returns whether the quaternion is normalized or not. - </description> - </method> <method name="slerp"> <return type="Quat"> </return> @@ -35485,6 +35517,13 @@ Returns the collision shape of the closest object the ray is pointing to. </description> </method> + <method name="get_collision_layer" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the collision layer for this ray. + </description> + </method> <method name="get_collision_normal" qualifiers="const"> <return type="Vector3"> </return> @@ -35499,13 +35538,6 @@ Returns collision point. This point is in [b]global[/b] coordinate system. </description> </method> - <method name="get_layer_mask" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the layer mask for this ray. - </description> - </method> <method name="get_type_mask" qualifiers="const"> <return type="int"> </return> @@ -35547,18 +35579,18 @@ Sets to which point ray should be casted. This point is in [b]local[/b] coordinate system. </description> </method> - <method name="set_enabled"> - <argument index="0" name="enabled" type="bool"> + <method name="set_collision_layer"> + <argument index="0" name="layer" type="int"> </argument> <description> - Enables the RayCast2D. Only enabled raycasts will be able to query the space and report collisions. + Set the mask to filter objects. Only objects with at least the same mask element set will be detected. </description> </method> - <method name="set_layer_mask"> - <argument index="0" name="mask" type="int"> + <method name="set_enabled"> + <argument index="0" name="enabled" type="bool"> </argument> <description> - Set the mask to filter objects. Only objects with at least the same mask element set will be detected. + Enables the RayCast2D. Only enabled raycasts will be able to query the space and report collisions. </description> </method> <method name="set_type_mask"> @@ -35572,9 +35604,9 @@ <members> <member name="cast_to" type="Vector3" setter="set_cast_to" getter="get_cast_to" brief=""> </member> - <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" brief=""> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" brief=""> </member> - <member name="layer_mask" type="int" setter="set_layer_mask" getter="get_layer_mask" brief=""> + <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" brief=""> </member> <member name="type_mask" type="int" setter="set_type_mask" getter="get_type_mask" brief=""> </member> @@ -35640,6 +35672,13 @@ Returns the collision shape of the closest object the ray is pointing to. </description> </method> + <method name="get_collision_layer" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the collision layer for this ray. + </description> + </method> <method name="get_collision_normal" qualifiers="const"> <return type="Vector2"> </return> @@ -35661,13 +35700,6 @@ Returns whether this ray should hit your parent node, if it's a body. </description> </method> - <method name="get_layer_mask" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the layer mask for this ray. - </description> - </method> <method name="get_type_mask" qualifiers="const"> <return type="int"> </return> @@ -35709,6 +35741,13 @@ Sets the ray destination point, so that the ray will test from the ray's origin to [code]local_point[/code] </description> </method> + <method name="set_collision_layer"> + <argument index="0" name="layer" type="int"> + </argument> + <description> + Set the mask to filter objects. Only objects with at least the same mask element set will be detected. + </description> + </method> <method name="set_enabled"> <argument index="0" name="enabled" type="bool"> </argument> @@ -35723,13 +35762,6 @@ Toggle whether this ray should hit your parent node, if it's a body. </description> </method> - <method name="set_layer_mask"> - <argument index="0" name="mask" type="int"> - </argument> - <description> - Set the mask to filter objects. Only objects with at least the same mask element set will be detected. - </description> - </method> <method name="set_type_mask"> <argument index="0" name="mask" type="int"> </argument> @@ -35741,12 +35773,12 @@ <members> <member name="cast_to" type="Vector2" setter="set_cast_to" getter="get_cast_to" brief=""> </member> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" brief=""> + </member> <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" brief=""> </member> <member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" brief=""> </member> - <member name="layer_mask" type="int" setter="set_layer_mask" getter="get_layer_mask" brief=""> - </member> <member name="type_mask" type="int" setter="set_type_mask" getter="get_type_mask" brief=""> </member> </members> @@ -35886,6 +35918,30 @@ Return a copy of the [Rect2] grown a given amount of units towards all the sides. </description> </method> + <method name="grow_individual"> + <return type="Rect2"> + </return> + <argument index="0" name="left" type="float"> + </argument> + <argument index="1" name="top" type="float"> + </argument> + <argument index="2" name="right" type="float"> + </argument> + <argument index="3" name=" bottom" type="float"> + </argument> + <description> + </description> + </method> + <method name="grow_margin"> + <return type="Rect2"> + </return> + <argument index="0" name="margin" type="int"> + </argument> + <argument index="1" name="by" type="float"> + </argument> + <description> + </description> + </method> <method name="has_no_area"> <return type="bool"> </return> @@ -35925,8 +35981,7 @@ <member name="end" type="Vector2" setter="" getter="" brief=""> Ending corner. </member> - <member name="pos" type="Vector2" setter="" getter="" brief=""> - Position (starting corner). + <member name="position" type="Vector2" setter="" getter="" brief=""> </member> <member name="size" type="Vector2" setter="" getter="" brief=""> Size from position to end. @@ -36642,7 +36697,7 @@ <description> </description> </method> - <method name="duplicate"> + <method name="duplicate" qualifiers="const"> <return type="Object"> </return> <argument index="0" name="subresources" type="bool" default="false"> @@ -39418,7 +39473,7 @@ </constant> </constants> </class> -<class name="SkyBox" inherits="Resource" category="Core"> +<class name="Sky" inherits="Resource" category="Core"> <brief_description> </brief_description> <description> @@ -39970,12 +40025,30 @@ <description> </description> </method> + <method name="get_depth_deep_parallax_max_layers" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_depth_deep_parallax_min_layers" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> <method name="get_depth_draw_mode" qualifiers="const"> <return type="int"> </return> <description> </description> </method> + <method name="get_depth_scale" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_detail_blend_mode" qualifiers="const"> <return type="int"> </return> @@ -40022,19 +40095,13 @@ <description> </description> </method> - <method name="get_height_scale" qualifiers="const"> - <return type="float"> - </return> - <description> - </description> - </method> <method name="get_line_width" qualifiers="const"> <return type="float"> </return> <description> </description> </method> - <method name="get_metalness" qualifiers="const"> + <method name="get_metallic" qualifiers="const"> <return type="float"> </return> <description> @@ -40076,12 +40143,6 @@ <description> </description> </method> - <method name="get_refraction_roughness" qualifiers="const"> - <return type="float"> - </return> - <description> - </description> - </method> <method name="get_rim" qualifiers="const"> <return type="float"> </return> @@ -40101,13 +40162,7 @@ </description> </method> <method name="get_specular" qualifiers="const"> - <return type="Color"> - </return> - <description> - </description> - </method> - <method name="get_specular_mode" qualifiers="const"> - <return type="int"> + <return type="float"> </return> <description> </description> @@ -40150,6 +40205,12 @@ <description> </description> </method> + <method name="is_depth_deep_parallax_enabled" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="set_albedo"> <argument index="0" name="albedo" type="Color"> </argument> @@ -40192,12 +40253,36 @@ <description> </description> </method> + <method name="set_depth_deep_parallax"> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_depth_deep_parallax_max_layers"> + <argument index="0" name="layer" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_depth_deep_parallax_min_layers"> + <argument index="0" name="layer" type="int"> + </argument> + <description> + </description> + </method> <method name="set_depth_draw_mode"> <argument index="0" name="depth_draw_mode" type="int"> </argument> <description> </description> </method> + <method name="set_depth_scale"> + <argument index="0" name="depth_scale" type="float"> + </argument> + <description> + </description> + </method> <method name="set_detail_blend_mode"> <argument index="0" name="detail_blend_mode" type="int"> </argument> @@ -40244,20 +40329,14 @@ <description> </description> </method> - <method name="set_height_scale"> - <argument index="0" name="height_scale" type="float"> - </argument> - <description> - </description> - </method> <method name="set_line_width"> <argument index="0" name="line_width" type="float"> </argument> <description> </description> </method> - <method name="set_metalness"> - <argument index="0" name="metalness" type="float"> + <method name="set_metallic"> + <argument index="0" name="metallic" type="float"> </argument> <description> </description> @@ -40298,12 +40377,6 @@ <description> </description> </method> - <method name="set_refraction_roughness"> - <argument index="0" name="refraction_roughness" type="float"> - </argument> - <description> - </description> - </method> <method name="set_rim"> <argument index="0" name="rim" type="float"> </argument> @@ -40323,13 +40396,7 @@ </description> </method> <method name="set_specular"> - <argument index="0" name="specular" type="Color"> - </argument> - <description> - </description> - </method> - <method name="set_specular_mode"> - <argument index="0" name="specular_mode" type="int"> + <argument index="0" name="specular" type="float"> </argument> <description> </description> @@ -40396,6 +40463,18 @@ </member> <member name="clearcoat_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> </member> + <member name="depth_deep_parallax" type="bool" setter="set_depth_deep_parallax" getter="is_depth_deep_parallax_enabled" brief=""> + </member> + <member name="depth_enabled" type="bool" setter="set_feature" getter="get_feature" brief=""> + </member> + <member name="depth_max_layers" type="int" setter="set_depth_deep_parallax_max_layers" getter="get_depth_deep_parallax_max_layers" brief=""> + </member> + <member name="depth_min_layers" type="int" setter="set_depth_deep_parallax_min_layers" getter="get_depth_deep_parallax_min_layers" brief=""> + </member> + <member name="depth_scale" type="float" setter="set_depth_scale" getter="get_depth_scale" brief=""> + </member> + <member name="depth_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> + </member> <member name="detail_albedo" type="Texture" setter="set_texture" getter="get_texture" brief=""> </member> <member name="detail_blend_mode" type="int" setter="set_detail_blend_mode" getter="get_detail_blend_mode" brief=""> @@ -40426,11 +40505,11 @@ </member> <member name="flags_use_point_size" type="bool" setter="set_flag" getter="get_flag" brief=""> </member> - <member name="height_enabled" type="bool" setter="set_feature" getter="get_feature" brief=""> + <member name="metallic_amount" type="float" setter="set_metallic" getter="get_metallic" brief=""> </member> - <member name="height_scale" type="float" setter="set_height_scale" getter="get_height_scale" brief=""> + <member name="metallic_specular" type="float" setter="set_specular" getter="get_specular" brief=""> </member> - <member name="height_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> + <member name="metallic_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> </member> <member name="normal_enabled" type="bool" setter="set_feature" getter="get_feature" brief=""> </member> @@ -40458,11 +40537,9 @@ </member> <member name="particles_anim_v_frames" type="int" setter="set_particles_anim_v_frames" getter="get_particles_anim_v_frames" brief=""> </member> - <member name="refraction_displacement" type="float" setter="set_refraction" getter="get_refraction" brief=""> - </member> <member name="refraction_enabled" type="bool" setter="set_feature" getter="get_feature" brief=""> </member> - <member name="refraction_roughness" type="float" setter="set_refraction_roughness" getter="get_refraction_roughness" brief=""> + <member name="refraction_scale" type="float" setter="set_refraction" getter="get_refraction" brief=""> </member> <member name="refraction_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> </member> @@ -40474,15 +40551,9 @@ </member> <member name="rim_tint" type="float" setter="set_rim_tint" getter="get_rim_tint" brief=""> </member> - <member name="specular_color" type="Color" setter="set_specular" getter="get_specular" brief=""> - </member> - <member name="specular_metalness" type="float" setter="set_metalness" getter="get_metalness" brief=""> - </member> - <member name="specular_mode" type="int" setter="set_specular_mode" getter="get_specular_mode" brief=""> + <member name="roughness_amount" type="float" setter="set_roughness" getter="get_roughness" brief=""> </member> - <member name="specular_roughness" type="float" setter="set_roughness" getter="get_roughness" brief=""> - </member> - <member name="specular_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> + <member name="roughness_texture" type="Texture" setter="set_texture" getter="get_texture" brief=""> </member> <member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" brief=""> </member> @@ -40506,27 +40577,27 @@ <constants> <constant name="TEXTURE_ALBEDO" value="0"> </constant> - <constant name="TEXTURE_SPECULAR" value="1"> + <constant name="TEXTURE_METALLIC" value="1"> </constant> - <constant name="TEXTURE_EMISSION" value="2"> + <constant name="TEXTURE_ROUGHNESS" value="2"> </constant> - <constant name="TEXTURE_NORMAL" value="3"> + <constant name="TEXTURE_EMISSION" value="3"> </constant> - <constant name="TEXTURE_RIM" value="4"> + <constant name="TEXTURE_NORMAL" value="4"> </constant> - <constant name="TEXTURE_CLEARCOAT" value="5"> + <constant name="TEXTURE_RIM" value="5"> </constant> - <constant name="TEXTURE_FLOWMAP" value="6"> + <constant name="TEXTURE_CLEARCOAT" value="6"> </constant> - <constant name="TEXTURE_AMBIENT_OCCLUSION" value="7"> + <constant name="TEXTURE_FLOWMAP" value="7"> </constant> - <constant name="TEXTURE_HEIGHT" value="8"> + <constant name="TEXTURE_AMBIENT_OCCLUSION" value="8"> </constant> - <constant name="TEXTURE_SUBSURFACE_SCATTERING" value="9"> + <constant name="TEXTURE_DEPTH" value="9"> </constant> - <constant name="TEXTURE_REFRACTION" value="10"> + <constant name="TEXTURE_SUBSURFACE_SCATTERING" value="10"> </constant> - <constant name="TEXTURE_REFRACTION_ROUGHNESS" value="11"> + <constant name="TEXTURE_REFRACTION" value="11"> </constant> <constant name="TEXTURE_DETAIL_MASK" value="12"> </constant> @@ -40554,7 +40625,7 @@ </constant> <constant name="FEATURE_AMBIENT_OCCLUSION" value="6"> </constant> - <constant name="FEATURE_HEIGHT_MAPPING" value="7"> + <constant name="FEATURE_DEPTH_MAPPING" value="7"> </constant> <constant name="FEATURE_SUBSURACE_SCATTERING" value="8"> </constant> @@ -40602,16 +40673,12 @@ </constant> <constant name="DIFFUSE_LAMBERT" value="0"> </constant> - <constant name="DIFFUSE_LAMBERT_WRAP" value="1"> + <constant name="DIFFUSE_HALF_LAMBERT" value="1"> </constant> <constant name="DIFFUSE_OREN_NAYAR" value="2"> </constant> <constant name="DIFFUSE_BURLEY" value="3"> </constant> - <constant name="SPECULAR_MODE_METALLIC" value="0"> - </constant> - <constant name="SPECULAR_MODE_SPECULAR" value="1"> - </constant> <constant name="BILLBOARD_DISABLED" value="0"> </constant> <constant name="BILLBOARD_ENABLED" value="1"> @@ -41847,7 +41914,7 @@ <description> </description> </method> - <method name="get_position" qualifiers="const"> + <method name="get_pos" qualifiers="const"> <return type="int"> </return> <description> @@ -42164,14 +42231,6 @@ <method name="String"> <return type="String"> </return> - <argument index="0" name="from" type="InputEvent"> - </argument> - <description> - </description> - </method> - <method name="String"> - <return type="String"> - </return> <argument index="0" name="from" type="Dictionary"> </argument> <description> @@ -43158,7 +43217,7 @@ </argument> <argument index="4" name="normals" type="PoolVector3Array" default="PoolVector3Array([])"> </argument> - <argument index="5" name="tangents" type="Array" default="Array()"> + <argument index="5" name="tangents" type="Array" default="[]"> </argument> <description> Insert a triangle fan made of array data into [Mesh] being constructed. @@ -43461,7 +43520,7 @@ <theme_items> <theme_item name="decrement" type="Texture"> </theme_item> - <theme_item name="decrement_hilite" type="Texture"> + <theme_item name="decrement_highlight" type="Texture"> </theme_item> <theme_item name="font" type="Font"> </theme_item> @@ -43475,7 +43534,7 @@ </theme_item> <theme_item name="increment" type="Texture"> </theme_item> - <theme_item name="increment_hilite" type="Texture"> + <theme_item name="increment_highlight" type="Texture"> </theme_item> <theme_item name="label_valign_bg" type="int"> </theme_item> @@ -43483,7 +43542,7 @@ </theme_item> <theme_item name="menu" type="Texture"> </theme_item> - <theme_item name="menu_hilite" type="Texture"> + <theme_item name="menu_highlight" type="Texture"> </theme_item> <theme_item name="panel" type="StyleBox"> </theme_item> @@ -43491,8 +43550,6 @@ </theme_item> <theme_item name="tab_bg" type="StyleBox"> </theme_item> - <theme_item name="tab_disabled" type="StyleBox"> - </theme_item> <theme_item name="tab_fg" type="StyleBox"> </theme_item> <theme_item name="top_margin" type="int"> @@ -43653,7 +43710,7 @@ </theme_item> <theme_item name="decrement" type="Texture"> </theme_item> - <theme_item name="decrement_hilite" type="Texture"> + <theme_item name="decrement_highlight" type="Texture"> </theme_item> <theme_item name="font" type="Font"> </theme_item> @@ -43667,7 +43724,7 @@ </theme_item> <theme_item name="increment" type="Texture"> </theme_item> - <theme_item name="increment_hilite" type="Texture"> + <theme_item name="increment_highlight" type="Texture"> </theme_item> <theme_item name="label_valign_bg" type="int"> </theme_item> @@ -43677,8 +43734,6 @@ </theme_item> <theme_item name="tab_bg" type="StyleBox"> </theme_item> - <theme_item name="tab_disabled" type="StyleBox"> - </theme_item> <theme_item name="tab_fg" type="StyleBox"> </theme_item> <theme_item name="top_margin" type="int"> @@ -43801,7 +43856,7 @@ <method name="cursor_set_column"> <argument index="0" name="column" type="int"> </argument> - <argument index="1" name="adjust_viewport" type="bool" default="false"> + <argument index="1" name="adjust_viewport" type="bool" default="true"> </argument> <description> </description> @@ -43809,7 +43864,7 @@ <method name="cursor_set_line"> <argument index="0" name="line" type="int"> </argument> - <argument index="1" name="adjust_viewport" type="bool" default="false"> + <argument index="1" name="adjust_viewport" type="bool" default="true"> </argument> <description> </description> @@ -45022,6 +45077,14 @@ Return the collision layer. </description> </method> + <method name="get_collision_layer_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + </description> + </method> <method name="get_collision_mask" qualifiers="const"> <return type="int"> </return> @@ -45029,6 +45092,14 @@ Return the collision mask. </description> </method> + <method name="get_collision_mask_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + </description> + </method> <method name="get_collision_use_kinematic" qualifiers="const"> <return type="bool"> </return> @@ -45221,13 +45292,21 @@ </description> </method> <method name="set_collision_layer"> - <argument index="0" name="mask" type="int"> + <argument index="0" name="layer" type="int"> </argument> <description> Set the collision layer. Layers are referenced by binary indexes, so allowable values to describe the 20 available layers range from 0 to 2^20-1. </description> </method> + <method name="set_collision_layer_bit"> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + </description> + </method> <method name="set_collision_mask"> <argument index="0" name="mask" type="int"> </argument> @@ -45236,6 +45315,14 @@ Masks are referenced by binary indexes, so allowable values to describe the 20 available masks range from 0 to 2^20-1. </description> </method> + <method name="set_collision_mask_bit"> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + </description> + </method> <method name="set_collision_use_kinematic"> <argument index="0" name="use_kinematic" type="bool"> </argument> @@ -45328,7 +45415,7 @@ </member> <member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" brief=""> </member> - <member name="collision_layers" type="int" setter="set_collision_layer" getter="get_collision_layer" brief=""> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" brief=""> </member> <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" brief=""> </member> @@ -46685,6 +46772,12 @@ Emitted when a cell is selected. </description> </signal> + <signal name="column_title_pressed"> + <argument index="0" name="column" type="int"> + </argument> + <description> + </description> + </signal> <signal name="custom_popup_edited"> <argument index="0" name="arrow_clicked" type="bool"> </argument> @@ -46711,6 +46804,10 @@ Emitted when an item is collapsed by a click on the folding arrow. </description> </signal> + <signal name="item_custom_button_pressed"> + <description> + </description> + </signal> <signal name="item_double_clicked"> <description> </description> @@ -46778,6 +46875,14 @@ </theme_item> <theme_item name="cursor_unfocused" type="StyleBox"> </theme_item> + <theme_item name="custom_button" type="StyleBox"> + </theme_item> + <theme_item name="custom_button_font_highlight" type="Color"> + </theme_item> + <theme_item name="custom_button_hover" type="StyleBox"> + </theme_item> + <theme_item name="custom_button_pressed" type="StyleBox"> + </theme_item> <theme_item name="draw_relationship_lines" type="int"> </theme_item> <theme_item name="drop_position_color" type="Color"> @@ -46843,6 +46948,8 @@ </argument> <argument index="3" name="disabled" type="bool" default="false"> </argument> + <argument index="4" name="tooltip" type="String" default=""""> + </argument> <description> </description> </method> @@ -47028,6 +47135,14 @@ <description> </description> </method> + <method name="is_custom_set_as_button" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <description> + </description> + </method> <method name="is_editable"> <return type="bool"> </return> @@ -47106,6 +47221,14 @@ <description> </description> </method> + <method name="set_custom_as_button"> + <argument index="0" name="column" type="int"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> <method name="set_custom_bg_color"> <argument index="0" name="column" type="int"> </argument> @@ -47833,40 +47956,6 @@ do_property]. </theme_item> </theme_items> </class> -<class name="VButtonArray" inherits="ButtonArray" category="Core"> - <brief_description> - Vertical button array. - </brief_description> - <description> - Vertical button array. See [ButtonArray]. - </description> - <methods> - </methods> - <constants> - </constants> - <theme_items> - <theme_item name="button_separator" type="int"> - </theme_item> - <theme_item name="focus" type="StyleBox"> - </theme_item> - <theme_item name="font" type="Font"> - </theme_item> - <theme_item name="font_color" type="Color"> - </theme_item> - <theme_item name="font_color_selected" type="Color"> - </theme_item> - <theme_item name="font_selected" type="Font"> - </theme_item> - <theme_item name="hover" type="StyleBox"> - </theme_item> - <theme_item name="icon_separator" type="int"> - </theme_item> - <theme_item name="normal" type="StyleBox"> - </theme_item> - <theme_item name="selected" type="StyleBox"> - </theme_item> - </theme_items> -</class> <class name="VScrollBar" inherits="ScrollBar" category="Core"> <brief_description> Vertical version of [ScrollBar], which goes from left (min) to right (max). @@ -47880,15 +47969,15 @@ do_property]. <theme_items> <theme_item name="decrement" type="Texture"> </theme_item> - <theme_item name="decrement_hilite" type="Texture"> + <theme_item name="decrement_highlight" type="Texture"> </theme_item> <theme_item name="grabber" type="StyleBox"> </theme_item> - <theme_item name="grabber_hilite" type="StyleBox"> + <theme_item name="grabber_highlight" type="StyleBox"> </theme_item> <theme_item name="increment" type="Texture"> </theme_item> - <theme_item name="increment_hilite" type="Texture"> + <theme_item name="increment_highlight" type="Texture"> </theme_item> <theme_item name="scroll" type="StyleBox"> </theme_item> @@ -47928,9 +48017,9 @@ do_property]. <theme_items> <theme_item name="grabber" type="Texture"> </theme_item> - <theme_item name="grabber_hilite" type="Texture"> + <theme_item name="grabber_highlight" type="Texture"> </theme_item> - <theme_item name="grabber_hilite" type="StyleBox"> + <theme_item name="grabber_highlight" type="StyleBox"> </theme_item> <theme_item name="slider" type="StyleBox"> </theme_item> @@ -48094,6 +48183,13 @@ do_property]. Remove the fractional part of x and y. </description> </method> + <method name="is_normalized"> + <return type="bool"> + </return> + <description> + Returns whether the vector is normalized or not. + </description> + </method> <method name="length"> <return type="float"> </return> @@ -48126,13 +48222,6 @@ do_property]. Returns a normalized vector to unit length. </description> </method> - <method name="is_normalized"> - <return type="bool"> - </return> - <description> - Returns whether the vector is normalized or not. - </description> - </method> <method name="reflect"> <return type="Vector2"> </return> @@ -48311,6 +48400,13 @@ do_property]. Returns the inverse of the vector. This is the same as Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z ) </description> </method> + <method name="is_normalized"> + <return type="bool"> + </return> + <description> + Returns whether the vector is normalized or not. + </description> + </method> <method name="length"> <return type="float"> </return> @@ -48357,13 +48453,6 @@ do_property]. Return a copy of the normalized vector to unit length. This is the same as v / v.length(). </description> </method> - <method name="is_normalized"> - <return type="bool"> - </return> - <description> - Returns whether the vector is normalized or not. - </description> - </method> <method name="outer"> <return type="Basis"> </return> @@ -48567,6 +48656,12 @@ do_property]. <description> </description> </method> + <method name="get_roll_influence" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_suspension_max_force" qualifiers="const"> <return type="float"> </return> @@ -48591,6 +48686,12 @@ do_property]. <description> </description> </method> + <method name="is_in_contact" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="is_used_as_steering" qualifiers="const"> <return type="bool"> </return> @@ -48627,6 +48728,12 @@ do_property]. <description> </description> </method> + <method name="set_roll_influence"> + <argument index="0" name="roll_influence" type="float"> + </argument> + <description> + </description> + </method> <method name="set_suspension_max_force"> <argument index="0" name="length" type="float"> </argument> @@ -48685,6 +48792,8 @@ do_property]. </member> <member name="wheel_rest_length" type="float" setter="set_suspension_rest_length" getter="get_suspension_rest_length" brief=""> </member> + <member name="wheel_roll_influence" type="float" setter="set_roll_influence" getter="get_roll_influence" brief=""> + </member> </members> <constants> </constants> @@ -48928,6 +49037,12 @@ do_property]. Return whether automatic clearing of the render target on each frame is enabled. </description> </method> + <method name="get_debug_draw" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> <method name="get_final_transform" qualifiers="const"> <return type="Transform2D"> </return> @@ -48969,8 +49084,16 @@ do_property]. Get whether picking for all physics objects inside the viewport is enabled. </description> </method> + <method name="get_render_info"> + <return type="int"> + </return> + <argument index="0" name="info" type="int"> + </argument> + <description> + </description> + </method> <method name="get_screen_capture" qualifiers="const"> - <return type="Image"> + <return type="Object"> </return> <description> Return the captured screenshot after [method queue_screen_capture]. You might need to check more than one frame until the right image is returned. @@ -49018,6 +49141,12 @@ do_property]. Get when the viewport would be updated, will be one of the [code]UPDATE_*[/code] constants. </description> </method> + <method name="get_usage" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> <method name="get_vflip" qualifiers="const"> <return type="bool"> </return> @@ -49075,7 +49204,7 @@ do_property]. </description> </method> <method name="input"> - <argument index="0" name="local_event" type="InputEvent"> + <argument index="0" name="local_event" type="Object"> </argument> <description> </description> @@ -49166,6 +49295,12 @@ do_property]. <description> </description> </method> + <method name="set_debug_draw"> + <argument index="0" name="debug_draw" type="int"> + </argument> + <description> + </description> + </method> <method name="set_disable_3d"> <argument index="0" name="disable" type="bool"> </argument> @@ -49258,6 +49393,12 @@ do_property]. Set when the render target would be updated, using the [code]UPDATE_*[/code] constants </description> </method> + <method name="set_usage"> + <argument index="0" name="usage" type="int"> + </argument> + <description> + </description> + </method> <method name="set_use_own_world"> <argument index="0" name="enable" type="bool"> </argument> @@ -49286,7 +49427,7 @@ do_property]. </description> </method> <method name="unhandled_input"> - <argument index="0" name="local_event" type="InputEvent"> + <argument index="0" name="local_event" type="Object"> </argument> <description> </description> @@ -49309,6 +49450,8 @@ do_property]. </member> <member name="audio_listener_enable_3d" type="bool" setter="set_as_audio_listener" getter="is_audio_listener" brief=""> </member> + <member name="debug_draw" type="int" setter="set_debug_draw" getter="get_debug_draw" brief=""> + </member> <member name="disable_3d" type="bool" setter="set_disable_3d" getter="is_3d_disabled" brief=""> </member> <member name="gui_disable_input" type="bool" setter="set_disable_input" getter="is_input_disabled" brief=""> @@ -49341,6 +49484,8 @@ do_property]. </member> <member name="transparent_bg" type="bool" setter="set_transparent_background" getter="has_transparent_background" brief=""> </member> + <member name="usage" type="int" setter="set_usage" getter="get_usage" brief=""> + </member> <member name="world" type="World" setter="set_world" getter="get_world" brief=""> </member> </members> @@ -49379,6 +49524,28 @@ do_property]. </constant> <constant name="SHADOW_ATLAS_QUADRANT_SUBDIV_MAX" value="7"> </constant> + <constant name="RENDER_INFO_OBJECTS_IN_FRAME" value="0"> + </constant> + <constant name="RENDER_INFO_VERTICES_IN_FRAME" value="1"> + </constant> + <constant name="RENDER_INFO_MATERIAL_CHANGES_IN_FRAME" value="2"> + </constant> + <constant name="RENDER_INFO_SHADER_CHANGES_IN_FRAME" value="3"> + </constant> + <constant name="RENDER_INFO_SURFACE_CHANGES_IN_FRAME" value="4"> + </constant> + <constant name="RENDER_INFO_DRAW_CALLS_IN_FRAME" value="5"> + </constant> + <constant name="RENDER_INFO_MAX" value="6"> + </constant> + <constant name="DEBUG_DRAW_DISABLED" value="0"> + </constant> + <constant name="DEBUG_DRAW_UNSHADED" value="1"> + </constant> + <constant name="DEBUG_DRAW_OVERDRAW" value="2"> + </constant> + <constant name="DEBUG_DRAW_WIREFRAME" value="3"> + </constant> <constant name="MSAA_DISABLED" value="0"> </constant> <constant name="MSAA_2X" value="1"> @@ -50510,24 +50677,12 @@ do_property]. <description> </description> <methods> - <method name="get_deconstruct_input_type" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> <method name="get_deconstruct_type" qualifiers="const"> <return type="int"> </return> <description> </description> </method> - <method name="set_deconstruct_input_type"> - <argument index="0" name="input_type" type="int"> - </argument> - <description> - </description> - </method> <method name="set_deconstruct_type"> <argument index="0" name="type" type="int"> </argument> @@ -50538,8 +50693,6 @@ do_property]. <members> <member name="elem_cache" type="Array" setter="_set_elem_cache" getter="_get_elem_cache" brief=""> </member> - <member name="input_type" type="int" setter="set_deconstruct_input_type" getter="get_deconstruct_input_type" brief=""> - </member> <member name="type" type="int" setter="set_deconstruct_type" getter="get_deconstruct_type" brief=""> </member> </members> @@ -50900,16 +51053,6 @@ do_property]. <constants> </constants> </class> -<class name="VisualScriptInputFilter" inherits="VisualScriptNode" category="Core"> - <brief_description> - </brief_description> - <description> - </description> - <methods> - </methods> - <constants> - </constants> -</class> <class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core"> <brief_description> </brief_description> @@ -51170,12 +51313,6 @@ do_property]. <description> </description> </method> - <method name="get_event_type" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> <method name="get_property" qualifiers="const"> <return type="String"> </return> @@ -51212,12 +51349,6 @@ do_property]. <description> </description> </method> - <method name="set_event_type"> - <argument index="0" name="event_type" type="int"> - </argument> - <description> - </description> - </method> <method name="set_property"> <argument index="0" name="property" type="String"> </argument> @@ -51232,8 +51363,6 @@ do_property]. </member> <member name="property/basic_type" type="int" setter="set_basic_type" getter="get_basic_type" brief=""> </member> - <member name="property/event_type" type="int" setter="set_event_type" getter="get_event_type" brief=""> - </member> <member name="property/node_path" type="NodePath" setter="set_base_path" getter="get_base_path" brief=""> </member> <member name="property/property" type="String" setter="set_property" getter="get_property" brief=""> @@ -51288,12 +51417,6 @@ do_property]. <description> </description> </method> - <method name="get_event_type" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> <method name="get_property" qualifiers="const"> <return type="String"> </return> @@ -51330,12 +51453,6 @@ do_property]. <description> </description> </method> - <method name="set_event_type"> - <argument index="0" name="event_type" type="int"> - </argument> - <description> - </description> - </method> <method name="set_property"> <argument index="0" name="property" type="String"> </argument> @@ -51350,8 +51467,6 @@ do_property]. </member> <member name="property/basic_type" type="int" setter="set_basic_type" getter="get_basic_type" brief=""> </member> - <member name="property/event_type" type="int" setter="set_event_type" getter="get_event_type" brief=""> - </member> <member name="property/node_path" type="NodePath" setter="set_base_path" getter="get_base_path" brief=""> </member> <member name="property/property" type="String" setter="set_property" getter="get_property" brief=""> @@ -51774,7 +51889,7 @@ do_property]. <method name="texture_create_from_image"> <return type="RID"> </return> - <argument index="0" name="arg0" type="Image"> + <argument index="0" name="arg0" type="Object"> </argument> <argument index="1" name="arg1" type="int" default="7"> </argument> @@ -51897,7 +52012,7 @@ do_property]. </theme_item> <theme_item name="close_h_ofs" type="int"> </theme_item> - <theme_item name="close_hilite" type="Texture"> + <theme_item name="close_highlight" type="Texture"> </theme_item> <theme_item name="close_v_ofs" type="int"> </theme_item> @@ -51911,8 +52026,6 @@ do_property]. </theme_item> <theme_item name="title_height" type="int"> </theme_item> - <theme_item name="titlebar_height" type="int"> - </theme_item> </theme_items> </class> <class name="World" inherits="Resource" category="Core"> @@ -51935,6 +52048,12 @@ do_property]. <description> </description> </method> + <method name="get_fallback_environment" qualifiers="const"> + <return type="Environment"> + </return> + <description> + </description> + </method> <method name="get_scenario" qualifiers="const"> <return type="RID"> </return> @@ -51953,10 +52072,18 @@ do_property]. <description> </description> </method> + <method name="set_fallback_environment"> + <argument index="0" name="env" type="Environment"> + </argument> + <description> + </description> + </method> </methods> <members> <member name="environment" type="Environment" setter="set_environment" getter="get_environment" brief=""> </member> + <member name="fallback_environment" type="Environment" setter="set_fallback_environment" getter="get_fallback_environment" brief=""> + </member> </members> <constants> </constants> @@ -52345,4 +52472,3 @@ do_property]. </constants> </class> </doc> - diff --git a/doc/tools/makemd.py b/doc/tools/makemd.py index bd0d4c6819..b2444eb47b 100644 --- a/doc/tools/makemd.py +++ b/doc/tools/makemd.py @@ -273,6 +273,12 @@ def make_doku_class(node): f.write('\n### Signals \n') for m in list(events): make_method(f, node.attrib['name'], m, True, True) + d = m.find('description') + if d == None or d.text.strip() == '': + continue + f.write('\n') + f.write(dokuize_text(d.text.strip())) + f.write('\n') members = node.find('members') diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index 6b6780ce1e..8a117f6450 100644 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -441,6 +441,12 @@ def make_rst_class(node): f.write(make_heading('Signals', '-')) for m in list(events): make_method(f, node.attrib['name'], m, True, name, True) + d = m.find('description') + if d == None or d.text.strip() == '': + continue + f.write(rstize_text(d.text.strip(), name)) + f.write("\n\n") + f.write('\n') members = node.find('members') diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 1121a07347..aad132a92d 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "rasterizer_canvas_gles3.h" +#include "global_config.h" #include "os/os.h" - #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif @@ -113,7 +113,7 @@ void RasterizerCanvasGLES3::light_internal_update(RID p_rid, Light *p_light) { li->ubo_data.light_pos[0] = p_light->light_shader_pos.x; li->ubo_data.light_pos[1] = p_light->light_shader_pos.y; - li->ubo_data.shadowpixel_size = 1.0 / p_light->shadow_buffer_size; + li->ubo_data.shadowpixel_size = (1.0 / p_light->shadow_buffer_size) * (1.0 + p_light->shadow_smooth); li->ubo_data.light_outside_alpha = p_light->mode == VS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0; li->ubo_data.light_height = p_light->height; if (p_light->radius_cache == 0) @@ -247,113 +247,56 @@ void RasterizerCanvasGLES3::_set_texture_rect_mode(bool p_enable) { state.using_texture_rect = p_enable; } -void RasterizerCanvasGLES3::_draw_polygon(int p_vertex_count, const int *p_indices, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, const RID &p_texture, bool p_singlecolor) { +void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - bool do_colors = false; - Color m; - if (p_singlecolor) { - m = *p_colors; - glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { + glBindVertexArray(data.polygon_buffer_pointer_array); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } else - do_colors = true; - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(p_texture); + uint32_t buffer_ofs = 0; -#ifndef GLES_NO_CLIENT_ARRAYS + //vertex + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), p_vertices); - if (do_colors) { + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Vector2) * p_vertex_count; + //color - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), p_colors); - } else { + if (p_singlecolor) { glDisableVertexAttribArray(VS::ARRAY_COLOR); - } - - if (texture && p_uvs) { - - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), p_uvs); - } else { - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - } - - if (p_indices) { - glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_INT, p_indices); + Color m = *p_colors; + glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + } else if (!p_colors) { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); } else { - glDrawArrays(GL_TRIANGLES, 0, p_vertex_count); - } - -#else //WebGL specific impl. - glBindBuffer(GL_ARRAY_BUFFER, gui_quad_buffer); - float *b = GlobalVertexBuffer; - int ofs = 0; - if (p_vertex_count > MAX_POLYGON_VERTICES) { - print_line("Too many vertices to render"); - return; - } - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(float) * 2, ((float *)0) + ofs); - for (int i = 0; i < p_vertex_count; i++) { - b[ofs++] = p_vertices[i].x; - b[ofs++] = p_vertices[i].y; - } - - if (p_colors && do_colors) { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(float) * 4, ((float *)0) + ofs); - for (int i = 0; i < p_vertex_count; i++) { - b[ofs++] = p_colors[i].r; - b[ofs++] = p_colors[i].g; - b[ofs++] = p_colors[i].b; - b[ofs++] = p_colors[i].a; - } - - } else { - glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Color) * p_vertex_count; } if (p_uvs) { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(float) * 2, ((float *)0) + ofs); - for (int i = 0; i < p_vertex_count; i++) { - b[ofs++] = p_uvs[i].x; - b[ofs++] = p_uvs[i].y; - } + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Vector2) * p_vertex_count; } else { glDisableVertexAttribArray(VS::ARRAY_TEX_UV); } - glBufferSubData(GL_ARRAY_BUFFER, 0, ofs * 4, &b[0]); - //bind the indices buffer. - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer); - - static const int _max_draw_poly_indices = 16 * 1024; // change this size if needed!!! - ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices); - static uint16_t _draw_poly_indices[_max_draw_poly_indices]; - for (int i = 0; i < p_vertex_count; i++) { - _draw_poly_indices[i] = p_indices[i]; - //OS::get_singleton()->print("ind: %d ", p_indices[i]); - }; - - //copy the data to GPU. - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, p_vertex_count * sizeof(uint16_t), &_draw_poly_indices[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); //draw the triangles. - glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, 0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#endif + glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); storage->frame.canvas_draw_commands++; + + glBindVertexArray(0); } void RasterizerCanvasGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs) { @@ -404,9 +347,9 @@ void RasterizerCanvasGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_v } } - glBindBuffer(GL_ARRAY_BUFFER, data.primitive_quad_buffer); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4, &b[0]); - glBindVertexArray(data.primitive_quad_buffer_arrays[version]); + glBindVertexArray(data.polygon_buffer_quad_arrays[version]); glDrawArrays(prim[p_points], 0, p_points); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -624,7 +567,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } - //_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); + _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); } break; case Item::Command::TYPE_CIRCLE: { @@ -644,6 +587,9 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur indices[i * 3 + 1] = (i + 1) % numpoints; indices[i * 3 + 2] = numpoints; } + + _draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true); + //_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); } break; @@ -1165,7 +1111,6 @@ void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, cons glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); state.canvas_shadow_shader.bind(); glViewport(0, 0, cls->size, cls->height); @@ -1264,18 +1209,14 @@ void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, cons } } */ - glBindBuffer(GL_ARRAY_BUFFER, cc->vertex_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cc->index_id); - glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); + glBindVertexArray(cc->array_id); glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0); instance = instance->next; } } - glDisableVertexAttribArray(VS::ARRAY_VERTEX); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); } void RasterizerCanvasGLES3::reset_canvas() { @@ -1299,9 +1240,6 @@ void RasterizerCanvasGLES3::reset_canvas() { //glLineWidth(1.0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - for (int i = 0; i < VS::ARRAY_MAX; i++) { - glDisableVertexAttribArray(i); - } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); @@ -1327,9 +1265,7 @@ void RasterizerCanvasGLES3::reset_canvas() { state.vp = canvas_transform; store_transform(canvas_transform, state.canvas_item_ubo_data.projection_matrix); - for (int i = 0; i < 4; i++) { - state.canvas_item_ubo_data.time[i] = storage->frame.time[i]; - } + state.canvas_item_ubo_data.time = storage->frame.time[0]; glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data); @@ -1376,15 +1312,19 @@ void RasterizerCanvasGLES3::initialize() { { - glGenBuffers(1, &data.primitive_quad_buffer); - glBindBuffer(GL_ARRAY_BUFFER, data.primitive_quad_buffer); - glBufferData(GL_ARRAY_BUFFER, (2 + 2 + 4) * 4 * sizeof(float), NULL, GL_DYNAMIC_DRAW); //allocate max size + uint32_t poly_size = GLOBAL_DEF("rendering/buffers/canvas_polygon_buffer_size_kb", 128); + poly_size *= 1024; //kb + poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); + glGenBuffers(1, &data.polygon_buffer); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); //allocate max size glBindBuffer(GL_ARRAY_BUFFER, 0); + //quad arrays for (int i = 0; i < 4; i++) { - glGenVertexArrays(1, &data.primitive_quad_buffer_arrays[i]); - glBindVertexArray(data.primitive_quad_buffer_arrays[i]); - glBindBuffer(GL_ARRAY_BUFFER, data.primitive_quad_buffer); + glGenVertexArrays(1, &data.polygon_buffer_quad_arrays[i]); + glBindVertexArray(data.polygon_buffer_quad_arrays[i]); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); int uv_ofs = 0; int color_ofs = 0; @@ -1415,6 +1355,15 @@ void RasterizerCanvasGLES3::initialize() { glBindVertexArray(0); } + + glGenVertexArrays(1, &data.polygon_buffer_pointer_array); + + uint32_t index_size = GLOBAL_DEF("rendering/buffers/canvas_polygon_index_buffer_size_kb", 128); + index_size *= 1024; //kb + glGenBuffers(1, &data.polygon_index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); //allocate max size + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } store_transform(Transform(), state.canvas_item_ubo_data.projection_matrix); @@ -1436,6 +1385,8 @@ void RasterizerCanvasGLES3::finalize() { glDeleteBuffers(1, &data.canvas_quad_vertices); glDeleteVertexArrays(1, &data.canvas_quad_array); + + glDeleteVertexArrays(1, &data.polygon_buffer_pointer_array); } RasterizerCanvasGLES3::RasterizerCanvasGLES3() { diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index 95ef9ee443..b4f491285d 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -39,7 +39,7 @@ public: struct CanvasItemUBO { float projection_matrix[16]; - float time[4]; + float time; }; struct Data { @@ -47,8 +47,11 @@ public: GLuint canvas_quad_vertices; GLuint canvas_quad_array; - GLuint primitive_quad_buffer; - GLuint primitive_quad_buffer_arrays[4]; + GLuint polygon_buffer; + GLuint polygon_buffer_quad_arrays[4]; + GLuint polygon_buffer_pointer_array; + GLuint polygon_index_buffer; + uint32_t polygon_buffer_size; } data; @@ -107,7 +110,7 @@ public: _FORCE_INLINE_ RasterizerStorageGLES3::Texture *_bind_canvas_texture(const RID &p_texture); _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); - _FORCE_INLINE_ void _draw_polygon(int p_vertex_count, const int *p_indices, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, const RID &p_texture, bool p_singlecolor); + _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip); virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 08f15a9b84..f7253c6b5b 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -887,17 +887,16 @@ void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_ void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { } -void RasterizerSceneGLES3::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_accel, float p_fade, float p_depth_tolerance, bool p_smooth, bool p_roughness) { +void RasterizerSceneGLES3::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->ssr_enabled = p_enable; env->ssr_max_steps = p_max_steps; - env->ssr_accel = p_accel; - env->ssr_fade = p_fade; + env->ssr_fade_in = p_fade_in; + env->ssr_fade_out = p_fade_out; env->ssr_depth_tolerance = p_depth_tolerance; - env->ssr_smooth = p_smooth; env->ssr_roughness = p_roughness; } @@ -1004,7 +1003,7 @@ void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, co light_instance->transform = p_transform; } -void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass) { +void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); @@ -1019,6 +1018,7 @@ void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_insta light_instance->shadow_transform[p_pass].transform = p_transform; light_instance->shadow_transform[p_pass].farplane = p_far; light_instance->shadow_transform[p_pass].split = p_split; + light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; } void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { @@ -1905,7 +1905,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ if (!p_shadow) { if (p_directional_add) { - if (e->sort_key & RenderList::SORT_KEY_UNSHADED_FLAG || !(e->instance->layer_mask & directional_light->light_ptr->cull_mask)) { + if (e->sort_key & SORT_KEY_UNSHADED_FLAG || !(e->instance->layer_mask & directional_light->light_ptr->cull_mask)) { continue; } @@ -1914,7 +1914,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ if (shading != prev_shading) { - if (e->sort_key & RenderList::SORT_KEY_UNSHADED_FLAG) { + if (e->sort_key & SORT_KEY_UNSHADED_FLAG) { state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING, false); @@ -1943,7 +1943,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); - if (p_directional_add || (directional_light && (e->sort_key & RenderList::SORT_KEY_NO_DIRECTIONAL_FLAG) == 0)) { + if (p_directional_add || (directional_light && (e->sort_key & SORT_KEY_NO_DIRECTIONAL_FLAG) == 0)) { state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, true); if (p_directional_shadows && directional_light->light_ptr->shadow) { @@ -2047,7 +2047,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ } } - if (!(e->sort_key & RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { + if (!(e->sort_key & SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { _setup_light(e, p_view_transform); } @@ -2113,7 +2113,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo if (m_src.is_valid()) { m = storage->material_owner.getornull(m_src); - if (!m->shader) { + if (!m->shader || !m->shader->valid) { m = NULL; } } @@ -2176,7 +2176,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo } if (!p_shadow && directional_light && (directional_light->light_ptr->cull_mask & e->instance->layer_mask) == 0) { - e->sort_key |= RenderList::SORT_KEY_NO_DIRECTIONAL_FLAG; + e->sort_key |= SORT_KEY_NO_DIRECTIONAL_FLAG; } e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; @@ -2204,7 +2204,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo } if (e->instance->gi_probe_instances.size()) { - e->sort_key |= RenderList::SORT_KEY_GI_PROBES_FLAG; + e->sort_key |= SORT_KEY_GI_PROBES_FLAG; } } @@ -2221,7 +2221,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo if (shadow || m->shader->spatial.unshaded || state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - e->sort_key |= RenderList::SORT_KEY_UNSHADED_FLAG; + e->sort_key |= SORT_KEY_UNSHADED_FLAG; } } @@ -2314,9 +2314,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr store_transform(p_cam_transform.affine_inverse(), state.ubo_data.camera_inverse_matrix); //time global variables - for (int i = 0; i < 4; i++) { - state.ubo_data.time[i] = storage->frame.time[i]; - } + state.ubo_data.time = storage->frame.time[0]; state.ubo_data.z_far = p_cam_projection.get_z_far(); //bg and ambient @@ -3250,8 +3248,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ //perform SSR - state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::SMOOTH_ACCEL, env->ssr_accel > 0 && env->ssr_smooth); - state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::REFLECT_ROUGHNESS, env->ssr_accel > 0 && env->ssr_roughness); + state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::REFLECT_ROUGHNESS, env->ssr_roughness); state.ssr_shader.bind(); @@ -3267,9 +3264,9 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ //state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::FRAME_INDEX,int(render_pass)); state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::FILTER_MIPMAP_LEVELS, float(storage->frame.current_rt->effects.mip_maps[0].sizes.size())); state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::NUM_STEPS, env->ssr_max_steps); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::ACCELERATION, env->ssr_accel); state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::DEPTH_TOLERANCE, env->ssr_depth_tolerance); - state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::DISTANCE_FADE, env->ssr_fade); + state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::DISTANCE_FADE, env->ssr_fade_out); + state.ssr_shader.set_uniform(ScreenSpaceReflectionShaderGLES3::CURVE_FADE_IN, env->ssr_fade_in); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); @@ -3840,8 +3837,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.ubo_data.subsurface_scatter_width = subsurface_scatter_size; - state.ubo_data.shadow_z_offset = 0; - state.ubo_data.shadow_slope_scale = 0; + state.ubo_data.z_offset = 0; + state.ubo_data.z_slope_scale = 0; state.ubo_data.shadow_dual_paraboloid_render_side = 0; state.ubo_data.shadow_dual_paraboloid_render_zfar = 0; @@ -4001,7 +3998,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { clear_color = Color(0, 0, 0, 0); storage->frame.clear_request = false; - } else if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + } else if (!probe && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { clear_color = Color(0, 0, 0, 0); } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR) { @@ -4161,151 +4158,6 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glBindTexture(GL_TEXTURE_2D, env_radiance_tex); storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); } - -#if 0 - if (use_fb) { - - - - for(int i=0;i<VS::ARRAY_MAX;i++) { - glDisableVertexAttribArray(i); - } - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_SCISSOR_TEST); - glDepthMask(false); - - if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR]) { - - int hdr_tm = current_env->fx_param[VS::ENV_FX_PARAM_HDR_TONEMAPPER]; - switch(hdr_tm) { - case VS::ENV_FX_HDR_TONE_MAPPER_LINEAR: { - - - } break; - case VS::ENV_FX_HDR_TONE_MAPPER_LOG: { - copy_shader.set_conditional(CopyShaderGLES2::USE_LOG_TONEMAPPER,true); - - } break; - case VS::ENV_FX_HDR_TONE_MAPPER_REINHARDT: { - copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,true); - } break; - case VS::ENV_FX_HDR_TONE_MAPPER_REINHARDT_AUTOWHITE: { - - copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,true); - copy_shader.set_conditional(CopyShaderGLES2::USE_AUTOWHITE,true); - } break; - } - - - _process_hdr(); - } - if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) { - _process_glow_bloom(); - int glow_transfer_mode=current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_BLEND_MODE]; - if (glow_transfer_mode==1) - copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,true); - if (glow_transfer_mode==2) - copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,true); - } - - glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer); - - Size2 size; - if (current_rt) { - glBindFramebuffer(GL_FRAMEBUFFER, current_rt->fbo); - glViewport( 0,0,viewport.width,viewport.height); - size=Size2(viewport.width,viewport.height); - } else { - glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer); - glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height ); - size=Size2(viewport.width,viewport.height); - } - - //time to copy!!! - copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,current_env && current_env->fx_enabled[VS::ENV_FX_BCS]); - copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]); - copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]); - copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,current_env && current_env->fx_enabled[VS::ENV_FX_HDR]); - copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,true); - copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,current_env && current_env->fx_enabled[VS::ENV_FX_FXAA]); - - copy_shader.bind(); - //copy_shader.set_uniform(CopyShaderGLES2::SOURCE,0); - - if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) { - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, framebuffer.blur[0].color ); - glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::GLOW_SOURCE),1); - - } - - if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR]) { - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, current_vd->lum_color ); - glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::HDR_SOURCE),2); - copy_shader.set_uniform(CopyShaderGLES2::TONEMAP_EXPOSURE,float(current_env->fx_param[VS::ENV_FX_PARAM_HDR_EXPOSURE])); - copy_shader.set_uniform(CopyShaderGLES2::TONEMAP_WHITE,float(current_env->fx_param[VS::ENV_FX_PARAM_HDR_WHITE])); - - } - - if (current_env && current_env->fx_enabled[VS::ENV_FX_FXAA]) - copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Size2(1.0/size.x,1.0/size.y)); - - - if (current_env && current_env->fx_enabled[VS::ENV_FX_BCS]) { - - Vector3 bcs; - bcs.x=current_env->fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS]; - bcs.y=current_env->fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST]; - bcs.z=current_env->fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]; - copy_shader.set_uniform(CopyShaderGLES2::BCS,bcs); - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, framebuffer.color ); - glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0); - - _copy_screen_quad(); - - copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_AUTOWHITE,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_LOG_TONEMAPPER,false); - - state.scene_shader.set_conditional(SceneShaderGLES3::USE_8BIT_HDR,false); - - - if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR] && GLOBAL_DEF("rasterizer/debug_hdr",false)) { - _debug_luminances(); - } - } - - current_env=NULL; - current_debug=VS::SCENARIO_DEBUG_DISABLED; - if (GLOBAL_DEF("rasterizer/debug_shadow_maps",false)) { - _debug_shadows(); - } - //_debug_luminances(); - //_debug_samplers(); - - if (using_canvas_bg) { - using_canvas_bg=false; - glColorMask(1,1,1,1); //don't touch alpha - } -#endif } void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { @@ -4395,8 +4247,8 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ } zfar = light->param[VS::LIGHT_PARAM_RANGE]; - bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; - normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; + bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * light_instance->shadow_transform[p_pass].bias_scale; + normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * light_instance->shadow_transform[p_pass].bias_scale; fbo = directional_shadow.fbo; vp_height = directional_shadow.size; @@ -4514,8 +4366,8 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ glClear(GL_DEPTH_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); - state.ubo_data.shadow_z_offset = bias; - state.ubo_data.shadow_slope_scale = normal_bias; + state.ubo_data.z_offset = bias; + state.ubo_data.z_slope_scale = normal_bias; state.ubo_data.shadow_dual_paraboloid_render_side = dp_direction; state.ubo_data.shadow_dual_paraboloid_render_zfar = zfar; @@ -4745,7 +4597,7 @@ void RasterizerSceneGLES3::initialize() { { //directional light shadow directional_shadow.light_count = 0; - directional_shadow.size = nearest_power_of_2(GLOBAL_DEF("rendering/shadows/directional_shadow_size", 2048)); + directional_shadow.size = nearest_power_of_2(GLOBAL_DEF("rendering/shadows/directional_shadow_size", 4096)); glGenFramebuffers(1, &directional_shadow.fbo); glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); glGenTextures(1, &directional_shadow.depth); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 59b8e3fb35..3e15da52ab 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -111,7 +111,6 @@ public: float projection_matrix[16]; float camera_inverse_matrix[16]; float camera_matrix[16]; - float time[4]; float ambient_light_color[4]; float bg_color[4]; float fog_color_enabled[4]; @@ -119,14 +118,15 @@ public: float ambient_energy; float bg_energy; - float shadow_z_offset; - float shadow_slope_scale; + float z_offset; + float z_slope_scale; float shadow_dual_paraboloid_render_zfar; float shadow_dual_paraboloid_render_side; float screen_pixel_size[2]; float shadow_atlas_pixel_size[2]; float shadow_directional_pixel_size[2]; + float time; float z_far; float reflection_multiplier; float subsurface_scatter_width; @@ -360,10 +360,9 @@ public: bool ssr_enabled; int ssr_max_steps; - float ssr_accel; - float ssr_fade; + float ssr_fade_in; + float ssr_fade_out; float ssr_depth_tolerance; - bool ssr_smooth; bool ssr_roughness; bool ssao_enabled; @@ -439,10 +438,9 @@ public: ssr_enabled = false; ssr_max_steps = 64; - ssr_accel = 0.04; - ssr_fade = 2.0; + ssr_fade_in = 0.15; + ssr_fade_out = 2.0; ssr_depth_tolerance = 0.2; - ssr_smooth = true; ssr_roughness = true; ssao_enabled = false; @@ -527,7 +525,7 @@ public: virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_treshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); - virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_accel, float p_fade, float p_depth_tolerance, bool p_smooth, bool p_roughness); + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_radius2, float p_intensity2, float p_intensity, float p_bias, float p_light_affect, const Color &p_color, bool p_blur); virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); @@ -563,6 +561,7 @@ public: Transform transform; float farplane; float split; + float bias_scale; }; ShadowTransform shadow_transform[4]; @@ -598,7 +597,7 @@ public: virtual RID light_instance_create(RID p_light); virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass); + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0); virtual void light_instance_mark_visible(RID p_light_instance); /* REFLECTION INSTANCE */ @@ -637,9 +636,10 @@ public: MAX_REFLECTIONS = 1024, SORT_KEY_DEPTH_LAYER_SHIFT = 60, - SORT_KEY_UNSHADED_FLAG = uint64_t(1) << 59, - SORT_KEY_NO_DIRECTIONAL_FLAG = uint64_t(1) << 58, - SORT_KEY_GI_PROBES_FLAG = uint64_t(1) << 57, +//64 bits unsupported in MSVC +#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 59) +#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 58) +#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 57) SORT_KEY_SHADING_SHIFT = 57, SORT_KEY_SHADING_MASK = 7, SORT_KEY_MATERIAL_INDEX_SHIFT = 40, diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 54e99eb622..ac2cbcbd54 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1425,6 +1425,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { _shader_dirty_list.remove(&p_shader->dirty_list); p_shader->valid = false; + p_shader->ubo_size = 0; p_shader->uniforms.clear(); @@ -2244,6 +2245,10 @@ void RasterizerStorageGLES3::_update_material(Material *material) { if (material->shader && material->shader->dirty_list.in_list()) { _update_shader(material->shader); } + + if (material->shader && !material->shader->valid) + return; + //update caches { @@ -3102,6 +3107,7 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface) { } glDeleteVertexArrays(1, &surface->array_id); + glDeleteVertexArrays(1, &surface->instancing_array_id); for (int i = 0; i < surface->blend_shapes.size(); i++) { @@ -4268,7 +4274,6 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) { light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1; - light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1; light->color = Color(1, 1, 1, 1); light->shadow = false; @@ -4305,8 +4310,7 @@ void RasterizerStorageGLES3::light_set_param(RID p_light, VS::LightParam p_param case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: - case VS::LIGHT_PARAM_SHADOW_BIAS: - case VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE: { + case VS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; light->instance_change_notify(); @@ -5377,7 +5381,7 @@ void RasterizerStorageGLES3::update_particles() { shaders.particles.bind(); shaders.particles.set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, particles->amount); - shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, Color(frame.time[0], frame.time[1], frame.time[2], frame.time[3])); + shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, frame.time[0]); shaders.particles.set_uniform(ParticlesShaderGLES3::EXPLOSIVENESS, particles->explosiveness); shaders.particles.set_uniform(ParticlesShaderGLES3::LIFETIME, particles->lifetime); shaders.particles.set_uniform(ParticlesShaderGLES3::ATTRACTOR_COUNT, 0); @@ -5443,10 +5447,6 @@ void RasterizerStorageGLES3::update_particles() { } glDisable(GL_RASTERIZER_DISCARD); - - for (int i = 0; i < 6; i++) { - glDisableVertexAttribArray(i); - } } //////// @@ -6105,6 +6105,7 @@ RID RasterizerStorageGLES3::canvas_light_occluder_create() { co->index_id = 0; co->vertex_id = 0; co->len = 0; + glGenVertexArrays(1, &co->array_id); return canvas_occluder_owner.make_rid(co); } @@ -6176,7 +6177,7 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, if (!co->vertex_id) { glGenBuffers(1, &co->vertex_id); glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_DYNAMIC_DRAW); } else { glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); @@ -6189,7 +6190,7 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, glGenBuffers(1, &co->index_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); @@ -6199,6 +6200,12 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind co->len = lc; + glBindVertexArray(co->array_id); + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBindVertexArray(0); } } @@ -6427,6 +6434,8 @@ bool RasterizerStorageGLES3::free(RID p_rid) { if (co->vertex_id) glDeleteBuffers(1, &co->vertex_id); + glDeleteVertexArrays(1, &co->array_id); + canvas_occluder_owner.free(p_rid); memdelete(co); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 1357206bfa..e4bde96443 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -448,6 +448,7 @@ public: : dirty_list(this) { shader = NULL; + ubo_size = 0; valid = false; custom_code_id = 0; version = 1; @@ -1285,6 +1286,7 @@ public: struct CanvasOccluder : public RID_Data { + GLuint array_id; // 0 means, unconfigured GLuint vertex_id; // 0 means, unconfigured GLuint index_id; // 0 means, unconfigured PoolVector<Vector2> lines; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index b1f7b4c9bd..3376f99112 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -668,6 +668,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix"; actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] == "extra_matrix"; actions[VS::SHADER_CANVAS_ITEM].renames["TIME"] = "time"; + actions[VS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass"; actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 017009015e..68660b657f 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -20,7 +20,7 @@ layout(location=4) in highp vec2 uv_attrib; layout(std140) uniform CanvasItemData { //ubo:0 highp mat4 projection_matrix; - highp vec4 time; + highp float time; }; uniform highp mat4 modelview_matrix; @@ -59,6 +59,9 @@ out vec4 local_rot; out highp vec2 pos; #endif +const bool at_light_pass = true; +#else +const bool at_light_pass = false; #endif @@ -155,7 +158,7 @@ uniform sampler2D screen_texture; // texunit:-3 layout(std140) uniform CanvasItemData { highp mat4 projection_matrix; - highp vec4 time; + highp float time; }; @@ -191,6 +194,9 @@ in highp vec2 pos; #endif +const bool at_light_pass = true; +#else +const bool at_light_pass = false; #endif uniform mediump vec4 final_modulate; @@ -381,7 +387,7 @@ FRAGMENT_SHADER_CODE #ifdef SHADOW_FILTER_NEAREST - SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); #endif diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 5d8a532f87..7e7b083f73 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -28,7 +28,7 @@ uniform float prev_system_phase; uniform int total_particles; uniform float explosiveness; uniform float randomness; -uniform vec4 time; +uniform float time; uniform float delta; uniform int attractor_count; @@ -132,6 +132,7 @@ void main() { } uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID); + int index = int(gl_VertexID); if (restart) { shader_active=emitting; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 60efc953f9..fc38346baa 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -63,7 +63,6 @@ layout(std140) uniform SceneData { //ubo:0 highp mat4 projection_matrix; highp mat4 camera_inverse_matrix; highp mat4 camera_matrix; - highp vec4 time; highp vec4 ambient_light_color; highp vec4 bg_color; @@ -74,8 +73,8 @@ layout(std140) uniform SceneData { //ubo:0 float ambient_energy; float bg_energy; - float shadow_z_offset; - float shadow_z_slope_scale; + float z_offset; + float z_slope_scale; float shadow_dual_paraboloid_render_zfar; float shadow_dual_paraboloid_render_side; @@ -83,6 +82,7 @@ layout(std140) uniform SceneData { //ubo:0 vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float time; float z_far; float reflection_multiplier; float subsurface_scatter_width; @@ -245,7 +245,7 @@ void main() { normal = vec4(normal,0.0) * m; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - tangent.xyz = vec4(tangent.xyz,0.0) * mn; + tangent.xyz = vec4(tangent.xyz,0.0) * m; #endif } #endif @@ -319,7 +319,7 @@ VERTEX_SHADER_CODE //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset; + highp vec3 vtx = vertex_interp+normalize(vertex_interp)*z_offset; highp float distance = length(vtx); vtx = normalize(vtx); vtx.xy/=1.0-vtx.z; @@ -332,8 +332,8 @@ VERTEX_SHADER_CODE #else - float z_ofs = shadow_z_offset; - z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale; + float z_ofs = z_offset; + z_ofs += (1.0-abs(normal_interp.z))*z_slope_scale; vertex_interp.z-=z_ofs; #endif //RENDER_DEPTH_DUAL_PARABOLOID @@ -435,7 +435,6 @@ layout(std140) uniform SceneData { highp mat4 projection_matrix; highp mat4 camera_inverse_matrix; highp mat4 camera_matrix; - highp vec4 time; highp vec4 ambient_light_color; highp vec4 bg_color; @@ -446,8 +445,8 @@ layout(std140) uniform SceneData { float ambient_energy; float bg_energy; - float shadow_z_offset; - float shadow_z_slope_scale; + float z_offset; + float z_slope_scale; float shadow_dual_paraboloid_render_zfar; float shadow_dual_paraboloid_render_side; @@ -455,6 +454,7 @@ layout(std140) uniform SceneData { vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float time; float z_far; float reflection_multiplier; float subsurface_scatter_width; @@ -1543,7 +1543,7 @@ FRAGMENT_SHADER_CODE #if defined(LIGHT_USE_PSSM_BLEND) if (use_blend) { - shadow=mix(shadow, sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp)); + shadow=mix(shadow, sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp),pssm_blend); } #endif diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index 8eec71ecb6..cc41d36c37 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -38,7 +38,8 @@ uniform mat4 projection; uniform int num_steps; uniform float depth_tolerance; uniform float distance_fade; -uniform float acceleration; +uniform float curve_fade_in; + layout(location = 0) out vec4 frag_color; @@ -148,8 +149,6 @@ void main() { bool found=false; - //if acceleration > 0, distance between pixels gets larger each step. This allows covering a larger area - float accel=1.0+acceleration; float steps_taken=0.0; for(int i=0;i<num_steps;i++) { @@ -177,9 +176,6 @@ void main() { steps_taken+=1.0; prev_pos=pos; - z_advance*=accel; - w_advance*=accel; - line_advance*=accel; } @@ -207,41 +203,14 @@ void main() { vec2 final_pos; float grad; + grad=steps_taken/float(num_steps); + float initial_fade = curve_fade_in==0.0 ? 1.0 : pow(clamp(grad,0.0,1.0),curve_fade_in); + float fade = pow(clamp(1.0-grad,0.0,1.0),distance_fade)*initial_fade; + final_pos=pos; -#ifdef SMOOTH_ACCEL - //if the distance between point and prev point is >1, then take some samples in the middle for smoothing out the image - vec2 blend_dir = pos - prev_pos; - float steps = min(8.0,length(blend_dir)); - if (steps>2.0) { - vec2 blend_step = blend_dir/steps; - float blend_z = (z_to-z_from)/steps; - vec2 new_pos; - float subgrad=0.0; - for(float i=0.0;i<steps;i++) { - - new_pos = (prev_pos+blend_step*i); - float z = z_from+blend_z*i; - - depth = texture(source_depth, new_pos*pixel_size).r * 2.0 - 1.0; - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); - depth=-depth; - - subgrad=i/steps; - if (depth>z) - break; - } - final_pos = new_pos; - grad=(steps_taken+subgrad)/float(num_steps); - } else { -#endif - grad=steps_taken/float(num_steps); - final_pos=pos; -#ifdef SMOOTH_ACCEL - } -#endif @@ -327,10 +296,10 @@ void main() { final_color = textureLod(source_diffuse,final_pos*pixel_size,0.0); } - frag_color = vec4(final_color.rgb,pow(clamp(1.0-grad,0.0,1.0),distance_fade)*margin_blend); + frag_color = vec4(final_color.rgb,fade*margin_blend); #else - frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,pow(clamp(1.0-grad,0.0,1.0),distance_fade)*margin_blend); + frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,fade*margin_blend); #endif diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl index ba29ec52c7..d8302bd46e 100644 --- a/drivers/gles3/shaders/ssao.glsl +++ b/drivers/gles3/shaders/ssao.glsl @@ -12,7 +12,7 @@ void main() { [fragment] -#define NUM_SAMPLES (11) +#define NUM_SAMPLES (15) // If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower // miplevel to maintain reasonable spatial locality in the cache @@ -25,8 +25,20 @@ void main() { // This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent // taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9 -#define NUM_SPIRAL_TURNS (7) +const int ROTATIONS[] = int[]( 1, 1, 2, 3, 2, 5, 2, 3, 2, +3, 3, 5, 5, 3, 4, 7, 5, 5, 7, +9, 8, 5, 5, 7, 7, 7, 8, 5, 8, +11, 12, 7, 10, 13, 8, 11, 8, 7, 14, +11, 11, 13, 12, 13, 19, 17, 13, 11, 18, +19, 11, 11, 14, 17, 21, 15, 16, 17, 18, +13, 17, 11, 17, 19, 18, 25, 18, 19, 19, +29, 21, 19, 27, 31, 29, 21, 18, 17, 29, +31, 31, 23, 18, 25, 26, 25, 23, 19, 34, +19, 27, 21, 25, 39, 29, 17, 21, 27 ); + +//#define NUM_SPIRAL_TURNS (7) +const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES-1]; uniform sampler2D source_depth; //texunit:0 uniform highp usampler2D source_depth_mipmaps; //texunit:1 diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index e3ed9fe1af..96bfb295ea 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -113,13 +113,13 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { extension_guess["png"] = get_icon("Texture", "EditorIcons"); extension_guess["jpg"] = get_icon("Texture", "EditorIcons"); extension_guess["tex"] = get_icon("Texture", "EditorIcons"); - extension_guess["atex"] = get_icon("Texture", "EditorIcons"); + extension_guess["atlastex"] = get_icon("Texture", "EditorIcons"); extension_guess["dds"] = get_icon("Texture", "EditorIcons"); extension_guess["scn"] = get_icon("PackedScene", "EditorIcons"); extension_guess["tscn"] = get_icon("PackedScene", "EditorIcons"); extension_guess["xml"] = get_icon("PackedScene", "EditorIcons"); extension_guess["xscn"] = get_icon("PackedScene", "EditorIcons"); - extension_guess["mtl"] = get_icon("Material", "EditorIcons"); + extension_guess["material"] = get_icon("Material", "EditorIcons"); extension_guess["shd"] = get_icon("Shader", "EditorIcons"); extension_guess["gd"] = get_icon("GDScript", "EditorIcons"); } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 31c1402c8f..58ffa223fb 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -675,7 +675,12 @@ String EditorData::get_scene_title(int p_idx) const { return "[empty]"; if (edited_scene[p_idx].root->get_filename() == "") return "[unsaved]"; - return edited_scene[p_idx].root->get_filename().get_file(); + bool show_ext = EDITOR_DEF("interface/scene_tabs/show_extension", false); + String name = edited_scene[p_idx].root->get_filename().get_file(); + if (!show_ext) { + name = name.get_basename(); + } + return name; } String EditorData::get_scene_path(int p_idx) const { diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index cb1b958cca..5cd00738a2 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -211,6 +211,7 @@ EditorExportPreset::EditorExportPreset() { void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags) { String host = EditorSettings::get_singleton()->get("network/debug/remote_host"); + int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (p_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST) host = "localhost"; @@ -230,7 +231,7 @@ void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags) r_flags.push_back("-rdebug"); - r_flags.push_back(host + ":" + String::num(GLOBAL_DEF("network/debug/remote_port", 6007))); + r_flags.push_back(host + ":" + String::num(remote_port)); List<String> breakpoints; ScriptEditor::get_singleton()->get_breakpoints(&breakpoints); @@ -621,6 +622,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, co void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags) { String host = EditorSettings::get_singleton()->get("network/debug/remote_host"); + int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (p_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST) host = "localhost"; @@ -640,7 +642,7 @@ void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags r_flags.push_back("-rdebug"); - r_flags.push_back(host + ":" + String::num(GLOBAL_DEF("network/debug/remote_port", 6007))); + r_flags.push_back(host + ":" + String::num(remote_port)); List<String> breakpoints; ScriptEditor::get_singleton()->get_breakpoints(&breakpoints); @@ -1941,14 +1943,14 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func atex->set_region(region); atex->set_margin(margin); - String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpatlas.atex"; + String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpatlas.atlastex"; Error err = ResourceSaver::save(path,atex); if (err!=OK) { EditorNode::add_io_error(TTR("Could not save atlas subtexture:")+" "+path); return ERR_CANT_CREATE; } Vector<uint8_t> data = FileAccess::get_file_as_array(path); - String dst_path = F->get().operator String().get_basename()+".atex"; + String dst_path = F->get().operator String().get_basename()+".atlastex"; err = p_func(p_udata,dst_path,data,counter++,files.size()); saved.insert(dst_path); if (err) @@ -2109,6 +2111,7 @@ static int _get_pad(int p_alignment, int p_n) { void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags) { String host = EditorSettings::get_singleton()->get("network/debug/remote_host"); + int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (p_flags&EXPORT_REMOTE_DEBUG_LOCALHOST) host="localhost"; @@ -2128,7 +2131,7 @@ void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags r_flags.push_back("-rdebug"); - r_flags.push_back(host+":"+String::num(GLOBAL_DEF("network/debug/remote_port", 6007))); + r_flags.push_back(host+":"+String::num(remote_port)); List<String> breakpoints; ScriptEditor::get_singleton()->get_breakpoints(&breakpoints); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 25fade46d6..c2a408e8ab 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -1300,16 +1300,21 @@ EditorFileDialog::EditorFileDialog() { favorite->connect("toggled", this, "_favorite_toggled"); pathhb->add_child(favorite); + Ref<ButtonGroup> view_mode_group; + view_mode_group.instance(); + mode_thumbnails = memnew(ToolButton); mode_thumbnails->connect("pressed", this, "set_display_mode", varray(DISPLAY_THUMBNAILS)); mode_thumbnails->set_toggle_mode(true); mode_thumbnails->set_pressed(display_mode == DISPLAY_THUMBNAILS); + mode_thumbnails->set_button_group(view_mode_group); pathhb->add_child(mode_thumbnails); mode_list = memnew(ToolButton); mode_list->connect("pressed", this, "set_display_mode", varray(DISPLAY_LIST)); mode_list->set_toggle_mode(true); mode_list->set_pressed(display_mode == DISPLAY_LIST); + mode_list->set_button_group(view_mode_group); pathhb->add_child(mode_list); drives = memnew(OptionButton); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8fa9cbdc1c..297be5e05f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -73,10 +73,10 @@ #include "plugins/collision_polygon_2d_editor_plugin.h" #include "plugins/collision_polygon_editor_plugin.h" #include "plugins/collision_shape_2d_editor_plugin.h" -#include "plugins/color_ramp_editor_plugin.h" #include "plugins/cube_grid_theme_editor_plugin.h" #include "plugins/curve_editor_plugin.h" #include "plugins/gi_probe_editor_plugin.h" +#include "plugins/gradient_editor_plugin.h" #include "plugins/gradient_texture_editor_plugin.h" #include "plugins/item_list_editor_plugin.h" #include "plugins/light_occluder_2d_editor_plugin.h" @@ -272,6 +272,8 @@ void EditorNode::_notification(int p_what) { } editor_selection->update(); + scene_root->set_size_override(true, Size2(GlobalConfig::get_singleton()->get("display/window/width"), GlobalConfig::get_singleton()->get("display/window/height"))); + ResourceImporterTexture::get_singleton()->update_imports(); } if (p_what == NOTIFICATION_ENTER_TREE) { @@ -340,6 +342,14 @@ void EditorNode::_notification(int p_what) { play_button_panel->add_style_override("panel", gui_base->get_stylebox("PlayButtonPanel", "EditorStyles")); scene_root_parent->add_style_override("panel", gui_base->get_stylebox("Content", "EditorStyles")); bottom_panel->add_style_override("panel", gui_base->get_stylebox("Content", "EditorStyles")); + scene_tabs->add_style_override("tab_fg", gui_base->get_stylebox("SceneTabFG", "EditorStyles")); + scene_tabs->add_style_override("tab_bg", gui_base->get_stylebox("SceneTabBG", "EditorStyles")); + if (bool(EDITOR_DEF("interface/scene_tabs/resize_if_many_tabs", true))) { + scene_tabs->set_min_width(int(EDITOR_DEF("interface/scene_tabs/minimum_width", 50)) * EDSCALE); + } else { + scene_tabs->set_min_width(0); + } + _update_scene_tabs(); } } @@ -4267,7 +4277,47 @@ void EditorNode::_scene_tab_closed(int p_tab) { } } +void EditorNode::_scene_tab_hover(int p_tab) { + if (bool(EDITOR_DEF("interface/scene_tabs/show_thumbnail_on_hover", true)) == false) { + return; + } + int current_tab = scene_tabs->get_current_tab(); + + if (p_tab == current_tab || p_tab < 0) { + tab_preview_panel->hide(); + } else { + String path = editor_data.get_scene_path(p_tab); + EditorResourcePreview::get_singleton()->queue_resource_preview(path, this, "_thumbnail_done", p_tab); + } +} + +void EditorNode::_scene_tab_exit() { + tab_preview_panel->hide(); +} + +void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { + Ref<InputEventMouseButton> mb = p_input; + + if (mb.is_valid()) { + if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed() && scene_tabs->get_hovered_tab() >= 0) { + _scene_tab_closed(scene_tabs->get_hovered_tab()); + } + } +} + +void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata) { + int p_tab = p_udata.operator signed int(); + if (p_preview.is_valid()) { + Rect2 rect = scene_tabs->get_tab_rect(p_tab); + rect.position += scene_tabs->get_global_position(); + tab_preview->set_texture(p_preview); + tab_preview_panel->set_position(rect.position + Vector2(0, rect.size.height)); + tab_preview_panel->show(); + } +} + void EditorNode::_scene_tab_changed(int p_tab) { + tab_preview_panel->hide(); //print_line("set current 1 "); bool unsaved = (saved_version != editor_data.get_undo_redo().get_version()); @@ -4758,7 +4808,6 @@ void EditorNode::_dim_timeout() { } void EditorNode::_check_gui_base_size() { - print_line(itos(int(gui_base->get_size().width))); if (gui_base->get_size().width > 1200 * EDSCALE) { for (int i = 0; i < singleton->main_editor_button_vb->get_child_count(); i++) { ToolButton *btn = singleton->main_editor_button_vb->get_child(i)->cast_to<ToolButton>(); @@ -4835,6 +4884,10 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("set_current_version", &EditorNode::set_current_version); ClassDB::bind_method("_scene_tab_changed", &EditorNode::_scene_tab_changed); ClassDB::bind_method("_scene_tab_closed", &EditorNode::_scene_tab_closed); + ClassDB::bind_method("_scene_tab_hover", &EditorNode::_scene_tab_hover); + ClassDB::bind_method("_scene_tab_exit", &EditorNode::_scene_tab_exit); + ClassDB::bind_method("_scene_tab_input", &EditorNode::_scene_tab_input); + ClassDB::bind_method("_thumbnail_done", &EditorNode::_thumbnail_done); ClassDB::bind_method("_scene_tab_script_edited", &EditorNode::_scene_tab_script_edited); ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state); ClassDB::bind_method("_update_scene_tabs", &EditorNode::_update_scene_tabs); @@ -5179,13 +5232,31 @@ EditorNode::EditorNode() { main_editor_tabs->connect("tab_changed",this,"_editor_select"); main_editor_tabs->set_tab_close_display_policy(Tabs::SHOW_NEVER); */ + tab_preview_panel = memnew(Panel); + tab_preview_panel->set_size(Size2(100, 100) * EDSCALE); + tab_preview_panel->hide(); + tab_preview_panel->set_self_modulate(Color(1, 1, 1, 0.7)); + gui_base->add_child(tab_preview_panel); + + tab_preview = memnew(TextureRect); + tab_preview->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); + tab_preview->set_size(Size2(96, 96) * EDSCALE); + tab_preview->set_position(Point2(2, 2) * EDSCALE); + tab_preview_panel->add_child(tab_preview); + scene_tabs = memnew(Tabs); + scene_tabs->add_style_override("tab_fg", gui_base->get_stylebox("SceneTabFG", "EditorStyles")); + scene_tabs->add_style_override("tab_bg", gui_base->get_stylebox("SceneTabBG", "EditorStyles")); scene_tabs->add_tab("unsaved"); scene_tabs->set_tab_align(Tabs::ALIGN_LEFT); scene_tabs->set_tab_close_display_policy((bool(EDITOR_DEF("interface/always_show_close_button_in_scene_tabs", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY)); + scene_tabs->set_min_width(int(EDITOR_DEF("interface/scene_tabs/minimum_width", 50)) * EDSCALE); scene_tabs->connect("tab_changed", this, "_scene_tab_changed"); scene_tabs->connect("right_button_pressed", this, "_scene_tab_script_edited"); scene_tabs->connect("tab_close", this, "_scene_tab_closed"); + scene_tabs->connect("tab_hover", this, "_scene_tab_hover"); + scene_tabs->connect("mouse_exited", this, "_scene_tab_exit"); + scene_tabs->connect("gui_input", this, "_scene_tab_input"); HBoxContainer *tabbar_container = memnew(HBoxContainer); scene_tabs->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -6040,7 +6111,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(Polygon2DEditorPlugin(this))); add_editor_plugin(memnew(LightOccluder2DEditorPlugin(this))); add_editor_plugin(memnew(NavigationPolygonEditorPlugin(this))); - add_editor_plugin(memnew(ColorRampEditorPlugin(this))); + add_editor_plugin(memnew(GradientEditorPlugin(this))); add_editor_plugin(memnew(GradientTextureEditorPlugin(this))); add_editor_plugin(memnew(CollisionShape2DEditorPlugin(this))); add_editor_plugin(memnew(CurveTextureEditorPlugin(this))); diff --git a/editor/editor_node.h b/editor/editor_node.h index bb5b57a454..0f4561572a 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -233,6 +233,8 @@ private: //main tabs Tabs *scene_tabs; + Panel *tab_preview_panel; + TextureRect *tab_preview; int tab_closing; bool exiting; @@ -556,6 +558,10 @@ private: void _dock_popup_exit(); void _scene_tab_changed(int p_tab); void _scene_tab_closed(int p_tab); + void _scene_tab_hover(int p_tab); + void _scene_tab_exit(); + void _scene_tab_input(const Ref<InputEvent> &p_input); + void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata); void _scene_tab_script_edited(int p_tab); Dictionary _get_main_scene_state(); diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index c97dc9a88e..a8106b4eec 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -42,6 +42,7 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li String resource_path = GlobalConfig::get_singleton()->get_resource_path(); String remote_host = EditorSettings::get_singleton()->get("network/debug/remote_host"); + int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (resource_path != "") { args.push_back("-path"); @@ -50,7 +51,7 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li if (true) { args.push_back("-rdebug"); - args.push_back(remote_host + ":" + String::num(GLOBAL_GET("network/debug/remote_port"))); + args.push_back(remote_host + ":" + String::num(remote_port)); } args.push_back("-epid"); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index ec7e7597d5..485f8236de 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -292,6 +292,12 @@ void EditorSettings::create() { dir->change_dir(".."); } + if (dir->change_dir("script_templates") != OK) { + dir->make_dir("script_templates"); + } else { + dir->change_dir(".."); + } + if (dir->change_dir("tmp") != OK) { dir->make_dir("tmp"); } else { @@ -502,7 +508,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("interface/source_font_size", 14); hints["interface/source_font_size"] = PropertyInfo(Variant::INT, "interface/source_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); set("interface/custom_font", ""); - hints["interface/custom_font"] = PropertyInfo(Variant::STRING, "interface/custom_font", PROPERTY_HINT_GLOBAL_FILE, "*.fnt", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/custom_font"] = PropertyInfo(Variant::STRING, "interface/custom_font", PROPERTY_HINT_GLOBAL_FILE, "*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); set("interface/dim_editor_on_dialog_popup", true); set("interface/dim_amount", 0.6f); hints["interface/dim_amount"] = PropertyInfo(Variant::REAL, "interface/dim_amount", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT); @@ -522,6 +528,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("interface/theme/custom_theme", ""); hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + set("interface/scene_tabs/show_extension", false); + set("interface/scene_tabs/show_thumbnail_on_hover", true); + set("interface/scene_tabs/resize_if_many_tabs", true); + set("interface/scene_tabs/minimum_width", 50); + hints["interface/scene_tabs/minimum_width"] = PropertyInfo(Variant::INT, "interface/scene_tabs/minimum_width", PROPERTY_HINT_RANGE, "50,500,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + set("filesystem/directories/autoscan_project_path", ""); hints["filesystem/directories/autoscan_project_path"] = PropertyInfo(Variant::STRING, "filesystem/directories/autoscan_project_path", PROPERTY_HINT_GLOBAL_DIR); set("filesystem/directories/default_project_path", ""); @@ -569,7 +581,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1"); set("text_editor/theme/font", ""); - hints["text_editor/theme/font"] = PropertyInfo(Variant::STRING, "text_editor/theme/font", PROPERTY_HINT_GLOBAL_FILE, "*.fnt"); + hints["text_editor/theme/font"] = PropertyInfo(Variant::STRING, "text_editor/theme/font", PROPERTY_HINT_GLOBAL_FILE, "*.font"); set("text_editor/completion/auto_brace_complete", false); set("text_editor/files/restore_scripts_on_load", true); set("text_editor/completion/complete_file_paths", true); @@ -586,7 +598,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("editors/3d/grid_color", Color(0, 1, 0, 0.2)); hints["editors/3d/grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/grid_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - set("editors/3d/default_fov", 45.0); + set("editors/3d/default_fov", 55.0); set("editors/3d/default_z_near", 0.1); set("editors/3d/default_z_far", 500.0); @@ -619,7 +631,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("editors/poly_editor/point_grab_radius", 8); - set("run/window_placement/rect", 0); + set("run/window_placement/rect", 1); hints["run/window_placement/rect"] = PropertyInfo(Variant::INT, "run/window_placement/rect", PROPERTY_HINT_ENUM, "Default,Centered,Custom Position,Force Maximized,Force Full Screen"); String screen_hints = TTR("Default (Same as Editor)"); for (int i = 0; i < OS::get_singleton()->get_screen_count(); i++) { @@ -946,6 +958,25 @@ bool EditorSettings::save_text_editor_theme_as(String p_file) { return false; } +Vector<String> EditorSettings::get_script_templates(const String &p_extension) { + + Vector<String> templates; + DirAccess *d = DirAccess::open(settings_path + "/script_templates"); + if (d) { + d->list_dir_begin(); + String file = d->get_next(); + while (file != String()) { + if (file.get_extension() == p_extension) { + templates.push_back(file.get_basename()); + } + file = d->get_next(); + } + d->list_dir_end(); + memdelete(d); + } + return templates; +} + bool EditorSettings::_save_text_editor_theme(String p_file) { String theme_section = "color_theme"; Ref<ConfigFile> cf = memnew(ConfigFile); // hex is better? diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 7b45e28350..d5adb84b63 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -159,6 +159,8 @@ public: bool save_text_editor_theme(); bool save_text_editor_theme_as(String p_file); + Vector<String> get_script_templates(const String &p_extension); + void add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcut); bool is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const; Ref<ShortCut> get_shortcut(const String &p_name) const; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index b6952c3024..e6df58bc60 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -307,6 +307,8 @@ Ref<Theme> create_editor_theme() { theme->set_color("font_color_bg", "TabContainer", light_color_2); theme->set_icon("menu", "TabContainer", theme->get_icon("TabMenu", "EditorIcons")); theme->set_icon("menu_hl", "TabContainer", theme->get_icon("TabMenu", "EditorIcons")); + theme->set_stylebox("SceneTabFG", "EditorStyles", make_flat_stylebox(base_color, 10, 5, 10, 5)); + theme->set_stylebox("SceneTabBG", "EditorStyles", make_empty_stylebox(6, 5, 6, 5)); // Debugger Ref<StyleBoxFlat> style_panel_debugger = make_flat_stylebox(dark_color_2, 0, 4, 0, 0); diff --git a/editor/icons/icon_h_button_array.png b/editor/icons/icon_h_button_array.png Binary files differdeleted file mode 100644 index baf3386801..0000000000 --- a/editor/icons/icon_h_button_array.png +++ /dev/null diff --git a/editor/icons/icon_v_button_array.png b/editor/icons/icon_v_button_array.png Binary files differdeleted file mode 100644 index d7ea9cc375..0000000000 --- a/editor/icons/icon_v_button_array.png +++ /dev/null diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index 85d446f38a..9214b8f45e 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -128,7 +128,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const xlt = cxl; } - String save_path = p_source_file.get_basename() + "." + translations[i]->get_locale() + ".xl"; + String save_path = p_source_file.get_basename() + "." + translations[i]->get_locale() + ".translation"; ResourceSaver::save(save_path, xlt); if (r_gen_files) { diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 342808f9e1..1c5aa95ff1 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -33,7 +33,6 @@ #include "os/file_access.h" #include "scene/resources/mesh.h" #include "scene/resources/surface_tool.h" -#include "scene/resources/surface_tool.h" String ResourceImporterOBJ::get_importer_name() const { @@ -49,7 +48,7 @@ void ResourceImporterOBJ::get_recognized_extensions(List<String> *p_extensions) p_extensions->push_back("obj"); } String ResourceImporterOBJ::get_save_extension() const { - return "msh"; + return "mesh"; } String ResourceImporterOBJ::get_resource_type() const { @@ -244,7 +243,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s } */ - Error err = ResourceSaver::save(p_save_path + ".msh", mesh); + Error err = ResourceSaver::save(p_save_path + ".mesh", mesh); return err; } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index d2d2d45a47..2409f6707d 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -987,7 +987,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String if (!p_materials.has(mat)) { - String ext_name = p_base_path + "." + _make_extname(mat->get_name()) + ".mtl"; + String ext_name = p_base_path + "." + _make_extname(mat->get_name()) + ".material"; if (FileAccess::exists(ext_name)) { //if exists, use it Ref<Material> existing = ResourceLoader::load(ext_name); @@ -1015,7 +1015,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String if (!p_meshes.has(mesh)) { - String ext_name = p_base_path + "." + _make_extname(mesh->get_name()) + ".msh"; + String ext_name = p_base_path + "." + _make_extname(mesh->get_name()) + ".mesh"; if (FileAccess::exists(ext_name)) { //if exists, use it Ref<ArrayMesh> existing = ResourceLoader::load(ext_name); @@ -1040,7 +1040,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String if (!p_materials.has(mat)) { - String ext_name = p_base_path + "." + _make_extname(mat->get_name()) + ".mtl"; + String ext_name = p_base_path + "." + _make_extname(mat->get_name()) + ".material"; if (FileAccess::exists(ext_name)) { //if exists, use it Ref<Material> existing = ResourceLoader::load(ext_name); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 7e27f6c618..1a88c45eac 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -144,8 +144,12 @@ String ResourceImporterTexture::get_resource_type() const { bool ResourceImporterTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { - if (p_option == "compress/lossy_quality" && int(p_options["compress/mode"]) != COMPRESS_LOSSY) - return false; + if (p_option == "compress/lossy_quality") { + int compress_mode = int(p_options["compress/mode"]); + if (compress_mode != COMPRESS_LOSSY && compress_mode != COMPRESS_VIDEO_RAM) { + return false; + } + } return true; } @@ -277,7 +281,7 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String if (p_force_rgbe && image->get_format() >= Image::FORMAT_R8 && image->get_format() <= Image::FORMAT_RGBE9995) { image->convert(Image::FORMAT_RGBE9995); } else { - image->compress(p_vram_compression, p_texture_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR); + image->compress(p_vram_compression, p_texture_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR, p_lossy_quality); } format |= image->get_format(); @@ -382,8 +386,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String //Android, GLES 2.x _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe); r_platform_variants->push_back("etc"); - //_save_stex(image,p_save_path+".etc2.stex",compress_mode,lossy,Image::COMPRESS_ETC2,mipmaps,tex_flags,stream); - //r_platform_variants->push_back("etc2"); + _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe); + r_platform_variants->push_back("etc2"); _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe); r_platform_variants->push_back("s3tc"); diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 92c1aa47db..7841baa02e 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -48,7 +48,7 @@ void ResourceImporterWAV::get_recognized_extensions(List<String> *p_extensions) p_extensions->push_back("wav"); } String ResourceImporterWAV::get_save_extension() const { - return "smp"; + return "sample"; } String ResourceImporterWAV::get_resource_type() const { @@ -485,7 +485,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s sample->set_loop_end(loop_end); sample->set_stereo(format_channels == 2); - ResourceSaver::save(p_save_path + ".smp", sample); + ResourceSaver::save(p_save_path + ".sample", sample); return OK; } diff --git a/editor/io_plugins/editor_font_import_plugin.cpp b/editor/io_plugins/editor_font_import_plugin.cpp index fa66328887..9831e08cf1 100644 --- a/editor/io_plugins/editor_font_import_plugin.cpp +++ b/editor/io_plugins/editor_font_import_plugin.cpp @@ -533,16 +533,16 @@ class EditorFontImportDialog : public ConfirmationDialog { return; } - if (dest->get_line_edit()->get_text().get_file()==".fnt") { - dest->get_line_edit()->set_text(dest->get_line_edit()->get_text().get_base_dir() + "/" + source->get_line_edit()->get_text().get_file().get_basename() + ".fnt" ); + if (dest->get_line_edit()->get_text().get_file()==".font") { + dest->get_line_edit()->set_text(dest->get_line_edit()->get_text().get_base_dir() + "/" + source->get_line_edit()->get_text().get_file().get_basename() + ".font" ); } if (dest->get_line_edit()->get_text().get_extension() == dest->get_line_edit()->get_text()) { - dest->get_line_edit()->set_text(dest->get_line_edit()->get_text() + ".fnt"); + dest->get_line_edit()->set_text(dest->get_line_edit()->get_text() + ".font"); } - if (dest->get_line_edit()->get_text().get_extension().to_lower() != "fnt") { - error_dialog->set_text(TTR("Invalid file extension.\nPlease use .fnt.")); + if (dest->get_line_edit()->get_text().get_extension().to_lower() != "font") { + error_dialog->set_text(TTR("Invalid file extension.\nPlease use .font.")); error_dialog->popup_centered(Size2(200,100)); return; } @@ -665,7 +665,7 @@ public: // List<String> fl; Ref<BitmapFont> font= memnew(BitmapFont); - dest->get_file_dialog()->add_filter("*.fnt ; Font" ); + dest->get_file_dialog()->add_filter("*.font ; Font" ); /* ResourceSaver::get_recognized_extensions(font,&fl); for(List<String>::Element *E=fl.front();E;E=E->next()) { @@ -1690,7 +1690,7 @@ void EditorFontImportPlugin::import_from_drop(const Vector<String>& p_drop, cons if (ext=="ttf" || ext=="otf" || ext=="fnt") { import_dialog(); - dialog->set_source_and_dest(p_drop[i],p_dest_path.plus_file(file.get_basename()+".fnt")); + dialog->set_source_and_dest(p_drop[i],p_dest_path.plus_file(file.get_basename()+".font")); break; } } diff --git a/editor/io_plugins/editor_mesh_import_plugin.cpp b/editor/io_plugins/editor_mesh_import_plugin.cpp index a8ecc2f10e..0c9f3a3f37 100644 --- a/editor/io_plugins/editor_mesh_import_plugin.cpp +++ b/editor/io_plugins/editor_mesh_import_plugin.cpp @@ -262,7 +262,7 @@ public: imd->add_source(EditorImportPlugin::validate_source_path(meshes[i])); - String file_path = dst.plus_file(meshes[i].get_file().get_basename()+".msh"); + String file_path = dst.plus_file(meshes[i].get_file().get_basename()+".mesh"); plugin->import(file_path,imd); } diff --git a/editor/io_plugins/editor_sample_import_plugin.cpp b/editor/io_plugins/editor_sample_import_plugin.cpp index 7836b60fde..0909b96cdc 100644 --- a/editor/io_plugins/editor_sample_import_plugin.cpp +++ b/editor/io_plugins/editor_sample_import_plugin.cpp @@ -299,7 +299,7 @@ public: error_dialog->popup_centered(Size2(200,100)*EDSCALE); } - dst = dst.plus_file(samples[i].get_file().get_basename()+".smp"); + dst = dst.plus_file(samples[i].get_file().get_basename()+".sample"); plugin->import(dst,imd); } @@ -910,13 +910,13 @@ Vector<uint8_t> EditorSampleExportPlugin::custom_export(String& p_path,const Ref imd->set_option("edit/loop",false); imd->set_option("compress/mode",1); - String savepath = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/smpconv.smp"); + String savepath = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/smpconv.sample"); Error err = EditorSampleImportPlugin::singleton->import(savepath,imd); ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>()); - p_path=p_path.get_basename()+".converted.smp"; + p_path=p_path.get_basename()+".converted.sample"; return FileAccess::get_file_as_array(savepath); } diff --git a/editor/io_plugins/editor_texture_import_plugin.cpp b/editor/io_plugins/editor_texture_import_plugin.cpp index e860866d24..d48675fa30 100644 --- a/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/editor/io_plugins/editor_texture_import_plugin.cpp @@ -596,7 +596,7 @@ void EditorTextureImportDialog::_mode_changed(int p_mode) { size->show(); file_select->set_mode(EditorFileDialog::MODE_OPEN_FILE); - save_file_select->add_filter("*.ltex;"+TTR("Large Texture")); + save_file_select->add_filter("*.largetex;"+TTR("Large Texture")); texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER); texture_options->set_quality(0.7); @@ -1097,7 +1097,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc int cell_size=from->get_option("large_cell_size"); ERR_FAIL_COND_V(cell_size<128 || cell_size>16384,ERR_CANT_OPEN); - EditorProgress pg("ltex",TTR("Import Large Texture"),3); + EditorProgress pg("largetex",TTR("Import Large Texture"),3); pg.step(TTR("Load Source Image"),0); Image img; @@ -1317,9 +1317,9 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc String spath = from->get_source_path(E->get()).get_file(); if (p_external) { - apath = p_path.get_base_dir().plus_file(spath.get_basename()+"."+from->get_source_path(E->get()).md5_text()+".atex"); + apath = p_path.get_base_dir().plus_file(spath.get_basename()+"."+from->get_source_path(E->get()).md5_text()+".atlastex"); } else { - apath = p_path.get_base_dir().plus_file(spath.get_basename()+".atex"); + apath = p_path.get_base_dir().plus_file(spath.get_basename()+".atlastex"); } Ref<AtlasTexture> at; diff --git a/editor/io_plugins/editor_translation_import_plugin.cpp b/editor/io_plugins/editor_translation_import_plugin.cpp index caa0659046..5b15b94006 100644 --- a/editor/io_plugins/editor_translation_import_plugin.cpp +++ b/editor/io_plugins/editor_translation_import_plugin.cpp @@ -258,7 +258,7 @@ public: imd->set_option("skip_first",ignore_first->is_pressed()); imd->set_option("compress",compress->is_pressed()); - String savefile = save_path->get_text().plus_file(import_path->get_text().get_file().get_basename()+"."+locale+".xl"); + String savefile = save_path->get_text().plus_file(import_path->get_text().get_file().get_basename()+"."+locale+".translation"); Error err = plugin->import(savefile,imd); if (err!=OK) { error_dialog->set_text(TTR("Couldn't import!")); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 17fb953f3f..28c5b89741 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1377,19 +1377,18 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { name_dialog->set_title(TTR("Create New Animation")); name_dialog->set_hide_on_ok(false); add_child(name_dialog); - name = memnew(LineEdit); - name_dialog->add_child(name); - name->set_position(Point2(18, 30)); - name->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 10); - name_dialog->register_text_enter(name); + VBoxContainer *vb = memnew(VBoxContainer); + name_dialog->add_child(vb); l = memnew(Label); l->set_text(TTR("Animation Name:")); - l->set_position(Point2(10, 10)); - - name_dialog->add_child(l); + vb->add_child(l); name_title = l; + name = memnew(LineEdit); + vb->add_child(name); + name_dialog->register_text_enter(name); + error_dialog = memnew(ConfirmationDialog); error_dialog->get_ok()->set_text(TTR("Close")); //error_dialog->get_cancel()->set_text("Close"); diff --git a/editor/plugins/color_ramp_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index e4172db415..9884db934b 100644 --- a/editor/plugins/color_ramp_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -27,15 +27,15 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "color_ramp_editor_plugin.h" +#include "gradient_editor_plugin.h" #include "canvas_item_editor_plugin.h" #include "spatial_editor_plugin.h" -ColorRampEditorPlugin::ColorRampEditorPlugin(EditorNode *p_node) { +GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { editor = p_node; - ramp_editor = memnew(ColorRampEdit); + ramp_editor = memnew(GradientEdit); add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, ramp_editor); @@ -44,21 +44,21 @@ ColorRampEditorPlugin::ColorRampEditorPlugin(EditorNode *p_node) { ramp_editor->connect("ramp_changed", this, "ramp_changed"); } -void ColorRampEditorPlugin::edit(Object *p_object) { +void GradientEditorPlugin::edit(Object *p_object) { - Gradient *color_ramp = p_object->cast_to<Gradient>(); - if (!color_ramp) + Gradient *gradient = p_object->cast_to<Gradient>(); + if (!gradient) return; - color_ramp_ref = Ref<Gradient>(color_ramp); - ramp_editor->set_points(color_ramp_ref->get_points()); + gradient_ref = Ref<Gradient>(gradient); + ramp_editor->set_points(gradient_ref->get_points()); } -bool ColorRampEditorPlugin::handles(Object *p_object) const { +bool GradientEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("ColorRamp"); + return p_object->is_class("Gradient"); } -void ColorRampEditorPlugin::make_visible(bool p_visible) { +void GradientEditorPlugin::make_visible(bool p_visible) { if (p_visible) { ramp_editor->show(); @@ -67,43 +67,43 @@ void ColorRampEditorPlugin::make_visible(bool p_visible) { } } -void ColorRampEditorPlugin::_ramp_changed() { +void GradientEditorPlugin::_ramp_changed() { - if (color_ramp_ref.is_valid()) { + if (gradient_ref.is_valid()) { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); //Not sure if I should convert this data to PoolVector Vector<float> new_offsets = ramp_editor->get_offsets(); Vector<Color> new_colors = ramp_editor->get_colors(); - Vector<float> old_offsets = color_ramp_ref->get_offsets(); - Vector<Color> old_colors = color_ramp_ref->get_colors(); + Vector<float> old_offsets = gradient_ref->get_offsets(); + Vector<Color> old_colors = gradient_ref->get_colors(); if (old_offsets.size() != new_offsets.size()) ur->create_action(TTR("Add/Remove Color Ramp Point")); else ur->create_action(TTR("Modify Color Ramp"), UndoRedo::MERGE_ENDS); - ur->add_do_method(this, "undo_redo_color_ramp", new_offsets, new_colors); - ur->add_undo_method(this, "undo_redo_color_ramp", old_offsets, old_colors); + ur->add_do_method(this, "undo_redo_gradient", new_offsets, new_colors); + ur->add_undo_method(this, "undo_redo_gradient", old_offsets, old_colors); ur->commit_action(); //color_ramp_ref->set_points(ramp_editor->get_points()); } } -void ColorRampEditorPlugin::_undo_redo_color_ramp(const Vector<float> &offsets, +void GradientEditorPlugin::_undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors) { - color_ramp_ref->set_offsets(offsets); - color_ramp_ref->set_colors(colors); - ramp_editor->set_points(color_ramp_ref->get_points()); + gradient_ref->set_offsets(offsets); + gradient_ref->set_colors(colors); + ramp_editor->set_points(gradient_ref->get_points()); ramp_editor->update(); } -ColorRampEditorPlugin::~ColorRampEditorPlugin() { +GradientEditorPlugin::~GradientEditorPlugin() { } -void ColorRampEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("ramp_changed"), &ColorRampEditorPlugin::_ramp_changed); - ClassDB::bind_method(D_METHOD("undo_redo_color_ramp", "offsets", "colors"), &ColorRampEditorPlugin::_undo_redo_color_ramp); +void GradientEditorPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("ramp_changed"), &GradientEditorPlugin::_ramp_changed); + ClassDB::bind_method(D_METHOD("undo_redo_gradient", "offsets", "colors"), &GradientEditorPlugin::_undo_redo_gradient); } diff --git a/editor/plugins/color_ramp_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index 35446062b5..843e98a917 100644 --- a/editor/plugins/color_ramp_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -32,21 +32,21 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/gui/color_ramp_edit.h" +#include "scene/gui/gradient_edit.h" -class ColorRampEditorPlugin : public EditorPlugin { +class GradientEditorPlugin : public EditorPlugin { - GDCLASS(ColorRampEditorPlugin, EditorPlugin); + GDCLASS(GradientEditorPlugin, EditorPlugin); bool _2d; - Ref<Gradient> color_ramp_ref; - ColorRampEdit *ramp_editor; + Ref<Gradient> gradient_ref; + GradientEdit *ramp_editor; EditorNode *editor; protected: static void _bind_methods(); void _ramp_changed(); - void _undo_redo_color_ramp(const Vector<float> &offsets, const Vector<Color> &colors); + void _undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors); public: virtual String get_name() const { return "ColorRamp"; } @@ -55,8 +55,8 @@ public: virtual bool handles(Object *p_node) const; virtual void make_visible(bool p_visible); - ColorRampEditorPlugin(EditorNode *p_node); - ~ColorRampEditorPlugin(); + GradientEditorPlugin(EditorNode *p_node); + ~GradientEditorPlugin(); }; #endif /* TOOLS_EDITOR_PLUGINS_COLOR_RAMP_EDITOR_PLUGIN_H_ */ diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 8ae7d55bdd..7c8ee97f22 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -552,7 +552,8 @@ ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) { shader_editor = memnew(ShaderEditor); shader_editor->set_custom_minimum_size(Size2(0, 300)); - button = editor->add_bottom_panel_item("Shader", shader_editor); + button = editor->add_bottom_panel_item(TTR("Shader"), shader_editor); + button->hide(); } ShaderEditorPlugin::~ShaderEditorPlugin() { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index a8d875a769..5da242ffaa 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -3682,7 +3682,7 @@ void SpatialEditor::_bind_methods() { void SpatialEditor::clear() { - settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 60.0)); + settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 55.0)); settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.1)); settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0)); @@ -3900,7 +3900,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { settings_fov->set_max(179); settings_fov->set_min(1); settings_fov->set_step(0.01); - settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 60.0)); + settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 55.0)); settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov); settings_znear = memnew(SpinBox); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 2220e3330f..dbd0758256 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -116,6 +116,18 @@ void ScriptCreateDialog::_parent_name_changed(const String &p_parent) { _update_dialog(); } +void ScriptCreateDialog::_template_changed(int p_template) { + + if (p_template == 0) { + //default + script_template = ""; + return; + } + String ext = ScriptServer::get_language(language_menu->get_selected())->get_extension(); + String name = template_menu->get_item_text(p_template) + "." + ext; + script_template = EditorSettings::get_singleton()->get_settings_path() + "/script_templates/" + name; +} + void ScriptCreateDialog::ok_pressed() { if (is_new_script_created) { @@ -134,7 +146,13 @@ void ScriptCreateDialog::_create_new() { if (has_named_classes) cname = class_name->get_text(); - Ref<Script> scr = ScriptServer::get_language(language_menu->get_selected())->get_template(cname, parent_name->get_text()); + Ref<Script> scr; + if (script_template != "") { + scr = ResourceLoader::load(script_template)->duplicate(); + ScriptServer::get_language(language_menu->get_selected())->make_template(cname, parent_name->get_text(), scr); + } else { + scr = ScriptServer::get_language(language_menu->get_selected())->get_template(cname, parent_name->get_text()); + } String selected_language = language_menu->get_item_text(language_menu->get_selected()); editor_settings->set_project_metadata("script_setup", "last_selected_language", selected_language); @@ -175,7 +193,8 @@ void ScriptCreateDialog::_load_exist() { void ScriptCreateDialog::_lang_changed(int l) { l = language_menu->get_selected(); - if (ScriptServer::get_language(l)->has_named_classes()) { + ScriptLanguage *language = ScriptServer::get_language(l); + if (language->has_named_classes()) { has_named_classes = true; } else { has_named_classes = false; @@ -187,7 +206,7 @@ void ScriptCreateDialog::_lang_changed(int l) { can_inherit_from_file = false; } - String selected_ext = "." + ScriptServer::get_language(l)->get_extension(); + String selected_ext = "." + language->get_extension(); String path = file_path->get_text(); String extension = ""; if (path != "") { @@ -204,7 +223,7 @@ void ScriptCreateDialog::_lang_changed(int l) { List<String> extensions; // get all possible extensions for script for (int l = 0; l < language_menu->get_item_count(); l++) { - ScriptServer::get_language(l)->get_recognized_extensions(&extensions); + language->get_recognized_extensions(&extensions); } for (List<String>::Element *E = extensions.front(); E; E = E->next()) { @@ -218,6 +237,18 @@ void ScriptCreateDialog::_lang_changed(int l) { file_path->set_text(path); } + bool use_templates = language->is_using_templates(); + template_menu->set_disabled(!use_templates); + if (use_templates) { + Vector<String> template_list = EditorSettings::get_singleton()->get_script_templates(language->get_extension()); + + template_menu->clear(); + template_menu->add_item(TTR("Default")); + for (int i = 0; i < template_list.size(); i++) { + template_menu->add_item(template_list[i]); + } + } + _update_dialog(); } @@ -471,6 +502,7 @@ void ScriptCreateDialog::_bind_methods() { ClassDB::bind_method("_browse_path", &ScriptCreateDialog::_browse_path); ClassDB::bind_method("_file_selected", &ScriptCreateDialog::_file_selected); ClassDB::bind_method("_path_changed", &ScriptCreateDialog::_path_changed); + ClassDB::bind_method("_template_changed", &ScriptCreateDialog::_template_changed); ADD_SIGNAL(MethodInfo("script_created", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script"))); } @@ -629,6 +661,16 @@ ScriptCreateDialog::ScriptCreateDialog() { gc->add_child(l); gc->add_child(class_name); + /* Templates */ + + template_menu = memnew(OptionButton); + l = memnew(Label); + l->set_text(TTR("Template")); + l->set_align(Label::ALIGN_RIGHT); + gc->add_child(l); + gc->add_child(template_menu); + template_menu->connect("item_selected", this, "_template_changed"); + /* Built-in Script */ internal = memnew(CheckButton); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 862d4f88f2..1adbfe3f7d 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -48,6 +48,7 @@ class ScriptCreateDialog : public ConfirmationDialog { LineEdit *parent_name; Button *parent_browse_button; OptionButton *language_menu; + OptionButton *template_menu; LineEdit *file_path; Button *path_button; EditorFileDialog *file_browse; @@ -68,6 +69,7 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_built_in; int current_language; bool re_check_path; + String script_template; void _path_changed(const String &p_path = String()); void _lang_changed(int l = 0); @@ -75,6 +77,7 @@ class ScriptCreateDialog : public ConfirmationDialog { bool _validate(const String &p_strin); void _class_name_changed(const String &p_name); void _parent_name_changed(const String &p_parent); + void _template_changed(int p_template = 0); void _browse_path(bool browse_parent); void _file_selected(const String &p_file); virtual void ok_pressed(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 7f1e6023bf..6d22935dcb 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1035,14 +1035,17 @@ void ScriptEditorDebugger::start() { EditorNode::get_singleton()->make_bottom_panel_item_visible(this); } - uint16_t port = GLOBAL_GET("network/debug/remote_port"); perf_history.clear(); for (int i = 0; i < Performance::MONITOR_MAX; i++) { perf_max[i] = 0; } - server->listen(port); + int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); + if (server->listen(remote_port) != OK) { + EditorNode::get_log()->add_message(String("** Error listening on port ") + itos(remote_port) + String(" **")); + return; + } set_process(true); } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 1b7afd3c43..76df9eb1ff 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1439,20 +1439,6 @@ VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) { car_wheel = p_car_wheel; } -/// - -void TestCubeSpatialGizmo::redraw() { - - clear(); - add_collision_triangles(SpatialEditorGizmos::singleton->test_cube_tm); -} - -TestCubeSpatialGizmo::TestCubeSpatialGizmo(TestCube *p_tc) { - - tc = p_tc; - set_spatial_node(p_tc); -} - /////////// String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { @@ -3045,12 +3031,6 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg; } - if (p_spatial->cast_to<TestCube>()) { - - Ref<TestCubeSpatialGizmo> misg = memnew(TestCubeSpatialGizmo(p_spatial->cast_to<TestCube>())); - return misg; - } - if (p_spatial->cast_to<CollisionShape>()) { Ref<CollisionShapeSpatialGizmo> misg = memnew(CollisionShapeSpatialGizmo(p_spatial->cast_to<CollisionShape>())); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 6a77e91425..a8ace87530 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -46,7 +46,6 @@ #include "scene/3d/ray_cast.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/room_instance.h" -#include "scene/3d/test_cube.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/visibility_notifier.h" @@ -187,17 +186,6 @@ public: SkeletonSpatialGizmo(Skeleton *p_skel = NULL); }; -class TestCubeSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(TestCubeSpatialGizmo, EditorSpatialGizmo); - - TestCube *tc; - -public: - void redraw(); - TestCubeSpatialGizmo(TestCube *p_tc = NULL); -}; - class RoomSpatialGizmo : public EditorSpatialGizmo { GDCLASS(RoomSpatialGizmo, EditorSpatialGizmo); diff --git a/main/main.cpp b/main/main.cpp index e13fb8d3db..e00c136596 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -581,12 +581,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph GLOBAL_DEF("memory/multithread/thread_rid_pool_prealloc", 60); GLOBAL_DEF("network/debug/max_remote_stdout_chars_per_second", 2048); - GLOBAL_DEF("network/debug/remote_port", 6007); if (debug_mode == "remote") { ScriptDebuggerRemote *sdr = memnew(ScriptDebuggerRemote); - uint16_t debug_port = GLOBAL_GET("network/debug/remote_port"); + uint16_t debug_port = 6007; if (debug_host.find(":") != -1) { int sep_pos = debug_host.find_last(":"); debug_port = debug_host.substr(sep_pos + 1, debug_host.length()).to_int(); diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp index 3d0b96ae5b..291a557d04 100644 --- a/main/tests/test_gui.cpp +++ b/main/tests/test_gui.cpp @@ -53,7 +53,6 @@ #include "scene/main/scene_main_loop.h" #include "scene/3d/camera.h" -#include "scene/3d/test_cube.h" #include "scene/main/viewport.h" namespace TestGUI { @@ -87,10 +86,6 @@ public: vp->add_child(camera); camera->make_current(); - TestCube *testcube = memnew( TestCube ); - vp->add_child(testcube); - testcube->set_transform(Transform( Basis().rotated(Vector3(0,1,0),Math_PI*0.25), Vector3(0,0,-8))); - Sprite *sp = memnew( Sprite ); sp->set_texture( vp->get_render_target_texture() ); //sp->set_texture( ResourceLoader::load("res://ball.png") ); @@ -375,6 +370,6 @@ MainLoop *test() { return memnew(TestMainLoop); } -} +} // namespace TestGUI #endif diff --git a/modules/etc/SCsub b/modules/etc/SCsub new file mode 100644 index 0000000000..8f5937017e --- /dev/null +++ b/modules/etc/SCsub @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_etc = env_modules.Clone() + +# Thirdparty source files +# Not unbundled so far since not widespread as shared library +thirdparty_dir = "#thirdparty/etc2comp/" +thirdparty_sources = [ + "EtcBlock4x4.cpp", + "EtcBlock4x4Encoding.cpp", + "EtcBlock4x4Encoding_ETC1.cpp", + "EtcBlock4x4Encoding_R11.cpp", + "EtcBlock4x4Encoding_RG11.cpp", + "EtcBlock4x4Encoding_RGB8A1.cpp", + "EtcBlock4x4Encoding_RGB8.cpp", + "EtcBlock4x4Encoding_RGBA8.cpp", + "Etc.cpp", + "EtcDifferentialTrys.cpp", + "EtcFilter.cpp", + "EtcImage.cpp", + "EtcIndividualTrys.cpp", + "EtcMath.cpp", + "EtcSortedBlockList.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_etc.add_source_files(env.modules_sources, thirdparty_sources) +env_etc.Append(CPPPATH=[thirdparty_dir]) + +# Godot source files +env_etc.add_source_files(env.modules_sources, "*.cpp") + +# upstream uses c++11 +env_etc.Append(CXXFLAGS="-std=gnu++11") diff --git a/modules/etc1/config.py b/modules/etc/config.py index fb920482f5..fb920482f5 100644 --- a/modules/etc1/config.py +++ b/modules/etc/config.py diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp new file mode 100644 index 0000000000..4ccd5c8d89 --- /dev/null +++ b/modules/etc/image_etc.cpp @@ -0,0 +1,181 @@ +/*************************************************************************/ +/* image_etc.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "image_etc.h" +#include "Etc.h" +#include "EtcFilter.h" +#include "image.h" +#include "os/copymem.h" +#include "os/os.h" +#include "print_string.h" + +static Image::Format _get_etc2_mode(Image::DetectChannels format) { + switch (format) { + case Image::DETECTED_L: + case Image::DETECTED_R: + return Image::FORMAT_ETC2_R11; + + case Image::DETECTED_RG: + return Image::FORMAT_ETC2_RG11; + + case Image::DETECTED_RGB: + return Image::FORMAT_ETC2_RGB8; + + case Image::DETECTED_RGBA: + return Image::FORMAT_ETC2_RGBA8; + + // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551 + } + + ERR_FAIL_COND_V(true, Image::FORMAT_MAX); +} + +static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) { + switch (format) { + case Image::FORMAT_ETC: + return Etc::Image::Format::ETC1; + + case Image::FORMAT_ETC2_R11: + return Etc::Image::Format::R11; + + case Image::FORMAT_ETC2_R11S: + return Etc::Image::Format::SIGNED_R11; + + case Image::FORMAT_ETC2_RG11: + return Etc::Image::Format::RG11; + + case Image::FORMAT_ETC2_RG11S: + return Etc::Image::Format::SIGNED_RG11; + + case Image::FORMAT_ETC2_RGB8: + return Etc::Image::Format::RGB8; + + case Image::FORMAT_ETC2_RGBA8: + return Etc::Image::Format::RGBA8; + + case Image::FORMAT_ETC2_RGB8A1: + return Etc::Image::Format::RGB8A1; + } + + ERR_FAIL_COND_V(true, Etc::Image::Format::UNKNOWN); +} + +static void _decompress_etc1(Image *p_img) { + // not implemented, to be removed +} + +static void _decompress_etc2(Image *p_img) { + // not implemented, to be removed +} + +static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_format) { + Image::Format img_format = p_img->get_format(); + Image::DetectChannels detected_channels = p_img->get_detected_channels(); + + if (img_format >= Image::FORMAT_DXT1) { + return; //do not compress, already compressed + } + + if (img_format > Image::FORMAT_RGBA8) { + // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually + return; + } + + int imgw = p_img->get_width(), imgh = p_img->get_height(); + ERR_FAIL_COND(nearest_power_of_2(imgw) != imgw || nearest_power_of_2(imgh) != imgh); + + Image::Format etc_format = force_etc1_format ? Image::FORMAT_ETC : _get_etc2_mode(detected_channels); + + Ref<Image> img = p_img->duplicate(); + + if (img->get_format() != Image::FORMAT_RGBA8) + img->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert + + PoolVector<uint8_t>::Read r = img->get_data().read(); + + int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps() ? -1 : 0); + int mmc = p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0; + + PoolVector<uint8_t> dst_data; + dst_data.resize(target_size); + + PoolVector<uint8_t>::Write w = dst_data.write(); + + // prepare parameters to be passed to etc2comp + int num_cpus = OS::get_singleton()->get_processor_count(); + int encoding_time = 0; + float effort = CLAMP(p_lossy_quality * 100, 0, 100); + Etc::ErrorMetric error_metric = Etc::ErrorMetric::BT709; // NOTE: we can experiment with other error metrics + Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format); + + int wofs = 0; + for (int i = 0; i < mmc + 1; i++) { + // convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF) + // NOTE: We can alternatively add a case to Image::convert to handle Image::FORMAT_RGBAF conversion. + int mipmap_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0; + img->get_mipmap_offset_size_and_dimensions(i, mipmap_ofs, mipmap_size, mipmap_w, mipmap_h); + const uint8_t *src = &r[mipmap_ofs]; + + Etc::ColorFloatRGBA *src_rgba_f = new Etc::ColorFloatRGBA[mipmap_w * mipmap_h]; + for (int i = 0; i < mipmap_w * mipmap_h; i++) { + int si = i * 4; // RGBA8 + src_rgba_f[i] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]); + } + + unsigned char *etc_data = NULL; + unsigned int etc_data_len = 0; + unsigned int extended_width = 0, extended_height = 0; + Etc::Encode((float *)src_rgba_f, mipmap_w, mipmap_h, etc2comp_etc_format, error_metric, effort, num_cpus, num_cpus, &etc_data, &etc_data_len, &extended_width, &extended_height, &encoding_time); + + memcpy(&w[wofs], etc_data, etc_data_len); + wofs += etc_data_len; + + delete[] etc_data; + delete[] src_rgba_f; + } + + p_img->create(imgw, imgh, mmc > 1 ? true : false, etc_format, dst_data); +} + +static void _compress_etc1(Image *p_img, float p_lossy_quality) { + _compress_etc(p_img, p_lossy_quality, true); +} + +static void _compress_etc2(Image *p_img, float p_lossy_quality) { + _compress_etc(p_img, p_lossy_quality, false); +} + +void _register_etc_compress_func() { + + Image::_image_compress_etc1_func = _compress_etc1; + //Image::_image_decompress_etc1 = _decompress_etc1; + + Image::_image_compress_etc2_func = _compress_etc2; + //Image::_image_decompress_etc2 = _decompress_etc2; +} diff --git a/modules/etc1/image_etc.h b/modules/etc/image_etc.h index 69e082bb87..3cbadef6fa 100644 --- a/modules/etc1/image_etc.h +++ b/modules/etc/image_etc.h @@ -30,6 +30,6 @@ #ifndef IMAGE_ETC1_H #define IMAGE_ETC1_H -void _register_etc1_compress_func(); +void _register_etc_compress_func(); #endif // IMAGE_ETC_H diff --git a/modules/etc1/register_types.cpp b/modules/etc/register_types.cpp index 859486222f..e777859a8f 100644 --- a/modules/etc1/register_types.cpp +++ b/modules/etc/register_types.cpp @@ -34,15 +34,15 @@ static ResourceFormatPKM *resource_loader_pkm = NULL; -void register_etc1_types() { +void register_etc_types() { resource_loader_pkm = memnew(ResourceFormatPKM); ResourceLoader::add_resource_format_loader(resource_loader_pkm); - _register_etc1_compress_func(); + _register_etc_compress_func(); } -void unregister_etc1_types() { +void unregister_etc_types() { memdelete(resource_loader_pkm); } diff --git a/modules/etc1/register_types.h b/modules/etc/register_types.h index 0552b87d65..44399376f3 100644 --- a/modules/etc1/register_types.h +++ b/modules/etc/register_types.h @@ -27,5 +27,5 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -void register_etc1_types(); -void unregister_etc1_types(); +void register_etc_types(); +void unregister_etc_types(); diff --git a/modules/etc1/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp index c04528d2a0..c04528d2a0 100644 --- a/modules/etc1/texture_loader_pkm.cpp +++ b/modules/etc/texture_loader_pkm.cpp diff --git a/modules/etc1/texture_loader_pkm.h b/modules/etc/texture_loader_pkm.h index 8a0f06a51a..8a0f06a51a 100644 --- a/modules/etc1/texture_loader_pkm.h +++ b/modules/etc/texture_loader_pkm.h diff --git a/modules/etc1/SCsub b/modules/etc1/SCsub deleted file mode 100644 index 0c5dc66d2e..0000000000 --- a/modules/etc1/SCsub +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python - -Import('env') -Import('env_modules') - -env_etc1 = env_modules.Clone() - -# Thirdparty source files -# Not unbundled so far since not widespread as shared library -thirdparty_dir = "#thirdparty/rg-etc1/" -thirdparty_sources = [ - "rg_etc1.cpp", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env_etc1.add_source_files(env.modules_sources, thirdparty_sources) -env_etc1.Append(CPPPATH=[thirdparty_dir]) - -# Godot source files -env_etc1.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/etc1/image_etc.cpp b/modules/etc1/image_etc.cpp deleted file mode 100644 index 121f50684d..0000000000 --- a/modules/etc1/image_etc.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/*************************************************************************/ -/* image_etc.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "image_etc.h" -#include "image.h" -#include "os/copymem.h" -#include "print_string.h" -#include "rg_etc1.h" -static void _decompress_etc(Image *p_img) { - - ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_ETC); - - int imgw = p_img->get_width(); - int imgh = p_img->get_height(); - PoolVector<uint8_t> src = p_img->get_data(); - PoolVector<uint8_t> dst; - - PoolVector<uint8_t>::Read r = src.read(); - - int mmc = p_img->get_mipmap_count(); - - for (int i = 0; i <= mmc; i++) { - - dst.resize(dst.size() + imgw * imgh * 3); - const uint8_t *srcbr = &r[p_img->get_mipmap_offset(i)]; - PoolVector<uint8_t>::Write w = dst.write(); - - uint8_t *wptr = &w[dst.size() - imgw * imgh * 3]; - - int bw = MAX(imgw / 4, 1); - int bh = MAX(imgh / 4, 1); - - for (int y = 0; y < bh; y++) { - - for (int x = 0; x < bw; x++) { - - uint8_t block[4 * 4 * 4]; - - rg_etc1::unpack_etc1_block(srcbr, (unsigned int *)block); - srcbr += 8; - - int maxx = MIN(imgw, 4); - int maxy = MIN(imgh, 4); - - for (int yy = 0; yy < maxy; yy++) { - - for (int xx = 0; xx < maxx; xx++) { - - uint32_t src_ofs = (yy * 4 + xx) * 4; - uint32_t dst_ofs = ((y * 4 + yy) * imgw + x * 4 + xx) * 3; - wptr[dst_ofs + 0] = block[src_ofs + 0]; - wptr[dst_ofs + 1] = block[src_ofs + 1]; - wptr[dst_ofs + 2] = block[src_ofs + 2]; - } - } - } - } - - imgw = MAX(1, imgw / 2); - imgh = MAX(1, imgh / 2); - } - - r = PoolVector<uint8_t>::Read(); - //print_line("Re Creating ETC into regular image: w "+itos(p_img->get_width())+" h "+itos(p_img->get_height())+" mm "+itos(p_img->get_mipmaps())); - bool needs_mipmaps = p_img->has_mipmaps(); - p_img->create(p_img->get_width(), p_img->get_height(), p_img->has_mipmaps(), Image::FORMAT_RGB8, dst); - if (needs_mipmaps) - p_img->generate_mipmaps(); -} - -static void _compress_etc(Image *p_img) { - - Ref<Image> img = p_img->duplicate(); - - int imgw = img->get_width(), imgh = img->get_height(); - - ERR_FAIL_COND(nearest_power_of_2(imgw) != imgw || nearest_power_of_2(imgh) != imgh); - - if (img->get_format() != Image::FORMAT_RGB8) - img->convert(Image::FORMAT_RGB8); - - PoolVector<uint8_t> res_data; - PoolVector<uint8_t> dst_data; - PoolVector<uint8_t>::Read r = img->get_data().read(); - - int target_size = Image::get_image_data_size(p_img->get_width(), p_img->get_height(), Image::FORMAT_ETC, p_img->has_mipmaps() ? -1 : 0); - int mmc = p_img->has_mipmaps() ? Image::get_image_required_mipmaps(p_img->get_width(), p_img->get_height(), Image::FORMAT_ETC) : 0; - - dst_data.resize(target_size); - int mc = 0; - int ofs = 0; - PoolVector<uint8_t>::Write w = dst_data.write(); - - rg_etc1::etc1_pack_params pp; - pp.m_quality = rg_etc1::cLowQuality; - for (int i = 0; i <= mmc; i++) { - - int bw = MAX(imgw / 4, 1); - int bh = MAX(imgh / 4, 1); - const uint8_t *src = &r[img->get_mipmap_offset(i)]; - int mmsize = MAX(bw, 1) * MAX(bh, 1) * 8; - - uint8_t *dst = &w[ofs]; - ofs += mmsize; - - //print_line("bh: "+itos(bh)+" bw: "+itos(bw)); - - for (int y = 0; y < bh; y++) { - - for (int x = 0; x < bw; x++) { - - //print_line("x: "+itos(x)+" y: "+itos(y)); - - uint8_t block[4 * 4 * 4]; - zeromem(block, 4 * 4 * 4); - uint8_t cblock[8]; - - int maxy = MIN(imgh, 4); - int maxx = MIN(imgw, 4); - - for (int yy = 0; yy < maxy; yy++) { - - for (int xx = 0; xx < maxx; xx++) { - - uint32_t dst_ofs = (yy * 4 + xx) * 4; - uint32_t src_ofs = ((y * 4 + yy) * imgw + x * 4 + xx) * 3; - block[dst_ofs + 0] = src[src_ofs + 0]; - block[dst_ofs + 1] = src[src_ofs + 1]; - block[dst_ofs + 2] = src[src_ofs + 2]; - block[dst_ofs + 3] = 255; - } - } - - rg_etc1::pack_etc1_block(cblock, (const unsigned int *)block, pp); - for (int j = 0; j < 8; j++) { - - dst[j] = cblock[j]; - } - - dst += 8; - } - } - - imgw = MAX(1, imgw / 2); - imgh = MAX(1, imgh / 2); - mc++; - } - - p_img->create(p_img->get_width(), p_img->get_height(), (mc - 1) ? true : false, Image::FORMAT_ETC, dst_data); -} - -void _register_etc1_compress_func() { - - rg_etc1::pack_etc1_block_init(); - Image::_image_compress_etc_func = _compress_etc; - Image::_image_decompress_etc = _decompress_etc; -} diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 9c8625c1e0..706b81f7a3 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -516,9 +516,9 @@ static const char *_dl_platforms_info[] = { "unix|server|so|Server", "unix|android|so|Android", "unix|haiku|so|Haiku", // Right? - "|mac|dynlib|Mac", - "mac|ios|dynlib|iOS", - "mac|osx|dynlib|OSX", + "|mac|dylib|Mac", + "mac|ios|dylib|iOS", + "mac|osx|dylib|OSX", "|html5|js|HTML5", "|windows|dll|Windows", "windows|uwp|dll|UWP", diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index eea5b15236..5e3ce31dd6 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -69,6 +69,19 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str return script; } +bool GDScriptLanguage::is_using_templates() { + + return true; +} + +void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { + + String src = p_script->get_source_code(); + src = src.replace("%BASE%", p_base_class_name); + src = src.replace("%TS%", _get_indentation()); + p_script->set_source_code(src); +} + bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { GDParser parser; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index dcc0e24098..1dcc442234 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -615,6 +615,11 @@ Error GDScript::reload(bool p_keep_state) { if (basedir != "") basedir = basedir.get_base_dir(); + if (basedir.find("res://") == -1 && basedir.find("user://") == -1) { + //loading a template, don't parse + return OK; + } + valid = false; GDParser parser; Error err = parser.parse(source, basedir, false, path); diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 00ae136790..ebef4fed74 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -381,6 +381,8 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; + virtual bool is_using_templates(); + virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/stb_vorbis/audio_stream_ogg_vorbis.h index 287aa4ca47..46cdfd3f2d 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.h +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.h @@ -77,7 +77,7 @@ class AudioStreamOGGVorbis : public AudioStream { GDCLASS(AudioStreamOGGVorbis, AudioStream) OBJ_SAVE_TYPE(AudioStream) //children are all saved as AudioStream, so they can be exchanged - RES_BASE_EXTENSION("asogg"); + RES_BASE_EXTENSION("oggstr"); friend class AudioStreamPlaybackOGGVorbis; diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp index 9a3d5c2651..f0a7ee1ec6 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp @@ -48,7 +48,7 @@ void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extens } String ResourceImporterOGGVorbis::get_save_extension() const { - return "asogg"; + return "oggstr"; } String ResourceImporterOGGVorbis::get_resource_type() const { @@ -99,7 +99,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin ogg_stream->set_data(data); ogg_stream->set_loop(loop); - return ResourceSaver::save(p_save_path + ".asogg", ogg_stream); + return ResourceSaver::save(p_save_path + ".oggstr", ogg_stream); } ResourceImporterOGGVorbis::ResourceImporterOGGVorbis() { diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index aec60391d3..bb8111ce99 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2369,6 +2369,17 @@ Ref<Script> VisualScriptLanguage::get_template(const String &p_class_name, const script->set_instance_base_type(p_base_class_name); return script; } + +bool VisualScriptLanguage::is_using_templates() { + + return true; +} + +void VisualScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { + Ref<VisualScript> script = p_script; + script->set_instance_base_type(p_base_class_name); +} + bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { return false; diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 72843099c7..1ccc358342 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -564,6 +564,8 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; + virtual bool is_using_templates(); + virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 84fc4f10bf..51597526ab 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1714,7 +1714,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { args.push_back("--remove-all"); err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv); - int port = GlobalConfig::get_singleton()->get("network/debug/remote_port"); + int port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); args.clear(); args.push_back("reverse"); args.push_back("tcp:"+itos(port)); @@ -2993,7 +2993,7 @@ public: args.push_back("--remove-all"); err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); - int port = GlobalConfig::get_singleton()->get("network/debug/remote_port"); + int port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); args.clear(); args.push_back("reverse"); args.push_back("tcp:" + itos(port)); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 72fba39e33..1070de724b 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -409,14 +409,14 @@ static int button_mask = 0; if ((int)[event buttonNumber] != 2) return; - button_mask |= BUTTON_MASK_MIDDLE; + button_mask &= ~BUTTON_MASK_MIDDLE; Ref<InputEventMouseButton> mb; mb.instance(); get_key_modifier_state([event modifierFlags], mb); mb->set_button_index(BUTTON_MIDDLE); - mb->set_pressed(true); + mb->set_pressed(false); mb->set_position(Vector2(mouse_x, mouse_y)); mb->set_global_position(Vector2(mouse_x, mouse_y)); mb->set_button_mask(button_mask); @@ -816,7 +816,7 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | (p_desired.resizable ? NSResizableWindowMask : 0); window_object = [[GodotWindow alloc] - initWithContentRect:NSMakeRect(0, 0, p_desired.width / display_scale, p_desired.height / display_scale) + initWithContentRect:NSMakeRect(0, 0, p_desired.width, p_desired.height) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; @@ -825,8 +825,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au window_view = [[GodotContentView alloc] init]; - window_size.width = p_desired.width; - window_size.height = p_desired.height; + window_size.width = p_desired.width * display_scale; + window_size.height = p_desired.height * display_scale; if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && display_scale > 1) { [window_view setWantsBestResolutionOpenGLSurface:YES]; diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp index 51aba9b7fd..c773c0b746 100644 --- a/platform/uwp/app.cpp +++ b/platform/uwp/app.cpp @@ -263,7 +263,7 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor screen_touch.instance(); screen_touch->set_device(0); screen_touch->set_pressed(p_pressed); - screen_touch->set_pos(Vector2(pos.X, pos.Y)); + screen_touch->set_position(Vector2(pos.X, pos.Y)); screen_touch->set_index(_get_finger(point->PointerId)); last_touch_x[screen_touch->get_index()] = pos.X; @@ -280,8 +280,8 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor mouse_button->set_device(0); mouse_button->set_pressed(p_pressed); mouse_button->set_button_index(but); - mouse_button->set_pos(Vector2(pos.X, pos.Y)); - mouse_button->set_global_pos(Vector2(pos.X, pos.Y)); + mouse_button->set_position(Vector2(pos.X, pos.Y)); + mouse_button->set_global_position(Vector2(pos.X, pos.Y)); if (p_is_wheel) { if (point->Properties->MouseWheelDelta > 0) { @@ -355,9 +355,9 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co Ref<InputEventScreenDrag> screen_drag; screen_drag.instance(); screen_drag->set_device(0); - screen_drag->set_pos(Vector2(pos.X, pos.Y)); + screen_drag->set_position(Vector2(pos.X, pos.Y)); screen_drag->set_index(_get_finger(point->PointerId)); - screen_drag->set_relative(Vector2(screen_drag->get_pos().x - last_touch_x[screen_drag->get_index()], screen_drag->get_pos().y - last_touch_y[screen_drag->get_index()])); + screen_drag->set_relative(Vector2(screen_drag->get_position().x - last_touch_x[screen_drag->get_index()], screen_drag->get_position().y - last_touch_y[screen_drag->get_index()])); os->input_event(screen_drag); if (number_of_contacts > 1) @@ -372,8 +372,8 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co Ref<InputEventMouseMotion> mouse_motion; mouse_motion.instance(); mouse_motion->set_device(0); - mouse_motion->set_pos(Vector2(pos.X, pos.Y)); - mouse_motion->set_global_pos(Vector2(pos.X, pos.Y)); + mouse_motion->set_position(Vector2(pos.X, pos.Y)); + mouse_motion->set_global_position(Vector2(pos.X, pos.Y)); mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31])); last_mouse_pos = pos; @@ -394,8 +394,8 @@ void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) { Ref<InputEventMouseMotion> mouse_motion; mouse_motion.instance(); mouse_motion->set_device(0); - mouse_motion->set_pos(Vector2(pos.X, pos.Y)); - mouse_motion->set_global_pos(Vector2(pos.X, pos.Y)); + mouse_motion->set_position(Vector2(pos.X, pos.Y)); + mouse_motion->set_global_position(Vector2(pos.X, pos.Y)); mouse_motion->set_relative(Vector2(args->MouseDelta.X, args->MouseDelta.Y)); last_mouse_pos = pos; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 4393cad3bf..e94529dd94 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -543,8 +543,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) mb->set_position(Vector2(old_x, old_y)); } - mb->set_global_position(mb->get_position()); - if (uMsg != WM_MOUSEWHEEL) { if (mb->is_pressed()) { @@ -568,6 +566,8 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) mb->set_position(Vector2(coords.x, coords.y)); } + mb->set_global_position(mb->get_position()); + if (main_loop) { input->parse_input_event(mb); if (mb->is_pressed() && mb->get_button_index() > 3) { diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 8bce489624..aca7a8c736 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -501,15 +501,15 @@ uint32_t Area2D::get_collision_mask() const { return collision_mask; } -void Area2D::set_layer_mask(uint32_t p_mask) { +void Area2D::set_collision_layer(uint32_t p_layer) { - layer_mask = p_mask; - Physics2DServer::get_singleton()->area_set_layer_mask(get_rid(), p_mask); + collision_layer = p_layer; + Physics2DServer::get_singleton()->area_set_collision_layer(get_rid(), p_layer); } -uint32_t Area2D::get_layer_mask() const { +uint32_t Area2D::get_collision_layer() const { - return layer_mask; + return collision_layer; } void Area2D::set_collision_mask_bit(int p_bit, bool p_value) { @@ -527,19 +527,19 @@ bool Area2D::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } -void Area2D::set_layer_mask_bit(int p_bit, bool p_value) { +void Area2D::set_collision_layer_bit(int p_bit, bool p_value) { - uint32_t mask = get_layer_mask(); + uint32_t layer = get_collision_layer(); if (p_value) - mask |= 1 << p_bit; + layer |= 1 << p_bit; else - mask &= ~(1 << p_bit); - set_layer_mask(mask); + layer &= ~(1 << p_bit); + set_collision_layer(layer); } -bool Area2D::get_layer_mask_bit(int p_bit) const { +bool Area2D::get_collision_layer_bit(int p_bit) const { - return get_layer_mask() & (1 << p_bit); + return get_collision_layer() & (1 << p_bit); } void Area2D::_bind_methods() { @@ -577,14 +577,14 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area2D::set_collision_mask); ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area2D::get_collision_mask); - ClassDB::bind_method(D_METHOD("set_layer_mask", "layer_mask"), &Area2D::set_layer_mask); - ClassDB::bind_method(D_METHOD("get_layer_mask"), &Area2D::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area2D::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area2D::get_collision_layer); ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area2D::set_collision_mask_bit); ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area2D::get_collision_mask_bit); - ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "bit", "value"), &Area2D::set_layer_mask_bit); - ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "bit"), &Area2D::get_layer_mask_bit); + ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area2D::set_collision_layer_bit); + ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area2D::get_collision_layer_bit); ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area2D::set_monitoring); ClassDB::bind_method(D_METHOD("is_monitoring"), &Area2D::is_monitoring); @@ -622,7 +622,7 @@ void Area2D::_bind_methods() { ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable"); ADD_GROUP("Collision", "collision_"); - ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_layer_mask", "get_layer_mask"); + ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); } @@ -641,7 +641,7 @@ Area2D::Area2D() monitoring = false; monitorable = false; collision_mask = 1; - layer_mask = 1; + collision_layer = 1; set_monitoring(true); set_monitorable(true); } diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index 3efc1abbd4..f0eb1e9240 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -55,7 +55,7 @@ private: real_t linear_damp; real_t angular_damp; uint32_t collision_mask; - uint32_t layer_mask; + uint32_t collision_layer; int priority; bool monitoring; bool monitorable; @@ -164,14 +164,14 @@ public: void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; - void set_layer_mask(uint32_t p_mask); - uint32_t get_layer_mask() const; + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; void set_collision_mask_bit(int p_bit, bool p_value); bool get_collision_mask_bit(int p_bit) const; - void set_layer_mask_bit(int p_bit, bool p_value); - bool get_layer_mask_bit(int p_bit) const; + void set_collision_layer_bit(int p_bit, bool p_value); + bool get_collision_layer_bit(int p_bit) const; Array get_overlapping_bodies() const; //function for script Array get_overlapping_areas() const; //function for script diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 34413074c1..e8c2122bd1 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -336,6 +336,17 @@ String Light2D::get_configuration_warning() const { return String(); } +void Light2D::set_shadow_smooth(float p_amount) { + + shadow_smooth = p_amount; + VS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth); +} + +float Light2D::get_shadow_smooth() const { + + return shadow_smooth; +} + void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &Light2D::set_enabled); @@ -389,6 +400,9 @@ void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_buffer_size", "size"), &Light2D::set_shadow_buffer_size); ClassDB::bind_method(D_METHOD("get_shadow_buffer_size"), &Light2D::get_shadow_buffer_size); + ClassDB::bind_method(D_METHOD("set_shadow_smooth", "smooth"), &Light2D::set_shadow_smooth); + ClassDB::bind_method(D_METHOD("get_shadow_smooth"), &Light2D::get_shadow_smooth); + ClassDB::bind_method(D_METHOD("set_shadow_gradient_length", "multiplier"), &Light2D::set_shadow_gradient_length); ClassDB::bind_method(D_METHOD("get_shadow_gradient_length"), &Light2D::get_shadow_gradient_length); @@ -420,6 +434,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_buffer_size", PROPERTY_HINT_RANGE, "32,16384,1"), "set_shadow_buffer_size", "get_shadow_buffer_size"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_gradient_length", PROPERTY_HINT_RANGE, "1,4096,0.1"), "set_shadow_gradient_length", "get_shadow_gradient_length"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_filter", PROPERTY_HINT_ENUM, "None,PCF3,PCF5,PCF9,PCF13"), "set_shadow_filter", "get_shadow_filter"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_filter_smooth", PROPERTY_HINT_RANGE, "0,64,0.1"), "set_shadow_smooth", "get_shadow_smooth"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_shadow_cull_mask", "get_item_shadow_cull_mask"); BIND_CONSTANT(MODE_ADD); @@ -449,6 +464,7 @@ Light2D::Light2D() { energy = 1.0; shadow_color = Color(0, 0, 0, 0); shadow_filter = SHADOW_FILTER_NONE; + shadow_smooth = 0; set_notify_transform(true); } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 9b09d54dd8..90e55aeda4 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -69,6 +69,7 @@ private: int item_mask; int item_shadow_mask; int shadow_buffer_size; + float shadow_smooth; float shadow_gradient_length; Mode mode; Ref<Texture> texture; @@ -146,6 +147,9 @@ public: void set_shadow_color(const Color &p_shadow_color); Color get_shadow_color() const; + void set_shadow_smooth(float p_amount); + float get_shadow_smooth() const; + virtual Rect2 get_item_rect() const; String get_configuration_warning() const; diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 80969d11b3..1a57d24342 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -310,7 +310,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color"); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "ColorRamp"), "set_gradient", "get_gradient"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile"), "set_texture_mode", "get_texture_mode"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode"); diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index ea059d133d..3c1410edbb 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -337,7 +337,7 @@ void LineBuilder::build() { } else if (current_joint_mode == LINE_JOINT_ROUND) { Vector2 vbegin = cbegin - pos1; Vector2 vend = cend - pos1; - strip_add_arc(pos1, vend.angle_to(vbegin), orientation); + strip_add_arc(pos1, vbegin.angle_to(vend), orientation); } if (intersection_result != SEGMENT_INTERSECT) @@ -498,7 +498,7 @@ void LineBuilder::strip_add_arc(Vector2 center, float angle_delta, Orientation o if (angle_delta < 0.f) angle_step = -angle_step; - float t = vbegin.angle_to(Vector2(1, 0)); + float t = Vector2(1, 0).angle_to(vbegin); float end_angle = t + angle_delta; Vector2 rpos(0, 0); @@ -525,7 +525,7 @@ void LineBuilder::new_arc(Vector2 center, Vector2 vbegin, float angle_delta, Col if (angle_delta < 0.f) angle_step = -angle_step; - float t = vbegin.angle_to(Vector2(1, 0)); + float t = Vector2(1, 0).angle_to(vbegin); float end_angle = t + angle_delta; Vector2 rpos(0, 0); float tt_begin = -Math_PI / 2.f; diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 27d0d07c0f..21d64c5d64 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -505,8 +505,8 @@ void Particles2D::_notification(int p_what) { Color color; - if (color_ramp.is_valid()) { - color = color_ramp->get_color_at_offset(ptime); + if (gradient.is_valid()) { + color = gradient->get_color_at_offset(ptime); } else { color = default_color; } @@ -774,14 +774,14 @@ Color Particles2D::get_color() const { return default_color; } -void Particles2D::set_color_ramp(const Ref<Gradient> &p_color_ramp) { +void Particles2D::set_gradient(const Ref<Gradient> &p_gradient) { - color_ramp = p_color_ramp; + gradient = p_gradient; } -Ref<Gradient> Particles2D::get_color_ramp() const { +Ref<Gradient> Particles2D::get_gradient() const { - return color_ramp; + return gradient; } void Particles2D::set_emissor_offset(const Point2 &p_offset) { @@ -809,19 +809,19 @@ void Particles2D::set_color_phases(int p_phases) { //Create color ramp if we have 2 or more phases. //Otherwise first phase phase will be assigned to default color. - if (p_phases > 1 && color_ramp.is_null()) { - color_ramp = Ref<Gradient>(memnew(Gradient())); + if (p_phases > 1 && gradient.is_null()) { + gradient = Ref<Gradient>(memnew(Gradient())); } - if (color_ramp.is_valid()) { - color_ramp->get_points().resize(p_phases); + if (gradient.is_valid()) { + gradient->get_points().resize(p_phases); } } //Deprecated. int Particles2D::get_color_phases() const { - if (color_ramp.is_valid()) { - return color_ramp->get_points_count(); + if (gradient.is_valid()) { + return gradient->get_points_count(); } return 0; } @@ -830,9 +830,9 @@ int Particles2D::get_color_phases() const { void Particles2D::set_color_phase_color(int p_phase, const Color &p_color) { ERR_FAIL_INDEX(p_phase, MAX_COLOR_PHASES); - if (color_ramp.is_valid()) { - if (color_ramp->get_points_count() > p_phase) - color_ramp->set_color(p_phase, p_color); + if (gradient.is_valid()) { + if (gradient->get_points_count() > p_phase) + gradient->set_color(p_phase, p_color); } else { if (p_phase == 0) default_color = p_color; @@ -843,8 +843,8 @@ void Particles2D::set_color_phase_color(int p_phase, const Color &p_color) { Color Particles2D::get_color_phase_color(int p_phase) const { ERR_FAIL_INDEX_V(p_phase, MAX_COLOR_PHASES, Color()); - if (color_ramp.is_valid()) { - return color_ramp->get_color(p_phase); + if (gradient.is_valid()) { + return gradient->get_color(p_phase); } return Color(0, 0, 0, 1); } @@ -853,8 +853,8 @@ Color Particles2D::get_color_phase_color(int p_phase) const { void Particles2D::set_color_phase_pos(int p_phase, float p_pos) { ERR_FAIL_INDEX(p_phase, MAX_COLOR_PHASES); ERR_FAIL_COND(p_pos < 0.0 || p_pos > 1.0); - if (color_ramp.is_valid() && color_ramp->get_points_count() > p_phase) { - return color_ramp->set_offset(p_phase, p_pos); + if (gradient.is_valid() && gradient->get_points_count() > p_phase) { + return gradient->set_offset(p_phase, p_pos); } } @@ -862,8 +862,8 @@ void Particles2D::set_color_phase_pos(int p_phase, float p_pos) { float Particles2D::get_color_phase_pos(int p_phase) const { ERR_FAIL_INDEX_V(p_phase, MAX_COLOR_PHASES, 0); - if (color_ramp.is_valid()) { - return color_ramp->get_offset(p_phase); + if (gradient.is_valid()) { + return gradient->get_offset(p_phase); } return 0; } @@ -996,8 +996,8 @@ void Particles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color", "color"), &Particles2D::set_color); ClassDB::bind_method(D_METHOD("get_color"), &Particles2D::get_color); - ClassDB::bind_method(D_METHOD("set_color_ramp:ColorRamp", "color_ramp"), &Particles2D::set_color_ramp); - ClassDB::bind_method(D_METHOD("get_color_ramp:ColorRamp"), &Particles2D::get_color_ramp); + ClassDB::bind_method(D_METHOD("set_gradient:Gradient", "gradient"), &Particles2D::set_gradient); + ClassDB::bind_method(D_METHOD("get_gradient:Gradient"), &Particles2D::get_gradient); ClassDB::bind_method(D_METHOD("set_emissor_offset", "offset"), &Particles2D::set_emissor_offset); ClassDB::bind_method(D_METHOD("get_emissor_offset"), &Particles2D::get_emissor_offset); @@ -1078,7 +1078,7 @@ void Particles2D::_bind_methods() { } ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "color/color"), "set_color", "get_color"); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "color/color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "ColorRamp"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "color/color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); ADD_PROPERTYNZ(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_points", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_emission_points", "get_emission_points"); diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index 5769fdd251..856beaa836 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -169,7 +169,7 @@ private: //If no color ramp is set then default color is used. Created as simple alternative to color_ramp. Color default_color; - Ref<Gradient> color_ramp; + Ref<Gradient> gradient; void _process_particles(float p_delta); friend class ParticleAttractor2D; @@ -241,8 +241,8 @@ public: void set_color(const Color &p_color); Color get_color() const; - void set_color_ramp(const Ref<Gradient> &p_texture); - Ref<Gradient> get_color_ramp() const; + void set_gradient(const Ref<Gradient> &p_texture); + Ref<Gradient> get_gradient() const; void set_emissor_offset(const Point2 &p_offset); Point2 get_emissor_offset() const; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 626ea10515..68270ed771 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -79,7 +79,7 @@ uint32_t PhysicsBody2D::_get_layers() const { void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_collision_layer", "mask"), &PhysicsBody2D::set_collision_layer); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody2D::set_collision_layer); ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody2D::get_collision_layer); ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody2D::set_collision_mask); ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody2D::get_collision_mask); @@ -108,15 +108,15 @@ void PhysicsBody2D::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "one_way_collision/max_depth"), "set_one_way_collision_max_depth", "get_one_way_collision_max_depth"); } -void PhysicsBody2D::set_collision_layer(uint32_t p_mask) { +void PhysicsBody2D::set_collision_layer(uint32_t p_layer) { - mask = p_mask; - Physics2DServer::get_singleton()->body_set_layer_mask(get_rid(), p_mask); + collision_layer = p_layer; + Physics2DServer::get_singleton()->body_set_collision_layer(get_rid(), p_layer); } uint32_t PhysicsBody2D::get_collision_layer() const { - return mask; + return collision_layer; } void PhysicsBody2D::set_collision_mask(uint32_t p_mask) { @@ -146,12 +146,12 @@ bool PhysicsBody2D::get_collision_mask_bit(int p_bit) const { void PhysicsBody2D::set_collision_layer_bit(int p_bit, bool p_value) { - uint32_t mask = get_collision_layer(); + uint32_t collision_layer = get_collision_layer(); if (p_value) - mask |= 1 << p_bit; + collision_layer |= 1 << p_bit; else - mask &= ~(1 << p_bit); - set_collision_layer(mask); + collision_layer &= ~(1 << p_bit); + set_collision_layer(collision_layer); } bool PhysicsBody2D::get_collision_layer_bit(int p_bit) const { @@ -162,7 +162,7 @@ bool PhysicsBody2D::get_collision_layer_bit(int p_bit) const { PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D(Physics2DServer::get_singleton()->body_create(p_mode), false) { - mask = 1; + collision_layer = 1; collision_mask = 1; set_one_way_collision_max_depth(0); set_pickable(false); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index f706111e7e..50c9865f18 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -38,7 +38,7 @@ class PhysicsBody2D : public CollisionObject2D { GDCLASS(PhysicsBody2D, CollisionObject2D); - uint32_t mask; + uint32_t collision_layer; uint32_t collision_mask; Vector2 one_way_collision_direction; float one_way_collision_max_depth; @@ -53,7 +53,7 @@ protected: static void _bind_methods(); public: - void set_collision_layer(uint32_t p_mask); + void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; void set_collision_mask(uint32_t p_mask); diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 0a1a8b56ff..cfb4059714 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -44,14 +44,14 @@ Vector2 RayCast2D::get_cast_to() const { return cast_to; } -void RayCast2D::set_layer_mask(uint32_t p_mask) { +void RayCast2D::set_collision_layer(uint32_t p_layer) { - layer_mask = p_mask; + collision_layer = p_layer; } -uint32_t RayCast2D::get_layer_mask() const { +uint32_t RayCast2D::get_collision_layer() const { - return layer_mask; + return collision_layer; } void RayCast2D::set_type_mask(uint32_t p_mask) { @@ -201,7 +201,7 @@ void RayCast2D::_update_raycast_state() { Physics2DDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, layer_mask, type_mask)) { + if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_layer, type_mask)) { collided = true; against = rr.collider_id; @@ -274,8 +274,8 @@ void RayCast2D::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_exceptions"), &RayCast2D::clear_exceptions); - ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &RayCast2D::set_layer_mask); - ClassDB::bind_method(D_METHOD("get_layer_mask"), &RayCast2D::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &RayCast2D::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &RayCast2D::get_collision_layer); ClassDB::bind_method(D_METHOD("set_type_mask", "mask"), &RayCast2D::set_type_mask); ClassDB::bind_method(D_METHOD("get_type_mask"), &RayCast2D::get_type_mask); @@ -286,7 +286,7 @@ void RayCast2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cast_to"), "set_cast_to", "get_cast_to"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "layer_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_layer_mask", "get_layer_mask"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "type_mask", PROPERTY_HINT_FLAGS, "Static,Kinematic,Rigid,Character,Area"), "set_type_mask", "get_type_mask"); } @@ -296,7 +296,7 @@ RayCast2D::RayCast2D() { against = 0; collided = false; against_shape = 0; - layer_mask = 1; + collision_layer = 1; type_mask = Physics2DDirectSpaceState::TYPE_MASK_COLLISION; cast_to = Vector2(0, 50); exclude_parent_body = true; diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index cfecfa2585..244f4302ad 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -43,7 +43,7 @@ class RayCast2D : public Node2D { Vector2 collision_point; Vector2 collision_normal; Set<RID> exclude; - uint32_t layer_mask; + uint32_t collision_layer; uint32_t type_mask; bool exclude_parent_body; @@ -61,8 +61,8 @@ public: void set_cast_to(const Vector2 &p_point); Vector2 get_cast_to() const; - void set_layer_mask(uint32_t p_mask); - uint32_t get_layer_mask() const; + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; void set_type_mask(uint32_t p_mask); uint32_t get_type_mask() const; diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp index ea68a111af..37139b2b93 100644 --- a/scene/2d/screen_button.cpp +++ b/scene/2d/screen_button.cpp @@ -194,40 +194,27 @@ void TouchScreenButton::_input(const Ref<InputEvent> &p_event) { if (p_event->get_device() != 0) return; + ERR_FAIL_COND(!is_visible_in_tree()); + + const InputEventScreenTouch *st = p_event->cast_to<InputEventScreenTouch>(); + if (passby_press) { - Ref<InputEventScreenTouch> st = p_event; - Ref<InputEventScreenTouch> sd = p_event; + const InputEventScreenDrag *sd = p_event->cast_to<InputEventScreenDrag>(); - if (st.is_valid() && !st->is_pressed() && finger_pressed == st->get_index()) { + if (st && !st->is_pressed() && finger_pressed == st->get_index()) { _release(); } - if ((st.is_valid() && st->is_pressed()) || sd.is_valid()) { + if ((st && st->is_pressed()) || sd) { - int index = st.is_valid() ? st->get_index() : sd->get_index(); - Vector2 coord = st.is_valid() ? st->get_position() : sd->get_position(); + int index = st ? st->get_index() : sd->get_index(); + Point2 coord = st ? st->get_position() : sd->get_position(); if (finger_pressed == -1 || index == finger_pressed) { - coord = (get_global_transform_with_canvas()).affine_inverse().xform(coord); - - bool touched = false; - if (bitmask.is_valid()) { - - if (Rect2(Point2(), bitmask->get_size()).has_point(coord)) { - - if (bitmask->get_bit(coord)) - touched = true; - } - } else { - - if (texture.is_valid()) - touched = Rect2(Point2(), texture->get_size()).has_point(coord); - } - - if (touched) { + if (_is_point_inside(coord)) { if (finger_pressed == -1) { _press(index); } @@ -241,47 +228,15 @@ void TouchScreenButton::_input(const Ref<InputEvent> &p_event) { } else { - Ref<InputEventScreenTouch> st = p_event; - - if (st.is_valid()) { + if (st) { if (st->is_pressed()) { - if (!is_visible_in_tree()) - return; - const bool can_press = finger_pressed == -1; if (!can_press) return; //already fingering - Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(st->get_position()); - Rect2 item_rect = get_item_rect(); - - bool touched = false; - bool check_rect = true; - if (shape.is_valid()) { - - check_rect = false; - Transform2D xform = shape_centered ? Transform2D().translated(get_item_rect().size * 0.5f) : Transform2D(); - touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); - } - - if (bitmask.is_valid()) { - - check_rect = false; - if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) { - - if (bitmask->get_bit(coord)) - touched = true; - } - } - - if (!touched && check_rect) { - if (!texture.is_null()) - touched = item_rect.has_point(coord); - } - - if (touched) { + if (_is_point_inside(st->get_position())) { _press(st->get_index()); } } else { @@ -293,6 +248,39 @@ void TouchScreenButton::_input(const Ref<InputEvent> &p_event) { } } +bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { + + Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(p_point); + Rect2 item_rect = get_item_rect(); + + bool touched = false; + bool check_rect = true; + + if (shape.is_valid()) { + + check_rect = false; + Transform2D xform = shape_centered ? Transform2D().translated(item_rect.size * 0.5f) : Transform2D(); + touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); + } + + if (bitmask.is_valid()) { + + check_rect = false; + if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) { + + if (bitmask->get_bit(coord)) + touched = true; + } + } + + if (!touched && check_rect) { + if (texture.is_valid()) + touched = item_rect.has_point(coord); + } + + return touched; +} + void TouchScreenButton::_press(int p_finger_pressed) { finger_pressed = p_finger_pressed; diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h index e44f556c31..8923da2ae4 100644 --- a/scene/2d/screen_button.h +++ b/scene/2d/screen_button.h @@ -63,6 +63,8 @@ private: void _input(const Ref<InputEvent> &p_Event); + bool _is_point_inside(const Point2 &p_point); + void _press(int p_finger_pressed); void _release(bool p_exiting_tree = false); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index eebf0efd1e..4f892a31fc 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -587,7 +587,7 @@ Map<TileMap::PosKey, TileMap::Quadrant>::Element *TileMap::_create_quadrant(cons //q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); q.body = Physics2DServer::get_singleton()->body_create(use_kinematic ? Physics2DServer::BODY_MODE_KINEMATIC : Physics2DServer::BODY_MODE_STATIC); Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body, get_instance_ID()); - Physics2DServer::get_singleton()->body_set_layer_mask(q.body, collision_layer); + Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, friction); Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, bounce); @@ -863,7 +863,7 @@ void TileMap::set_collision_layer(uint32_t p_layer) { for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_layer_mask(q.body, collision_layer); + Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); } } @@ -1286,7 +1286,7 @@ void TileMap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_kinematic", PROPERTY_HINT_NONE, ""), "set_collision_use_kinematic", "get_collision_use_kinematic"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_GROUP("Occluder", "occluder_"); diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 8dae078e5b..39a4e926b2 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -489,15 +489,15 @@ uint32_t Area::get_collision_mask() const { return collision_mask; } -void Area::set_layer_mask(uint32_t p_mask) { +void Area::set_collision_layer(uint32_t p_layer) { - layer_mask = p_mask; - PhysicsServer::get_singleton()->area_set_layer_mask(get_rid(), p_mask); + collision_layer = p_layer; + PhysicsServer::get_singleton()->area_set_collision_layer(get_rid(), p_layer); } -uint32_t Area::get_layer_mask() const { +uint32_t Area::get_collision_layer() const { - return layer_mask; + return collision_layer; } void Area::set_collision_mask_bit(int p_bit, bool p_value) { @@ -515,19 +515,19 @@ bool Area::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } -void Area::set_layer_mask_bit(int p_bit, bool p_value) { +void Area::set_collision_layer_bit(int p_bit, bool p_value) { - uint32_t mask = get_layer_mask(); + uint32_t layer = get_collision_layer(); if (p_value) - mask |= 1 << p_bit; + layer |= 1 << p_bit; else - mask &= ~(1 << p_bit); - set_layer_mask(mask); + layer &= ~(1 << p_bit); + set_collision_layer(layer); } -bool Area::get_layer_mask_bit(int p_bit) const { +bool Area::get_collision_layer_bit(int p_bit) const { - return get_layer_mask() & (1 << p_bit); + return get_collision_layer() & (1 << p_bit); } void Area::_bind_methods() { @@ -565,14 +565,14 @@ void Area::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area::set_collision_mask); ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area::get_collision_mask); - ClassDB::bind_method(D_METHOD("set_layer_mask", "layer_mask"), &Area::set_layer_mask); - ClassDB::bind_method(D_METHOD("get_layer_mask"), &Area::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area::get_collision_layer); ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area::set_collision_mask_bit); ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area::get_collision_mask_bit); - ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "bit", "value"), &Area::set_layer_mask_bit); - ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "bit"), &Area::get_layer_mask_bit); + ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area::set_collision_layer_bit); + ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area::get_collision_layer_bit); ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area::set_monitorable); ClassDB::bind_method(D_METHOD("is_monitorable"), &Area::is_monitorable); @@ -610,7 +610,7 @@ void Area::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable"); ADD_GROUP("Collision", "collision_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layers", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_layer_mask", "get_layer_mask"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); } @@ -628,7 +628,7 @@ Area::Area() priority = 0; monitoring = false; collision_mask = 1; - layer_mask = 1; + collision_layer = 1; set_ray_pickable(false); set_monitoring(true); set_monitorable(true); diff --git a/scene/3d/area.h b/scene/3d/area.h index 64bbae9236..279a52ee69 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -55,7 +55,7 @@ private: real_t angular_damp; real_t linear_damp; uint32_t collision_mask; - uint32_t layer_mask; + uint32_t collision_layer; int priority; bool monitoring; bool monitorable; @@ -164,14 +164,14 @@ public: void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; - void set_layer_mask(uint32_t p_mask); - uint32_t get_layer_mask() const; + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; void set_collision_mask_bit(int p_bit, bool p_value); bool get_collision_mask_bit(int p_bit) const; - void set_layer_mask_bit(int p_bit, bool p_value); - bool get_layer_mask_bit(int p_bit) const; + void set_collision_layer_bit(int p_bit, bool p_value); + bool get_collision_layer_bit(int p_bit) const; Array get_overlapping_bodies() const; Array get_overlapping_areas() const; //function for script diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index d648ff078c..0f4378acdd 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -626,7 +626,7 @@ Camera::Camera() { current = false; force_change = false; mode = PROJECTION_PERSPECTIVE; - set_perspective(60.0, 0.1, 100.0); + set_perspective(65.0, 0.1, 100.0); keep_aspect = KEEP_HEIGHT; layers = 0xfffff; v_offset = 0; diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 6ab65d3994..9c87acec6e 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -234,7 +234,7 @@ void Light::_bind_methods() { BIND_CONSTANT(PARAM_SHADOW_SPLIT_3_OFFSET); BIND_CONSTANT(PARAM_SHADOW_NORMAL_BIAS); BIND_CONSTANT(PARAM_SHADOW_BIAS); - BIND_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE); + BIND_CONSTANT(PARAM_MAX); } @@ -261,9 +261,8 @@ Light::Light(VisualServer::LightType p_type) { set_param(PARAM_SHADOW_SPLIT_1_OFFSET, 0.1); set_param(PARAM_SHADOW_SPLIT_2_OFFSET, 0.2); set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5); - set_param(PARAM_SHADOW_NORMAL_BIAS, 0.1); - set_param(PARAM_SHADOW_BIAS, 0.1); - set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.1); + set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0); + set_param(PARAM_SHADOW_BIAS, 0.15); } Light::Light() { @@ -318,7 +317,6 @@ void DirectionalLight::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE); BIND_CONSTANT(SHADOW_ORTHOGONAL); BIND_CONSTANT(SHADOW_PARALLEL_2_SPLITS); @@ -328,7 +326,11 @@ void DirectionalLight::_bind_methods() { DirectionalLight::DirectionalLight() : Light(VisualServer::LIGHT_DIRECTIONAL) { + set_param(PARAM_SHADOW_NORMAL_BIAS, 0.2); + set_param(PARAM_SHADOW_BIAS, 1.0); + set_param(PARAM_SHADOW_MAX_DISTANCE, 200); set_shadow_mode(SHADOW_PARALLEL_4_SPLITS); + blend_splits = false; } @@ -371,7 +373,7 @@ void OmniLight::_bind_methods() { OmniLight::OmniLight() : Light(VisualServer::LIGHT_OMNI) { - set_shadow_mode(SHADOW_DUAL_PARABOLOID); + set_shadow_mode(SHADOW_CUBE); set_shadow_detail(SHADOW_DETAIL_HORIZONTAL); } diff --git a/scene/3d/light.h b/scene/3d/light.h index c02f9d12d3..22ff5c0763 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -60,7 +60,6 @@ public: PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS, PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS, - PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE, PARAM_MAX = VS::LIGHT_PARAM_MAX }; diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 98babedf0d..3a55a2bc32 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -59,15 +59,15 @@ float PhysicsBody::get_inverse_mass() const { return 0; } -void PhysicsBody::set_collision_layer(uint32_t p_mask) { +void PhysicsBody::set_collision_layer(uint32_t p_layer) { - layer_mask = p_mask; - PhysicsServer::get_singleton()->body_set_layer_mask(get_rid(), p_mask); + collision_layer = p_layer; + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), p_layer); } uint32_t PhysicsBody::get_collision_layer() const { - return layer_mask; + return collision_layer; } void PhysicsBody::set_collision_mask(uint32_t p_mask) { @@ -167,7 +167,7 @@ void PhysicsBody::_bind_methods() { PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject(PhysicsServer::get_singleton()->body_create(p_mode), false) { - layer_mask = 1; + collision_layer = 1; collision_mask = 1; } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index d13f84dc15..db4147f8f6 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -38,7 +38,7 @@ class PhysicsBody : public CollisionObject { GDCLASS(PhysicsBody, CollisionObject); - uint32_t layer_mask; + uint32_t collision_layer; uint32_t collision_mask; void _set_layers(uint32_t p_mask); @@ -54,7 +54,7 @@ public: virtual Vector3 get_angular_velocity() const; virtual float get_inverse_mass() const; - void set_collision_layer(uint32_t p_mask); + void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; void set_collision_mask(uint32_t p_mask); diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp deleted file mode 100644 index c3d83ad50d..0000000000 --- a/scene/3d/quad.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/*************************************************************************/ -/* quad.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "quad.h" -#include "servers/visual_server.h" - -void Quad::_update() { - - if (!is_inside_tree()) - return; - - Vector3 normal; - normal[axis] = 1.0; - - const int axis_order_1[3] = { 1, 2, 0 }; - const int axis_order_2[3] = { 2, 0, 1 }; - const int a1 = axis_order_1[axis]; - const int a2 = axis_order_2[axis]; - - PoolVector<Vector3> points; - points.resize(4); - PoolVector<Vector3>::Write pointsw = points.write(); - - Vector2 s2 = size * 0.5; - Vector2 o = offset; - if (!centered) - o += s2; - - pointsw[0][a1] = -s2.x + offset.x; - pointsw[0][a2] = s2.y + offset.y; - - pointsw[1][a1] = s2.x + offset.x; - pointsw[1][a2] = s2.y + offset.y; - - pointsw[2][a1] = s2.x + offset.x; - pointsw[2][a2] = -s2.y + offset.y; - - pointsw[3][a1] = -s2.x + offset.x; - pointsw[3][a2] = -s2.y + offset.y; - - aabb = Rect3(pointsw[0], Vector3()); - for (int i = 1; i < 4; i++) - aabb.expand_to(pointsw[i]); - - pointsw = PoolVector<Vector3>::Write(); - - PoolVector<Vector3> normals; - normals.resize(4); - PoolVector<Vector3>::Write normalsw = normals.write(); - - for (int i = 0; i < 4; i++) - normalsw[i] = normal; - - normalsw = PoolVector<Vector3>::Write(); - - PoolVector<Vector2> uvs; - uvs.resize(4); - PoolVector<Vector2>::Write uvsw = uvs.write(); - - uvsw[0] = Vector2(0, 0); - uvsw[1] = Vector2(1, 0); - uvsw[2] = Vector2(1, 1); - uvsw[3] = Vector2(0, 1); - - uvsw = PoolVector<Vector2>::Write(); - - PoolVector<int> indices; - indices.resize(6); - - PoolVector<int>::Write indicesw = indices.write(); - indicesw[0] = 0; - indicesw[1] = 1; - indicesw[2] = 2; - indicesw[3] = 2; - indicesw[4] = 3; - indicesw[5] = 0; - - indicesw = PoolVector<int>::Write(); - - Array arr; - arr.resize(VS::ARRAY_MAX); - arr[VS::ARRAY_VERTEX] = points; - arr[VS::ARRAY_NORMAL] = normals; - arr[VS::ARRAY_TEX_UV] = uvs; - arr[VS::ARRAY_INDEX] = indices; - - if (configured) { - VS::get_singleton()->mesh_remove_surface(mesh, 0); - } else { - configured = true; - } - VS::get_singleton()->mesh_add_surface_from_arrays(mesh, VS::PRIMITIVE_TRIANGLES, arr); - - pending_update = false; -} - -void Quad::set_axis(Vector3::Axis p_axis) { - - axis = p_axis; - _update(); -} - -Vector3::Axis Quad::get_axis() const { - - return axis; -} - -void Quad::set_size(const Vector2 &p_size) { - - size = p_size; - _update(); -} -Vector2 Quad::get_size() const { - - return size; -} - -void Quad::set_offset(const Vector2 &p_offset) { - - offset = p_offset; - _update(); -} -Vector2 Quad::get_offset() const { - - return offset; -} - -void Quad::set_centered(bool p_enabled) { - - centered = p_enabled; - _update(); -} -bool Quad::is_centered() const { - - return centered; -} - -void Quad::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_ENTER_TREE: { - - if (pending_update) - _update(); - - } break; - case NOTIFICATION_EXIT_TREE: { - - pending_update = true; - - } break; - } -} - -PoolVector<Face3> Quad::get_faces(uint32_t p_usage_flags) const { - - return PoolVector<Face3>(); -} - -Rect3 Quad::get_aabb() const { - - return aabb; -} - -void Quad::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_axis", "axis"), &Quad::set_axis); - ClassDB::bind_method(D_METHOD("get_axis"), &Quad::get_axis); - - ClassDB::bind_method(D_METHOD("set_size", "size"), &Quad::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &Quad::get_size); - - ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Quad::set_centered); - ClassDB::bind_method(D_METHOD("is_centered"), &Quad::is_centered); - - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Quad::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &Quad::get_offset); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X,Y,Z"), "set_axis", "get_axis"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); -} - -Quad::Quad() { - - pending_update = true; - centered = true; - //offset=0; - size = Vector2(1, 1); - axis = Vector3::AXIS_Z; - mesh = VisualServer::get_singleton()->mesh_create(); - set_base(mesh); - configured = false; -} - -Quad::~Quad() { - VisualServer::get_singleton()->free(mesh); -} diff --git a/scene/3d/quad.h b/scene/3d/quad.h deleted file mode 100644 index bb6c1219ad..0000000000 --- a/scene/3d/quad.h +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/* quad.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef QUAD_H -#define QUAD_H - -#include "rid.h" -#include "scene/3d/visual_instance.h" - -class Quad : public GeometryInstance { - - GDCLASS(Quad, GeometryInstance); - - Vector3::Axis axis; - bool centered; - Vector2 offset; - Vector2 size; - - Rect3 aabb; - bool configured; - bool pending_update; - RID mesh; - - void _update(); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_axis(Vector3::Axis p_axis); - Vector3::Axis get_axis() const; - - void set_size(const Vector2 &p_sizze); - Vector2 get_size() const; - - void set_offset(const Vector2 &p_offset); - Vector2 get_offset() const; - - void set_centered(bool p_enabled); - bool is_centered() const; - - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; - virtual Rect3 get_aabb() const; - - Quad(); - ~Quad(); -}; - -#endif // QUAD_H diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 345afd3edf..67e7fb0e12 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -46,14 +46,14 @@ Vector3 RayCast::get_cast_to() const { return cast_to; } -void RayCast::set_layer_mask(uint32_t p_mask) { +void RayCast::set_collision_layer(uint32_t p_layer) { - layer_mask = p_mask; + collision_layer = p_layer; } -uint32_t RayCast::get_layer_mask() const { +uint32_t RayCast::get_collision_layer() const { - return layer_mask; + return collision_layer; } void RayCast::set_type_mask(uint32_t p_mask) { @@ -170,7 +170,7 @@ void RayCast::_update_raycast_state() { PhysicsDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, layer_mask, type_mask)) { + if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_layer, type_mask)) { collided = true; against = rr.collider_id; @@ -243,15 +243,15 @@ void RayCast::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_exceptions"), &RayCast::clear_exceptions); - ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &RayCast::set_layer_mask); - ClassDB::bind_method(D_METHOD("get_layer_mask"), &RayCast::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &RayCast::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &RayCast::get_collision_layer); ClassDB::bind_method(D_METHOD("set_type_mask", "mask"), &RayCast::set_type_mask); ClassDB::bind_method(D_METHOD("get_type_mask"), &RayCast::get_type_mask); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "layer_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_layer_mask", "get_layer_mask"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "type_mask", PROPERTY_HINT_FLAGS, "Static,Kinematic,Rigid,Character,Area"), "set_type_mask", "get_type_mask"); } @@ -323,7 +323,7 @@ RayCast::RayCast() { against = 0; collided = false; against_shape = 0; - layer_mask = 1; + collision_layer = 1; type_mask = PhysicsDirectSpaceState::TYPE_MASK_COLLISION; cast_to = Vector3(0, -1, 0); debug_shape = NULL; diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 63a53d724f..e9b34c4f75 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -47,7 +47,7 @@ class RayCast : public Spatial { Set<RID> exclude; - uint32_t layer_mask; + uint32_t collision_layer; uint32_t type_mask; Node *debug_shape; @@ -69,8 +69,8 @@ public: void set_cast_to(const Vector3 &p_point); Vector3 get_cast_to() const; - void set_layer_mask(uint32_t p_mask); - uint32_t get_layer_mask() const; + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; void set_type_mask(uint32_t p_mask); uint32_t get_type_mask() const; diff --git a/scene/3d/test_cube.cpp b/scene/3d/test_cube.cpp deleted file mode 100644 index af09bef7a7..0000000000 --- a/scene/3d/test_cube.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* test_cube.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "test_cube.h" -#include "servers/visual_server.h" - -Rect3 TestCube::get_aabb() const { - - return Rect3(Vector3(-1, -1, -1), Vector3(2, 2, 2)); -} -PoolVector<Face3> TestCube::get_faces(uint32_t p_usage_flags) const { - - return PoolVector<Face3>(); -} - -TestCube::TestCube() { - - set_base(VisualServer::get_singleton()->get_test_cube()); -} - -TestCube::~TestCube() { -} diff --git a/scene/3d/test_cube.h b/scene/3d/test_cube.h deleted file mode 100644 index db2bef67fe..0000000000 --- a/scene/3d/test_cube.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************/ -/* test_cube.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef TEST_CUBE_H -#define TEST_CUBE_H - -#include "rid.h" -#include "scene/3d/visual_instance.h" - -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ -class TestCube : public GeometryInstance { - - GDCLASS(TestCube, GeometryInstance); - - RID instance; - -public: - virtual Rect3 get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; - - TestCube(); - ~TestCube(); -}; - -#endif diff --git a/scene/gui/button_array.cpp b/scene/gui/button_array.cpp deleted file mode 100644 index 1616272e66..0000000000 --- a/scene/gui/button_array.cpp +++ /dev/null @@ -1,546 +0,0 @@ -/*************************************************************************/ -/* button_array.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "button_array.h" - -bool ButtonArray::_set(const StringName &p_name, const Variant &p_value) { - - String n = String(p_name); - if (n.begins_with("button/")) { - - String what = n.get_slicec('/', 1); - if (what == "count") { - int new_size = p_value; - if (new_size > 0 && buttons.size() == 0) { - selected = 0; - } - - if (new_size < buttons.size()) { - if (selected >= new_size) - selected = new_size - 1; - } - buttons.resize(new_size); - _change_notify(); - minimum_size_changed(); - } else if (what == "align") { - set_align(Align(p_value.operator int())); - } else if (what == "selected") { - set_selected(p_value); - } else if (what == "min_button_size") { - min_button_size = p_value; - } else { - int idx = what.to_int(); - ERR_FAIL_INDEX_V(idx, buttons.size(), false); - String f = n.get_slicec('/', 2); - if (f == "text") { - buttons[idx].text = p_value; - buttons[idx].xl_text = XL_MESSAGE(p_value); - } else if (f == "tooltip") - buttons[idx].tooltip = p_value; - else if (f == "icon") - buttons[idx].icon = p_value; - else - return false; - } - - update(); - return true; - } - - return false; -} - -bool ButtonArray::_get(const StringName &p_name, Variant &r_ret) const { - - String n = String(p_name); - if (n.begins_with("button/")) { - - String what = n.get_slicec('/', 1); - if (what == "count") { - r_ret = buttons.size(); - } else if (what == "align") { - r_ret = get_align(); - } else if (what == "selected") { - r_ret = get_selected(); - } else if (what == "min_button_size") { - r_ret = min_button_size; - } else { - int idx = what.to_int(); - ERR_FAIL_INDEX_V(idx, buttons.size(), false); - String f = n.get_slicec('/', 2); - if (f == "text") - r_ret = buttons[idx].text; - else if (f == "tooltip") - r_ret = buttons[idx].tooltip; - else if (f == "icon") - r_ret = buttons[idx].icon; - else - return false; - } - - return true; - } - - return false; -} -void ButtonArray::_get_property_list(List<PropertyInfo> *p_list) const { - - p_list->push_back(PropertyInfo(Variant::INT, "button/count", PROPERTY_HINT_RANGE, "0,512,1")); - p_list->push_back(PropertyInfo(Variant::INT, "button/min_button_size", PROPERTY_HINT_RANGE, "0,1024,1")); - p_list->push_back(PropertyInfo(Variant::INT, "button/align", PROPERTY_HINT_ENUM, "Begin,Center,End,Fill,Expand")); - for (int i = 0; i < buttons.size(); i++) { - String base = "button/" + itos(i) + "/"; - p_list->push_back(PropertyInfo(Variant::STRING, base + "text")); - p_list->push_back(PropertyInfo(Variant::STRING, base + "tooltip")); - p_list->push_back(PropertyInfo(Variant::OBJECT, base + "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture")); - } - if (buttons.size() > 0) { - p_list->push_back(PropertyInfo(Variant::INT, "button/selected", PROPERTY_HINT_RANGE, "0," + itos(buttons.size() - 1) + ",1")); - } -} - -Size2 ButtonArray::get_minimum_size() const { - - Ref<StyleBox> style_normal = get_stylebox("normal"); - Ref<StyleBox> style_selected = get_stylebox("selected"); - Ref<Font> font_normal = get_font("font"); - Ref<Font> font_selected = get_font("font_selected"); - int icon_sep = get_constant("icon_separator"); - int button_sep = get_constant("button_separator"); - - Size2 minsize; - - for (int i = 0; i < buttons.size(); i++) { - - Ref<StyleBox> sb = i == selected ? style_selected : style_normal; - Ref<Font> f = i == selected ? font_selected : font_normal; - - Size2 ms; - ms = f->get_string_size(buttons[i].xl_text); - if (buttons[i].icon.is_valid()) { - - Size2 bs = buttons[i].icon->get_size(); - ms.height = MAX(ms.height, bs.height); - ms.width += bs.width + icon_sep; - } - - ms += sb->get_minimum_size(); - - buttons[i]._ms_cache = ms[orientation]; - - minsize[orientation] += ms[orientation]; - if (i > 0) - minsize[orientation] += button_sep; - minsize[!orientation] = MAX(minsize[!orientation], ms[!orientation]); - } - - return minsize; -} - -void ButtonArray::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_MOUSE_EXIT: { - hover = -1; - update(); - } break; - case NOTIFICATION_READY: { - MethodInfo mi; - mi.name = "mouse_sub_enter"; - - add_user_signal(mi); - - } break; - case NOTIFICATION_DRAW: { - - Size2 size = get_size(); - Size2 minsize = get_combined_minimum_size(); - Ref<StyleBox> style_normal = get_stylebox("normal"); - Ref<StyleBox> style_selected = get_stylebox("selected"); - Ref<StyleBox> style_focus = get_stylebox("focus"); - Ref<StyleBox> style_hover = get_stylebox("hover"); - Ref<Font> font_normal = get_font("font"); - Ref<Font> font_selected = get_font("font_selected"); - int icon_sep = get_constant("icon_separator"); - int button_sep = get_constant("button_separator"); - Color color_normal = get_color("font_color"); - Color color_selected = get_color("font_color_selected"); - - int sep = button_sep; - int ofs = 0; - int expand = 0; - - switch (align) { - case ALIGN_BEGIN: { - - ofs = 0; - } break; - case ALIGN_CENTER: { - - ofs = Math::floor((size[orientation] - minsize[orientation]) / 2); - } break; - case ALIGN_END: { - - ofs = Math::floor((size[orientation] - minsize[orientation])); - } break; - case ALIGN_FILL: { - - if (buttons.size() > 1) - sep += Math::floor((size[orientation] - minsize[orientation]) / (buttons.size() - 1.0)); - ofs = 0; - } break; - case ALIGN_EXPAND_FILL: { - - ofs = 0; - expand = size[orientation] - minsize[orientation]; - } break; - } - - int op_size = orientation == VERTICAL ? size.width : size.height; - - for (int i = 0; i < buttons.size(); i++) { - - int ms = buttons[i]._ms_cache; - int s = ms; - if (expand > 0) { - s += expand / buttons.size(); - } - if (min_button_size != -1 && s < min_button_size) { - s = min_button_size; - } - - Rect2 r; - r.position[orientation] = ofs; - r.position[!orientation] = 0; - r.size[orientation] = s; - r.size[!orientation] = op_size; - - Ref<Font> f; - Color c; - Point2 sbsize; - Point2 sbofs; - if (i == selected) { - draw_style_box(style_selected, r); - sbsize = style_selected->get_minimum_size(); - sbofs = style_selected->get_offset(); - f = font_selected; - c = color_selected; - if (has_focus()) - draw_style_box(style_focus, r); - } else { - if (hover == i) - draw_style_box(style_hover, r); - else if (!flat) - draw_style_box(style_normal, r); - sbsize = style_normal->get_minimum_size(); - sbofs = style_normal->get_offset(); - f = font_normal; - c = color_normal; - } - - Size2 ssize = f->get_string_size(buttons[i].xl_text); - if (buttons[i].icon.is_valid()) { - - ssize.x += buttons[i].icon->get_width(); - } - Point2 text_ofs = ((r.size - ssize - sbsize) / 2.0 + Point2(0, f->get_ascent())).floor() + sbofs; - if (buttons[i].icon.is_valid()) { - - draw_texture(buttons[i].icon, r.position + Point2(text_ofs.x, Math::floor((r.size.height - buttons[i].icon->get_height()) / 2.0))); - text_ofs.x += buttons[i].icon->get_width() + icon_sep; - } - draw_string(f, text_ofs + r.position, buttons[i].xl_text, c); - buttons[i]._pos_cache = ofs; - buttons[i]._size_cache = s; - - ofs += s; - ofs += sep; - } - - } break; - } -} - -void ButtonArray::_gui_input(const Ref<InputEvent> &p_event) { - - if ( - ((orientation == HORIZONTAL && p_event->is_action("ui_left")) || - (orientation == VERTICAL && p_event->is_action("ui_up"))) && - p_event->is_pressed() && selected > 0) { - set_selected(selected - 1); - accept_event(); - emit_signal("button_selected", selected); - return; - } - - if ( - ((orientation == HORIZONTAL && p_event->is_action("ui_right")) || - (orientation == VERTICAL && p_event->is_action("ui_down"))) && - p_event->is_pressed() && selected < (buttons.size() - 1)) { - set_selected(selected + 1); - accept_event(); - emit_signal("button_selected", selected); - return; - } - - Ref<InputEventMouseButton> mb = p_event; - - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - - int ofs = orientation == HORIZONTAL ? mb->get_position().x : mb->get_position().y; - - for (int i = 0; i < buttons.size(); i++) { - - if (ofs >= buttons[i]._pos_cache && ofs < buttons[i]._pos_cache + buttons[i]._size_cache) { - - set_selected(i); - emit_signal("button_selected", i); - return; - } - } - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - - int ofs = orientation == HORIZONTAL ? mm->get_position().x : mm->get_position().y; - int new_hover = -1; - for (int i = 0; i < buttons.size(); i++) { - - if (ofs >= buttons[i]._pos_cache && ofs < buttons[i]._pos_cache + buttons[i]._size_cache) { - - new_hover = i; - break; - } - } - - if (new_hover != hover) { - hover = new_hover; - emit_signal("mouse_sub_enter"); - update(); - } - } -} - -String ButtonArray::get_tooltip(const Point2 &p_pos) const { - - int ofs = orientation == HORIZONTAL ? p_pos.x : p_pos.y; - for (int i = 0; i < buttons.size(); i++) { - - if (ofs >= buttons[i]._pos_cache && ofs < buttons[i]._pos_cache + buttons[i]._size_cache) - return buttons[i].tooltip; - } - return Control::get_tooltip(p_pos); -} - -void ButtonArray::set_align(Align p_align) { - - align = p_align; - update(); -} - -ButtonArray::Align ButtonArray::get_align() const { - - return align; -} - -void ButtonArray::set_flat(bool p_flat) { - - flat = p_flat; - update(); -} - -bool ButtonArray::is_flat() const { - - return flat; -} - -void ButtonArray::add_button(const String &p_text, const String &p_tooltip) { - - Button button; - button.text = p_text; - button.xl_text = XL_MESSAGE(p_text); - button.tooltip = p_tooltip; - buttons.push_back(button); - update(); - - if (selected == -1) - selected = 0; - - minimum_size_changed(); -} - -void ButtonArray::add_icon_button(const Ref<Texture> &p_icon, const String &p_text, const String &p_tooltip) { - - Button button; - button.text = p_text; - button.xl_text = XL_MESSAGE(p_text); - button.icon = p_icon; - button.tooltip = p_tooltip; - buttons.push_back(button); - if (selected == -1) - selected = 0; - - update(); -} - -void ButtonArray::set_button_text(int p_button, const String &p_text) { - - ERR_FAIL_INDEX(p_button, buttons.size()); - buttons[p_button].text = p_text; - buttons[p_button].xl_text = XL_MESSAGE(p_text); - update(); - minimum_size_changed(); -} - -void ButtonArray::set_button_tooltip(int p_button, const String &p_text) { - - ERR_FAIL_INDEX(p_button, buttons.size()); - buttons[p_button].tooltip = p_text; -} - -void ButtonArray::set_button_icon(int p_button, const Ref<Texture> &p_icon) { - - ERR_FAIL_INDEX(p_button, buttons.size()); - buttons[p_button].icon = p_icon; - update(); - minimum_size_changed(); -} - -String ButtonArray::get_button_text(int p_button) const { - - ERR_FAIL_INDEX_V(p_button, buttons.size(), ""); - return buttons[p_button].text; -} - -String ButtonArray::get_button_tooltip(int p_button) const { - - ERR_FAIL_INDEX_V(p_button, buttons.size(), ""); - return buttons[p_button].tooltip; -} - -Ref<Texture> ButtonArray::get_button_icon(int p_button) const { - - ERR_FAIL_INDEX_V(p_button, buttons.size(), Ref<Texture>()); - return buttons[p_button].icon; -} - -int ButtonArray::get_selected() const { - - return selected; -} - -int ButtonArray::get_hovered() const { - - return hover; -} - -void ButtonArray::set_selected(int p_selected) { - - ERR_FAIL_INDEX(p_selected, buttons.size()); - selected = p_selected; - update(); -} - -void ButtonArray::erase_button(int p_button) { - - ERR_FAIL_INDEX(p_button, buttons.size()); - buttons.remove(p_button); - if (p_button >= selected) - selected--; - if (selected < 0) - selected = 0; - if (selected >= buttons.size()) - selected = buttons.size() - 1; - - update(); -} - -void ButtonArray::clear() { - - buttons.clear(); - selected = -1; - update(); -} - -int ButtonArray::get_button_count() const { - - return buttons.size(); -} - -void ButtonArray::get_translatable_strings(List<String> *p_strings) const { - - for (int i = 0; i < buttons.size(); i++) { - p_strings->push_back(buttons[i].text); - p_strings->push_back(buttons[i].tooltip); - } -} - -void ButtonArray::_bind_methods() { - - ClassDB::bind_method(D_METHOD("add_button", "text", "tooltip"), &ButtonArray::add_button, DEFVAL("")); - ClassDB::bind_method(D_METHOD("add_icon_button", "icon:Texture", "text", "tooltip"), &ButtonArray::add_icon_button, DEFVAL(""), DEFVAL("")); - ClassDB::bind_method(D_METHOD("set_button_text", "button_idx", "text"), &ButtonArray::set_button_text); - ClassDB::bind_method(D_METHOD("set_button_tooltip", "button_idx", "text"), &ButtonArray::set_button_tooltip); - ClassDB::bind_method(D_METHOD("set_button_icon", "button_idx", "icon:Texture"), &ButtonArray::set_button_icon); - ClassDB::bind_method(D_METHOD("get_button_text", "button_idx"), &ButtonArray::get_button_text); - ClassDB::bind_method(D_METHOD("get_button_tooltip", "button_idx"), &ButtonArray::get_button_tooltip); - ClassDB::bind_method(D_METHOD("get_button_icon:Texture", "button_idx"), &ButtonArray::get_button_icon); - ClassDB::bind_method(D_METHOD("get_button_count"), &ButtonArray::get_button_count); - ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &ButtonArray::set_flat); - ClassDB::bind_method(D_METHOD("is_flat"), &ButtonArray::is_flat); - ClassDB::bind_method(D_METHOD("get_selected"), &ButtonArray::get_selected); - ClassDB::bind_method(D_METHOD("get_hovered"), &ButtonArray::get_hovered); - ClassDB::bind_method(D_METHOD("set_selected", "button_idx"), &ButtonArray::set_selected); - ClassDB::bind_method(D_METHOD("erase_button", "button_idx"), &ButtonArray::erase_button); - ClassDB::bind_method(D_METHOD("clear"), &ButtonArray::clear); - - ClassDB::bind_method(D_METHOD("_gui_input"), &ButtonArray::_gui_input); - - BIND_CONSTANT(ALIGN_BEGIN); - BIND_CONSTANT(ALIGN_CENTER); - BIND_CONSTANT(ALIGN_END); - BIND_CONSTANT(ALIGN_FILL); - BIND_CONSTANT(ALIGN_EXPAND_FILL); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); - - ADD_SIGNAL(MethodInfo("button_selected", PropertyInfo(Variant::INT, "button_idx"))); -} - -ButtonArray::ButtonArray(Orientation p_orientation) { - - orientation = p_orientation; - selected = -1; - set_focus_mode(FOCUS_ALL); - hover = -1; - flat = false; - min_button_size = -1; -} diff --git a/scene/gui/button_array.h b/scene/gui/button_array.h deleted file mode 100644 index 0ebf681cb6..0000000000 --- a/scene/gui/button_array.h +++ /dev/null @@ -1,131 +0,0 @@ -/*************************************************************************/ -/* button_array.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef BUTTON_ARRAY_H -#define BUTTON_ARRAY_H - -#include "scene/gui/control.h" - -class ButtonArray : public Control { - - GDCLASS(ButtonArray, Control); - -public: - enum Align { - ALIGN_BEGIN, - ALIGN_CENTER, - ALIGN_END, - ALIGN_FILL, - ALIGN_EXPAND_FILL - }; - -private: - Orientation orientation; - Align align; - - struct Button { - - String text; - String xl_text; - String tooltip; - Ref<Texture> icon; - mutable int _ms_cache; - mutable int _pos_cache; - mutable int _size_cache; - }; - - int selected; - int hover; - bool flat; - double min_button_size; - - Vector<Button> buttons; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - - void _notification(int p_what); - static void _bind_methods(); - -public: - void _gui_input(const Ref<InputEvent> &p_event); - - void set_align(Align p_align); - Align get_align() const; - - void set_flat(bool p_flat); - bool is_flat() const; - - void add_button(const String &p_button, const String &p_tooltip = ""); - void add_icon_button(const Ref<Texture> &p_icon, const String &p_button = "", const String &p_tooltip = ""); - - void set_button_text(int p_button, const String &p_text); - void set_button_tooltip(int p_button, const String &p_text); - void set_button_icon(int p_button, const Ref<Texture> &p_icon); - - String get_button_text(int p_button) const; - String get_button_tooltip(int p_button) const; - Ref<Texture> get_button_icon(int p_button) const; - - int get_selected() const; - int get_hovered() const; - void set_selected(int p_selected); - - int get_button_count() const; - - void erase_button(int p_button); - void clear(); - - virtual Size2 get_minimum_size() const; - - virtual void get_translatable_strings(List<String> *p_strings) const; - virtual String get_tooltip(const Point2 &p_pos) const; - - ButtonArray(Orientation p_orientation = HORIZONTAL); -}; - -class HButtonArray : public ButtonArray { - GDCLASS(HButtonArray, ButtonArray); - -public: - HButtonArray() - : ButtonArray(HORIZONTAL){}; -}; - -class VButtonArray : public ButtonArray { - GDCLASS(VButtonArray, ButtonArray); - -public: - VButtonArray() - : ButtonArray(VERTICAL){}; -}; - -#endif // BUTTON_ARRAY_H diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index f0e486aa50..d3bdc401ab 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -156,6 +156,8 @@ void ColorPicker::_update_color() { _update_text_value(); sample->update(); + uv_edit->update(); + w_edit->update(); updating = false; } @@ -263,10 +265,10 @@ void ColorPicker::_hsv_draw(int p_wich, Control *c) { points.push_back(c->get_size()); points.push_back(Vector2(0, c->get_size().y)); Vector<Color> colors; - colors.push_back(Color(1, 1, 1)); - colors.push_back(Color(1, 1, 1)); - colors.push_back(Color()); - colors.push_back(Color()); + colors.push_back(Color(1, 1, 1, 1)); + colors.push_back(Color(1, 1, 1, 1)); + colors.push_back(Color(0, 0, 0, 1)); + colors.push_back(Color(0, 0, 0, 1)); c->draw_polygon(points, colors); Vector<Color> colors2; Color col = color; @@ -279,7 +281,7 @@ void ColorPicker::_hsv_draw(int p_wich, Control *c) { colors2.push_back(col); col.a = 0; colors2.push_back(col); - c->draw_polygon(points, colors); + c->draw_polygon(points, colors2); int x = CLAMP(c->get_size().x * s, 0, c->get_size().x); int y = CLAMP(c->get_size().y - c->get_size().y * v, 0, c->get_size().y); col = color; @@ -290,7 +292,7 @@ void ColorPicker::_hsv_draw(int p_wich, Control *c) { } else if (p_wich == 1) { Ref<Texture> hue = get_icon("color_hue", "ColorPicker"); c->draw_texture_rect(hue, Rect2(Point2(), c->get_size())); - int y = c->get_size().y - c->get_size().y * h; + int y = c->get_size().y - c->get_size().y * (1.0 - h); Color col = Color(); col.set_hsv(h, 1, 1); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); @@ -343,7 +345,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &ev) { if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { changing_color = true; - h = 1 - ((float)bev->get_position().y) / 256.0; + h = 1 - (256.0 - (float)bev->get_position().y) / 256.0; } else { changing_color = false; @@ -362,7 +364,8 @@ void ColorPicker::_w_input(const Ref<InputEvent> &ev) { if (!changing_color) return; float y = CLAMP((float)mev->get_position().y, 0, 256); - h = 1.0 - y / 256.0; + //h = 1.0 - y / 256.0; + h = y / 256.0; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index ae30acf52e..45485b768e 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1184,6 +1184,7 @@ Size2 Control::get_parent_area_size() const { parent_size = get_viewport()->get_visible_rect().size; } + return parent_size; } diff --git a/scene/gui/color_ramp_edit.cpp b/scene/gui/gradient_edit.cpp index 33e4ce0403..58bce57580 100644 --- a/scene/gui/color_ramp_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -27,10 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "color_ramp_edit.h" +#include "gradient_edit.h" #include "os/keyboard.h" -ColorRampEdit::ColorRampEdit() { +GradientEdit::GradientEdit() { grabbed = -1; grabbing = false; set_focus_mode(FOCUS_ALL); @@ -46,7 +46,7 @@ ColorRampEdit::ColorRampEdit() { checker->create_from_image(img, ImageTexture::FLAG_REPEAT); } -int ColorRampEdit::_get_point_from_pos(int x) { +int GradientEdit::_get_point_from_pos(int x) { int result = -1; int total_w = get_size().width - get_size().height - 3; for (int i = 0; i < points.size(); i++) { @@ -58,7 +58,7 @@ int ColorRampEdit::_get_point_from_pos(int x) { return result; } -void ColorRampEdit::_show_color_picker() { +void GradientEdit::_show_color_picker() { if (grabbed == -1) return; Size2 ms = Size2(350, picker->get_combined_minimum_size().height + 10); @@ -68,10 +68,10 @@ void ColorRampEdit::_show_color_picker() { popup->popup(); } -ColorRampEdit::~ColorRampEdit() { +GradientEdit::~GradientEdit() { } -void ColorRampEdit::_gui_input(const Ref<InputEvent> &p_event) { +void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; @@ -272,7 +272,7 @@ void ColorRampEdit::_gui_input(const Ref<InputEvent> &p_event) { } } -void ColorRampEdit::_notification(int p_what) { +void GradientEdit::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { if (!picker->is_connected("color_changed", this, "_color_changed")) { @@ -370,7 +370,7 @@ void ColorRampEdit::_notification(int p_what) { } } -void ColorRampEdit::_draw_checker(int x, int y, int w, int h) { +void GradientEdit::_draw_checker(int x, int y, int w, int h) { //Draw it with polygon to insert UVs for scale Vector<Vector2> backPoints; backPoints.push_back(Vector2(x, y)); @@ -391,12 +391,12 @@ void ColorRampEdit::_draw_checker(int x, int y, int w, int h) { draw_polygon(backPoints, colorPoints, uvPoints, checker); } -Size2 ColorRampEdit::get_minimum_size() const { +Size2 GradientEdit::get_minimum_size() const { return Vector2(0, 16); } -void ColorRampEdit::_color_changed(const Color &p_color) { +void GradientEdit::_color_changed(const Color &p_color) { if (grabbed == -1) return; @@ -405,7 +405,7 @@ void ColorRampEdit::_color_changed(const Color &p_color) { emit_signal("ramp_changed"); } -void ColorRampEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) { +void GradientEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) { ERR_FAIL_COND(p_offsets.size() != p_colors.size()); points.clear(); @@ -420,33 +420,33 @@ void ColorRampEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> update(); } -Vector<float> ColorRampEdit::get_offsets() const { +Vector<float> GradientEdit::get_offsets() const { Vector<float> ret; for (int i = 0; i < points.size(); i++) ret.push_back(points[i].offset); return ret; } -Vector<Color> ColorRampEdit::get_colors() const { +Vector<Color> GradientEdit::get_colors() const { Vector<Color> ret; for (int i = 0; i < points.size(); i++) ret.push_back(points[i].color); return ret; } -void ColorRampEdit::set_points(Vector<Gradient::Point> &p_points) { +void GradientEdit::set_points(Vector<Gradient::Point> &p_points) { if (points.size() != p_points.size()) grabbed = -1; points.clear(); points = p_points; } -Vector<Gradient::Point> &ColorRampEdit::get_points() { +Vector<Gradient::Point> &GradientEdit::get_points() { return points; } -void ColorRampEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &ColorRampEdit::_gui_input); - ClassDB::bind_method(D_METHOD("_color_changed"), &ColorRampEdit::_color_changed); +void GradientEdit::_bind_methods() { + ClassDB::bind_method(D_METHOD("_gui_input"), &GradientEdit::_gui_input); + ClassDB::bind_method(D_METHOD("_color_changed"), &GradientEdit::_color_changed); ADD_SIGNAL(MethodInfo("ramp_changed")); } diff --git a/scene/gui/color_ramp_edit.h b/scene/gui/gradient_edit.h index 0fe447c43a..6c4ae6fd15 100644 --- a/scene/gui/color_ramp_edit.h +++ b/scene/gui/gradient_edit.h @@ -37,9 +37,9 @@ #define POINT_WIDTH 8 -class ColorRampEdit : public Control { +class GradientEdit : public Control { - GDCLASS(ColorRampEdit, Control); + GDCLASS(GradientEdit, Control); PopupPanel *popup; ColorPicker *picker; @@ -68,8 +68,8 @@ public: Vector<Gradient::Point> &get_points(); virtual Size2 get_minimum_size() const; - ColorRampEdit(); - virtual ~ColorRampEdit(); + GradientEdit(); + virtual ~GradientEdit(); }; /*class ColorRampEditPanel : public Panel diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index cdb7965444..600493b439 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -103,13 +103,17 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { } // test hovering to display right or close button + int hover_now = -1; int hover_buttons = -1; - hover = -1; for (int i = 0; i < tabs.size(); i++) { if (i < offset) continue; + Rect2 rect = get_tab_rect(i); + if (rect.has_point(pos)) { + hover_now = i; + } if (tabs[i].rb_rect.has_point(pos)) { rb_hover = i; cb_hover = -1; @@ -122,6 +126,10 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { break; } } + if (hover != hover_now) { + hover = hover_now; + emit_signal("tab_hover", hover); + } if (hover_buttons == -1) { // no hover rb_hover = hover_buttons; @@ -234,11 +242,13 @@ void Tabs::_notification(int p_what) { update(); } break; case NOTIFICATION_RESIZED: { - + _update_cache(); _ensure_no_over_offset(); + ensure_tab_visible(current); + } break; case NOTIFICATION_DRAW: { - + _update_cache(); RID ci = get_canvas_item(); Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); @@ -286,18 +296,7 @@ void Tabs::_notification(int p_what) { tabs[i].ofs_cache = w; - int lsize = get_tab_width(i); - - String text = tabs[i].text; - int slen = font->get_string_size(text).width; - - if (w + lsize > limit) { - max_drawn_tab = i - 1; - missing_right = true; - break; - } else { - max_drawn_tab = i; - } + int lsize = tabs[i].size_cache; Ref<StyleBox> sb; Color col; @@ -313,7 +312,15 @@ void Tabs::_notification(int p_what) { col = color_bg; } - Rect2 sb_rect = Rect2(w, 0, lsize, h); + if (w + lsize > limit) { + max_drawn_tab = i - 1; + missing_right = true; + break; + } else { + max_drawn_tab = i; + } + + Rect2 sb_rect = Rect2(w, 0, tabs[i].size_cache, h); sb->draw(ci, sb_rect); w += sb->get_margin(MARGIN_LEFT); @@ -323,13 +330,13 @@ void Tabs::_notification(int p_what) { if (icon.is_valid()) { icon->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); - if (text != "") + if (tabs[i].text != "") w += icon->get_width() + get_constant("hseparation"); } - font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), text, col); + font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].text, col, tabs[i].size_text); - w += slen; + w += tabs[i].size_text; if (tabs[i].right_button.is_valid()) { @@ -380,8 +387,6 @@ void Tabs::_notification(int p_what) { } w += sb->get_margin(MARGIN_RIGHT); - - tabs[i].size_cache = w - tabs[i].ofs_cache; } if (offset > 0 || missing_right) { @@ -419,6 +424,7 @@ void Tabs::set_current_tab(int p_current) { current = p_current; _change_notify("current_tab"); + _update_cache(); update(); } @@ -427,6 +433,10 @@ int Tabs::get_current_tab() const { return current; } +int Tabs::get_hovered_tab() const { + return hover; +} + void Tabs::set_tab_title(int p_tab, const String &p_title) { ERR_FAIL_INDEX(p_tab, tabs.size()); @@ -480,15 +490,81 @@ Ref<Texture> Tabs::get_tab_right_button(int p_tab) const { return tabs[p_tab].right_button; } +void Tabs::_update_cache() { + Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); + Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); + Ref<Font> font = get_font("font"); + Ref<Texture> incr = get_icon("increment"); + Ref<Texture> decr = get_icon("decrement"); + int limit = get_size().width - incr->get_width() - decr->get_width(); + + int w = 0; + int mw = 0; + int size_fixed = 0; + int count_resize = 0; + for (int i = 0; i < tabs.size(); i++) { + tabs[i].ofs_cache = mw; + tabs[i].size_cache = get_tab_width(i); + tabs[i].size_text = font->get_string_size(tabs[i].text).width; + mw += tabs[i].size_cache; + if (tabs[i].size_cache <= min_width || i == current) { + size_fixed += tabs[i].size_cache; + } else { + count_resize++; + } + } + int m_width = min_width; + if (count_resize > 0) { + m_width = MAX((limit - size_fixed) / count_resize, min_width); + } + for (int i = 0; i < tabs.size(); i++) { + if (i < offset) + continue; + Ref<StyleBox> sb; + if (tabs[i].disabled) { + sb = tab_disabled; + } else if (i == current) { + sb = tab_fg; + } else { + sb = tab_bg; + } + int lsize = tabs[i].size_cache; + int slen = tabs[i].size_text; + if (min_width > 0 && mw > limit && i != current) { + if (lsize > m_width) { + slen = m_width - (sb->get_margin(MARGIN_LEFT) + sb->get_margin(MARGIN_RIGHT)); + if (tabs[i].icon.is_valid()) { + slen -= tabs[i].icon->get_width(); + slen -= get_constant("hseparation"); + } + if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { + Ref<Texture> cb = get_icon("close"); + slen -= cb->get_width(); + slen -= get_constant("hseparation"); + } + slen = MAX(slen, 1); + lsize = m_width; + } + } + tabs[i].ofs_cache = w; + tabs[i].size_cache = lsize; + tabs[i].size_text = slen; + w += lsize; + } +} + void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) { Tab t; t.text = p_str; t.icon = p_icon; t.disabled = false; + t.ofs_cache = 0; + t.size_cache = 0; tabs.push_back(t); - + _update_cache(); update(); minimum_size_changed(); } @@ -505,6 +581,7 @@ void Tabs::remove_tab(int p_idx) { tabs.remove(p_idx); if (current >= p_idx) current--; + _update_cache(); update(); minimum_size_changed(); @@ -587,7 +664,7 @@ void Tabs::_ensure_no_over_offset() { if (i < offset - 1) continue; - total_w += get_tab_width(i); + total_w += tabs[i].size_cache; } if (total_w < limit) { @@ -604,37 +681,35 @@ void Tabs::ensure_tab_visible(int p_idx) { if (!is_inside_tree()) return; + if (tabs.size() == 0) return; ERR_FAIL_INDEX(p_idx, tabs.size()); - _ensure_no_over_offset(); - - if (p_idx <= offset) { + if (p_idx == offset) { + return; + } + if (p_idx < offset) { offset = p_idx; update(); return; } + int prev_offset = offset; Ref<Texture> incr = get_icon("increment"); Ref<Texture> decr = get_icon("decrement"); int limit = get_size().width - incr->get_width() - decr->get_width(); - - int x = 0; - for (int i = 0; i < tabs.size(); i++) { - - if (i < offset) - continue; - - int sz = get_tab_width(i); - tabs[i].x_cache = x; - tabs[i].x_size_cache = sz; - x += sz; + for (int i = offset; i <= p_idx; i++) { + if (tabs[i].ofs_cache + tabs[i].size_cache > limit) { + offset++; + } } - while (offset < tabs.size() && ((tabs[p_idx].x_cache + tabs[p_idx].x_size_cache) - tabs[offset].x_cache) > limit) { - offset++; + if (prev_offset != offset) { + update(); } +} - update(); +Rect2 Tabs::get_tab_rect(int p_tab) { + return Rect2(tabs[p_tab].ofs_cache, 0, tabs[p_tab].size_cache, get_size().height); } void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { @@ -642,6 +717,10 @@ void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { update(); } +void Tabs::set_min_width(int p_width) { + min_width = p_width; +} + void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input); @@ -663,6 +742,7 @@ void Tabs::_bind_methods() { ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("right_button_pressed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_close", PropertyInfo(Variant::INT, "tab"))); + ADD_SIGNAL(MethodInfo("tab_hover", PropertyInfo(Variant::INT, "tab"))); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); @@ -688,4 +768,6 @@ Tabs::Tabs() { cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; offset = 0; max_drawn_tab = 0; + + min_width = 0; } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 61b97d2dff..65d409c410 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -59,6 +59,7 @@ private: int ofs_cache; bool disabled; int size_cache; + int size_text; int x_cache; int x_size_cache; @@ -74,7 +75,6 @@ private: bool missing_right; Vector<Tab> tabs; int current; - Control *_get_tab(int idx) const; int _get_top_margin() const; TabAlign tab_align; int rb_hover; @@ -85,9 +85,11 @@ private: CloseButtonDisplayPolicy cb_displaypolicy; int hover; // hovered tab + int min_width; int get_tab_width(int p_idx) const; void _ensure_no_over_offset(); + void _update_cache(); protected: void _gui_input(const Ref<InputEvent> &p_event); @@ -117,13 +119,16 @@ public: int get_tab_count() const; void set_current_tab(int p_current); int get_current_tab() const; + int get_hovered_tab() const; void remove_tab(int p_idx); void clear_tabs(); void ensure_tab_visible(int p_idx); + void set_min_width(int p_width); + Rect2 get_tab_rect(int p_tab); Size2 get_minimum_size() const; Tabs(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 763cac2af4..d8ec8b9991 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1156,6 +1156,7 @@ void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vecto size_override_margin = p_margin; _update_rect(); _update_stretch_transform(); + emit_signal("size_changed"); } Size2 Viewport::get_size_override() const { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 9f078072d7..df3729c50b 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -42,7 +42,7 @@ #include "scene/2d/path_2d.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" -#include "scene/gui/button_array.h" + #include "scene/gui/button_group.h" #include "scene/gui/center_container.h" #include "scene/gui/check_box.h" @@ -74,7 +74,6 @@ #include "scene/gui/separator.h" #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" -#include "scene/gui/spin_box.h" #include "scene/gui/split_container.h" #include "scene/gui/tab_container.h" #include "scene/gui/tabs.h" @@ -130,7 +129,6 @@ #include "scene/animation/tween.h" #include "scene/main/resource_preloader.h" #include "scene/main/scene_main_loop.h" -#include "scene/main/scene_main_loop.h" #include "scene/resources/packed_scene.h" #include "scene/resources/mesh_data_tool.h" @@ -172,6 +170,8 @@ #include "scene/resources/sky_box.h" #include "scene/resources/texture.h" +#include "scene/resources/primitive_meshes.h" + #include "scene/resources/shader_graph.h" #include "scene/resources/world.h" @@ -206,9 +206,7 @@ #include "scene/3d/physics_body.h" #include "scene/3d/portal.h" #include "scene/3d/position_3d.h" -#include "scene/3d/quad.h" #include "scene/3d/reflection_probe.h" -#include "scene/3d/test_cube.h" #include "scene/resources/environment.h" #include "scene/3d/area.h" @@ -276,7 +274,7 @@ void register_scene_types() { String theme_path = GLOBAL_DEF("gui/theme/custom", ""); GlobalConfig::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); String font_path = GLOBAL_DEF("gui/theme/custom_font", ""); - GlobalConfig::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.fnt", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + GlobalConfig::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); if (theme_path != String()) { Ref<Theme> theme = ResourceLoader::load(theme_path); @@ -360,9 +358,6 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init - ClassDB::register_virtual_class<ButtonArray>(); - ClassDB::register_class<HButtonArray>(); - ClassDB::register_class<VButtonArray>(); ClassDB::register_class<TextureProgress>(); ClassDB::register_class<ItemList>(); @@ -410,7 +405,6 @@ void register_scene_types() { ClassDB::register_class<Camera>(); ClassDB::register_class<Listener>(); ClassDB::register_class<InterpolatedCamera>(); - ClassDB::register_class<TestCube>(); ClassDB::register_class<MeshInstance>(); ClassDB::register_class<ImmediateGeometry>(); ClassDB::register_class<Sprite3D>(); @@ -426,7 +420,6 @@ void register_scene_types() { ClassDB::register_class<Portal>(); ClassDB::register_class<Particles>(); ClassDB::register_class<Position3D>(); - ClassDB::register_class<Quad>(); ClassDB::register_class<NavigationMeshInstance>(); ClassDB::register_class<NavigationMesh>(); ClassDB::register_class<Navigation>(); @@ -525,6 +518,14 @@ void register_scene_types() { #ifndef _3D_DISABLED ClassDB::register_virtual_class<Mesh>(); ClassDB::register_class<ArrayMesh>(); + ClassDB::register_virtual_class<PrimitiveMesh>(); + ClassDB::register_class<CapsuleMesh>(); + ClassDB::register_class<CubeMesh>(); + ClassDB::register_class<CylinderMesh>(); + ClassDB::register_class<PlaneMesh>(); + ClassDB::register_class<PrismMesh>(); + ClassDB::register_class<QuadMesh>(); + ClassDB::register_class<SphereMesh>(); ClassDB::register_virtual_class<Material>(); ClassDB::register_class<SpatialMaterial>(); ClassDB::add_compatibility_class("FixedSpatialMaterial", "SpatialMaterial"); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index ef5befac65..b363f2b666 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -37,7 +37,7 @@ class Animation : public Resource { GDCLASS(Animation, Resource); - RES_BASE_EXTENSION("anm"); + RES_BASE_EXTENSION("anim"); public: enum TrackType { diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index 84d450e3f2..cd02df512f 100644 --- a/scene/resources/audio_stream_sample.h +++ b/scene/resources/audio_stream_sample.h @@ -84,7 +84,7 @@ public: class AudioStreamSample : public AudioStream { GDCLASS(AudioStreamSample, AudioStream) - RES_BASE_EXTENSION("smp") + RES_BASE_EXTENSION("sample") public: enum Format { diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index e40fc0d4be..a435ba06cc 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -315,7 +315,7 @@ void Environment::_validate_property(PropertyInfo &property) const { void Environment::set_ssr_enabled(bool p_enable) { ssr_enabled = p_enable; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); + VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness); _change_notify(); } @@ -327,57 +327,47 @@ bool Environment::is_ssr_enabled() const { void Environment::set_ssr_max_steps(int p_steps) { ssr_max_steps = p_steps; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); + VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness); } int Environment::get_ssr_max_steps() const { return ssr_max_steps; } -void Environment::set_ssr_accel(float p_accel) { +void Environment::set_ssr_fade_in(float p_fade_in) { - ssr_accel = p_accel; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); + ssr_fade_in = p_fade_in; + VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness); } -float Environment::get_ssr_accel() const { +float Environment::get_ssr_fade_in() const { - return ssr_accel; + return ssr_fade_in; } -void Environment::set_ssr_fade(float p_fade) { +void Environment::set_ssr_fade_out(float p_fade_out) { - ssr_fade = p_fade; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); + ssr_fade_out = p_fade_out; + VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness); } -float Environment::get_ssr_fade() const { +float Environment::get_ssr_fade_out() const { - return ssr_fade; + return ssr_fade_out; } void Environment::set_ssr_depth_tolerance(float p_depth_tolerance) { ssr_depth_tolerance = p_depth_tolerance; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); + VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness); } float Environment::get_ssr_depth_tolerance() const { return ssr_depth_tolerance; } -void Environment::set_ssr_smooth(bool p_enable) { - - ssr_smooth = p_enable; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); -} -bool Environment::is_ssr_smooth() const { - - return ssr_smooth; -} - void Environment::set_ssr_rough(bool p_enable) { ssr_roughness = p_enable; - VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_accel, ssr_fade, ssr_depth_tolerance, ssr_smooth, ssr_roughness); + VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness); } bool Environment::is_ssr_rough() const { @@ -954,18 +944,15 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ssr_max_steps", "max_steps"), &Environment::set_ssr_max_steps); ClassDB::bind_method(D_METHOD("get_ssr_max_steps"), &Environment::get_ssr_max_steps); - ClassDB::bind_method(D_METHOD("set_ssr_accel", "accel"), &Environment::set_ssr_accel); - ClassDB::bind_method(D_METHOD("get_ssr_accel"), &Environment::get_ssr_accel); + ClassDB::bind_method(D_METHOD("set_ssr_fade_in", "fade_in"), &Environment::set_ssr_fade_in); + ClassDB::bind_method(D_METHOD("get_ssr_fade_in"), &Environment::get_ssr_fade_in); - ClassDB::bind_method(D_METHOD("set_ssr_fade", "fade"), &Environment::set_ssr_fade); - ClassDB::bind_method(D_METHOD("get_ssr_fade"), &Environment::get_ssr_fade); + ClassDB::bind_method(D_METHOD("set_ssr_fade_out", "fade_out"), &Environment::set_ssr_fade_out); + ClassDB::bind_method(D_METHOD("get_ssr_fade_out"), &Environment::get_ssr_fade_out); ClassDB::bind_method(D_METHOD("set_ssr_depth_tolerance", "depth_tolerance"), &Environment::set_ssr_depth_tolerance); ClassDB::bind_method(D_METHOD("get_ssr_depth_tolerance"), &Environment::get_ssr_depth_tolerance); - ClassDB::bind_method(D_METHOD("set_ssr_smooth", "smooth"), &Environment::set_ssr_smooth); - ClassDB::bind_method(D_METHOD("is_ssr_smooth"), &Environment::is_ssr_smooth); - ClassDB::bind_method(D_METHOD("set_ssr_rough", "rough"), &Environment::set_ssr_rough); ClassDB::bind_method(D_METHOD("is_ssr_rough"), &Environment::is_ssr_rough); @@ -973,9 +960,9 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_enabled"), "set_ssr_enabled", "is_ssr_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ss_reflections_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_accel", PROPERTY_HINT_RANGE, "0,4,0.01"), "set_ssr_accel", "get_ssr_accel"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade", PROPERTY_HINT_EXP_EASING), "set_ssr_fade", "get_ssr_fade"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_depth_tolerance", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_accel_smooth"), "set_ssr_smooth", "is_ssr_smooth"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_roughness"), "set_ssr_rough", "is_ssr_rough"); ClassDB::bind_method(D_METHOD("set_ssao_enabled", "enabled"), &Environment::set_ssao_enabled); @@ -1179,10 +1166,9 @@ Environment::Environment() { ssr_enabled = false; ssr_max_steps = 64; - ssr_accel = 0.04; - ssr_fade = 2.0; + ssr_fade_in = 0.15; + ssr_fade_out = 2.0; ssr_depth_tolerance = 0.2; - ssr_smooth = true; ssr_roughness = true; ssao_enabled = false; diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 7df3458231..7eda8506b5 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -100,10 +100,9 @@ private: bool ssr_enabled; int ssr_max_steps; - float ssr_accel; - float ssr_fade; + float ssr_fade_in; + float ssr_fade_out; float ssr_depth_tolerance; - bool ssr_smooth; bool ssr_roughness; bool ssao_enabled; @@ -225,18 +224,15 @@ public: void set_ssr_max_steps(int p_steps); int get_ssr_max_steps() const; - void set_ssr_accel(float p_accel); - float get_ssr_accel() const; + void set_ssr_fade_in(float p_transition); + float get_ssr_fade_in() const; - void set_ssr_fade(float p_transition); - float get_ssr_fade() const; + void set_ssr_fade_out(float p_transition); + float get_ssr_fade_out() const; void set_ssr_depth_tolerance(float p_depth_tolerance); float get_ssr_depth_tolerance() const; - void set_ssr_smooth(bool p_enable); - bool is_ssr_smooth() const; - void set_ssr_rough(bool p_enable); bool is_ssr_rough() const; diff --git a/scene/resources/font.h b/scene/resources/font.h index 20978acccd..a04ffbdd4b 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -66,7 +66,7 @@ public: class BitmapFont : public Font { GDCLASS(BitmapFont, Font); - RES_BASE_EXTENSION("fnt"); + RES_BASE_EXTENSION("font"); Vector<Ref<Texture> > textures; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index ce88325539..a6927f13b9 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1370,6 +1370,8 @@ void SpatialMaterial::_bind_methods() { BIND_CONSTANT(BILLBOARD_ENABLED); BIND_CONSTANT(BILLBOARD_FIXED_Y); BIND_CONSTANT(BILLBOARD_PARTICLES); + + } SpatialMaterial::SpatialMaterial() diff --git a/scene/resources/material.h b/scene/resources/material.h index b6e85c8332..c043236489 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -43,7 +43,7 @@ class Material : public Resource { GDCLASS(Material, Resource); - RES_BASE_EXTENSION("mtl"); + RES_BASE_EXTENSION("material"); OBJ_SAVE_TYPE(Material); RID material; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 9f55f0c364..a3180ee1df 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1047,72 +1047,3 @@ ArrayMesh::~ArrayMesh() { VisualServer::get_singleton()->free(mesh); } - -//////////////////////// -#if 0 -void QuadMesh::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &QuadMesh::set_material); - ClassDB::bind_method(D_METHOD("get_material:Material"), &QuadMesh::get_material); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material", "get_material"); -} - -void QuadMesh::set_material(const Ref<Material> &p_material) { - - surface_set_material(0, p_material); -} - -Ref<Material> QuadMesh::get_material() const { - - return surface_get_material(0); -} - -QuadMesh::QuadMesh() { - - PoolVector<Vector3> faces; - PoolVector<Vector3> normals; - PoolVector<float> tangents; - PoolVector<Vector2> uvs; - - faces.resize(4); - normals.resize(4); - tangents.resize(4 * 4); - uvs.resize(4); - - for (int i = 0; i < 4; i++) { - - static const Vector3 quad_faces[4] = { - Vector3(-1, -1, 0), - Vector3(-1, 1, 0), - Vector3(1, 1, 0), - Vector3(1, -1, 0), - }; - - faces.set(i, quad_faces[i]); - normals.set(i, Vector3(0, 0, 1)); - tangents.set(i * 4 + 0, 1.0); - tangents.set(i * 4 + 1, 0.0); - tangents.set(i * 4 + 2, 0.0); - tangents.set(i * 4 + 3, 1.0); - - static const Vector2 quad_uv[4] = { - Vector2(0, 1), - Vector2(0, 0), - Vector2(1, 0), - Vector2(1, 1), - }; - - uvs.set(i, quad_uv[i]); - } - - Array arr; - arr.resize(ARRAY_MAX); - arr[ARRAY_VERTEX] = faces; - arr[ARRAY_NORMAL] = normals; - arr[ARRAY_TANGENT] = tangents; - arr[ARRAY_TEX_UV] = uvs; - - add_surface_from_arrays(PRIMITIVE_TRIANGLE_FAN, arr); -} -#endif diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 7804a84f81..37fddf3aa6 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -140,7 +140,7 @@ public: class ArrayMesh : public Mesh { GDCLASS(ArrayMesh, Mesh); - RES_BASE_EXTENSION("msh"); + RES_BASE_EXTENSION("mesh"); private: struct Surface { @@ -214,23 +214,6 @@ public: ~ArrayMesh(); }; -#if 0 -class QuadMesh : public Mesh { - - GDCLASS(QuadMesh, Mesh) - -protected: - virtual bool _is_generated() const { return true; } - static void _bind_methods(); - -public: - void set_material(const Ref<Material> &p_material); - Ref<Material> get_material() const; - QuadMesh(); -}; - -#endif - VARIANT_ENUM_CAST(Mesh::ArrayType); VARIANT_ENUM_CAST(Mesh::PrimitiveType); VARIANT_ENUM_CAST(Mesh::BlendShapeMode); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index a381f54a19..cc39110a99 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -39,7 +39,7 @@ class MeshLibrary : public Resource { GDCLASS(MeshLibrary, Resource); - RES_BASE_EXTENSION("gt"); + RES_BASE_EXTENSION("meshlib"); struct Item { String name; diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index 4a00685b9f..7d6a0ce44f 100644 --- a/scene/resources/multimesh.h +++ b/scene/resources/multimesh.h @@ -36,7 +36,7 @@ class MultiMesh : public Resource { GDCLASS(MultiMesh, Resource); - RES_BASE_EXTENSION("mmsh"); + RES_BASE_EXTENSION("multimesh"); public: enum TransformFormat { diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp new file mode 100644 index 0000000000..4064981f44 --- /dev/null +++ b/scene/resources/primitive_meshes.cpp @@ -0,0 +1,1455 @@ +/*************************************************************************/ +/* primitive_meshes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "primitive_meshes.h" +#include "servers/visual_server.h" + +/** + PrimitiveMesh +*/ +void PrimitiveMesh::_update() { + if (!cache_is_dirty) + return; + + Array arr; + arr.resize(VS::ARRAY_MAX); + _create_mesh_array(arr); + + // in with the new + VisualServer::get_singleton()->mesh_clear(mesh); + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr); + VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); + + cache_is_dirty = false; + + _clear_triangle_mesh(); + _change_notify(); + emit_changed(); +} + +void PrimitiveMesh::_queue_update() { + if (!cache_is_dirty) { + cache_is_dirty = true; + call_deferred("_update"); + } +} + +void PrimitiveMesh::set_aabb(Rect3 p_aabb) { + aabb = p_aabb; +} + +int PrimitiveMesh::get_surface_count() const { + return 1; +} + +int PrimitiveMesh::surface_get_array_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, -1); + return VisualServer::get_singleton()->mesh_surface_get_array_len(mesh, 0); +} + +int PrimitiveMesh::surface_get_array_index_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, -1); + return VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, 0); +} + +Array PrimitiveMesh::surface_get_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, 1, Array()); + return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, 0); +} + +uint32_t PrimitiveMesh::surface_get_format(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, 0); + return VisualServer::get_singleton()->mesh_surface_get_format(mesh, 0); +} + +Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const { + return primitive_type; +} + +Ref<Material> PrimitiveMesh::surface_get_material(int p_idx) const { + return material; +} + +int PrimitiveMesh::get_blend_shape_count() const { + return 0; +} + +StringName PrimitiveMesh::get_blend_shape_name(int p_index) const { + return StringName(); +} + +Rect3 PrimitiveMesh::get_aabb() const { + return aabb; +} + +RID PrimitiveMesh::get_rid() const { + return mesh; +} + +void PrimitiveMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update"), &PrimitiveMesh::_update); + + ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &PrimitiveMesh::set_material); + ClassDB::bind_method(D_METHOD("get_material:Material"), &PrimitiveMesh::get_material); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material", "get_material"); +} + +void PrimitiveMesh::set_material(const Ref<Material> &p_material) { + material = p_material; + if (!cache_is_dirty) { + // just apply it, else it'll happen when _update is called. + VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); + + _change_notify(); + emit_changed(); + }; +} + +Ref<Material> PrimitiveMesh::get_material() const { + return material; +} + +PrimitiveMesh::PrimitiveMesh() { + // defaults + mesh = VisualServer::get_singleton()->mesh_create(); + + // assume primitive triangles as the type, correct for all but one and it will change this :) + primitive_type = Mesh::PRIMITIVE_TRIANGLES; + + // make sure we do an update after we've finished constructing our object + cache_is_dirty = false; + _queue_update(); +} + +PrimitiveMesh::~PrimitiveMesh() { + VisualServer::get_singleton()->free(mesh); +} + +/** + CapsuleMesh +*/ + +void CapsuleMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z, u, v, w; + float onethird = 1.0 / 3.0; + float twothirds = 2.0 / 3.0; + + set_aabb(Rect3(Vector3(-radius, (mid_height * -0.5) - radius, -radius), Vector3(radius * 2.0, mid_height + (2.0 * radius), radius * 2.0))); + + PoolVector<Vector3> points; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + PoolVector<int> indices; + point = 0; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + /* top hemisphere */ + thisrow = 0; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + w; + + v /= (rings + 1); + w = sin(0.5 * Math_PI * v); + y = radius * cos(0.5 * Math_PI * v); + + for (i = 0; i <= radial_segments; i++) { + u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius * w, y, z * radius * w); + points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0)); + normals.push_back(p.normalized()); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, v * onethird)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + /* cylinder */ + thisrow = point; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + v /= (rings + 1); + + y = mid_height * v; + y = (mid_height * 0.5) - y; + + for (i = 0; i <= radial_segments; i++) { + u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius, y, z * radius); + points.push_back(p); + normals.push_back(Vector3(x, 0.0, z)); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, onethird + (v * onethird))); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + /* bottom hemisphere */ + thisrow = point; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + w; + + v /= (rings + 1); + v += 1.0; + w = sin(0.5 * Math_PI * v); + y = radius * cos(0.5 * Math_PI * v); + + for (i = 0; i <= radial_segments; i++) { + float u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius * w, y, z * radius * w); + points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0)); + normals.push_back(p.normalized()); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird))); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void CapsuleMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleMesh::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleMesh::get_radius); + ClassDB::bind_method(D_METHOD("set_mid_height", "mid_height"), &CapsuleMesh::set_mid_height); + ClassDB::bind_method(D_METHOD("get_mid_height"), &CapsuleMesh::get_mid_height); + + ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CapsuleMesh::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &CapsuleMesh::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_mid_height", "get_mid_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_rings", "get_rings"); +} + +void CapsuleMesh::set_radius(const float p_radius) { + radius = p_radius; + _queue_update(); +} + +float CapsuleMesh::get_radius() const { + return radius; +} + +void CapsuleMesh::set_mid_height(const float p_mid_height) { + mid_height = p_mid_height; + _queue_update(); +} + +float CapsuleMesh::get_mid_height() const { + return mid_height; +} + +void CapsuleMesh::set_radial_segments(const int p_segments) { + radial_segments = p_segments > 4 ? p_segments : 4; + _queue_update(); +} + +int CapsuleMesh::get_radial_segments() const { + return radial_segments; +} + +void CapsuleMesh::set_rings(const int p_rings) { + rings = p_rings > 1 ? p_rings : 1; + _queue_update(); +} + +int CapsuleMesh::get_rings() const { + return rings; +} + +CapsuleMesh::CapsuleMesh() { + // defaults + radius = 0.5; + mid_height = 0.5; + radial_segments = 64; + rings = 8; +} + +/** + CubeMesh +*/ + +void CubeMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z; + float onethird = 1.0 / 3.0; + float twothirds = 2.0 / 3.0; + + Vector3 start_pos = size * -0.5; + + // set our bounding box + set_aabb(Rect3(start_pos, size)); + + PoolVector<Vector3> points; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + PoolVector<int> indices; + point = 0; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + // front + back + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= subdivide_h + 1; j++) { + x = start_pos.x; + for (i = 0; i <= subdivide_w + 1; i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + // front + points.push_back(Vector3(x, -y, -start_pos.z)); // double negative on the Z! + normals.push_back(Vector3(0.0, 0.0, 1.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(u, v)); + point++; + + // back + points.push_back(Vector3(-x, -y, start_pos.z)); + normals.push_back(Vector3(0.0, 0.0, -1.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + u, v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + // front + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + // back + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + // left + right + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_h + 1); j++) { + z = start_pos.z; + for (i = 0; i <= (subdivide_d + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_d + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + // right + points.push_back(Vector3(-start_pos.x, -y, -z)); + normals.push_back(Vector3(1.0, 0.0, 0.0)); + ADD_TANGENT(0.0, 0.0, 1.0, -1.0); + uvs.push_back(Vector2(onethird + u, v)); + point++; + + // left + points.push_back(Vector3(start_pos.x, -y, z)); + normals.push_back(Vector3(-1.0, 0.0, 0.0)); + ADD_TANGENT(0.0, 0.0, -1.0, -1.0); + uvs.push_back(Vector2(u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + // right + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + // left + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + z += size.z / (subdivide_d + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + // top + bottom + z = start_pos.z; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_d + 1); j++) { + x = start_pos.x; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_d + 1.0)); + + // top + points.push_back(Vector3(-x, -start_pos.y, -z)); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(onethird + u, 0.5 + v)); + point++; + + // bottom + points.push_back(Vector3(x, start_pos.y, -z)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + // top + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + // bottom + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + z += size.z / (subdivide_d + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void CubeMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &CubeMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &CubeMesh::get_size); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &CubeMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &CubeMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &CubeMesh::set_subdivide_height); + ClassDB::bind_method(D_METHOD("get_subdivide_height"), &CubeMesh::get_subdivide_height); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_height", "get_subdivide_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void CubeMesh::set_size(const Vector3 &p_size) { + size = p_size; + _queue_update(); +} + +Vector3 CubeMesh::get_size() const { + return size; +} + +void CubeMesh::set_subdivide_width(const int p_subdivide) { + subdivide_w = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int CubeMesh::get_subdivide_width() const { + return subdivide_w; +} + +void CubeMesh::set_subdivide_height(const int p_subdivide) { + subdivide_h = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int CubeMesh::get_subdivide_height() const { + return subdivide_h; +} + +void CubeMesh::set_subdivide_depth(const int p_subdivide) { + subdivide_d = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int CubeMesh::get_subdivide_depth() const { + return subdivide_d; +} + +CubeMesh::CubeMesh() { + // defaults + size = Vector3(1.0, 1.0, 1.0); + subdivide_w = 0; + subdivide_h = 0; + subdivide_d = 0; +} + +/** + CylinderMesh +*/ + +void CylinderMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z, u, v, radius; + + radius = bottom_radius > top_radius ? bottom_radius : top_radius; + + set_aabb(Rect3(Vector3(-radius, height * -0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); + + PoolVector<Vector3> points; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + PoolVector<int> indices; + point = 0; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + thisrow = 0; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + v /= (rings + 1); + + radius = top_radius + ((bottom_radius - top_radius) * v); + + y = height * v; + y = (height * 0.5) - y; + + for (i = 0; i <= radial_segments; i++) { + u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius, y, z * radius); + points.push_back(p); + normals.push_back(Vector3(x, 0.0, z)); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, v * 0.5)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + // add top + if (top_radius > 0.0) { + y = height * 0.5; + + thisrow = point; + points.push_back(Vector3(0.0, y, 0.0)); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, 1.0) + uvs.push_back(Vector2(0.25, 0.75)); + point++; + + for (i = 0; i <= radial_segments; i++) { + float r = i; + r /= radial_segments; + + x = sin(r * (Math_PI * 2.0)); + z = cos(r * (Math_PI * 2.0)); + + u = ((x + 1.0) * 0.25); + v = 0.5 + ((z + 1.0) * 0.25); + + Vector3 p = Vector3(x * top_radius, y, z * top_radius); + points.push_back(p); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, 1.0) + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0) { + indices.push_back(thisrow); + indices.push_back(point - 1); + indices.push_back(point - 2); + }; + }; + }; + + // add bottom + if (bottom_radius > 0.0) { + y = height * -0.5; + + thisrow = point; + points.push_back(Vector3(0.0, y, 0.0)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0) + uvs.push_back(Vector2(0.75, 0.75)); + point++; + + for (i = 0; i <= radial_segments; i++) { + float r = i; + r /= radial_segments; + + x = sin(r * (Math_PI * 2.0)); + z = cos(r * (Math_PI * 2.0)); + + u = 0.5 + ((x + 1.0) * 0.25); + v = 1.0 - ((z + 1.0) * 0.25); + + Vector3 p = Vector3(x * bottom_radius, y, z * bottom_radius); + points.push_back(p); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0) + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0) { + indices.push_back(thisrow); + indices.push_back(point - 2); + indices.push_back(point - 1); + }; + }; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void CylinderMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_top_radius", "radius"), &CylinderMesh::set_top_radius); + ClassDB::bind_method(D_METHOD("get_top_radius"), &CylinderMesh::get_top_radius); + ClassDB::bind_method(D_METHOD("set_bottom_radius", "radius"), &CylinderMesh::set_bottom_radius); + ClassDB::bind_method(D_METHOD("get_bottom_radius"), &CylinderMesh::get_bottom_radius); + ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderMesh::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &CylinderMesh::get_height); + + ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CylinderMesh::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &CylinderMesh::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_top_radius", "get_top_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_bottom_radius", "get_bottom_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_rings", "get_rings"); +} + +void CylinderMesh::set_top_radius(const float p_radius) { + top_radius = p_radius; + _queue_update(); +} + +float CylinderMesh::get_top_radius() const { + return top_radius; +} + +void CylinderMesh::set_bottom_radius(const float p_radius) { + bottom_radius = p_radius; + _queue_update(); +} + +float CylinderMesh::get_bottom_radius() const { + return bottom_radius; +} + +void CylinderMesh::set_height(const float p_height) { + height = p_height; + _queue_update(); +} + +float CylinderMesh::get_height() const { + return height; +} + +void CylinderMesh::set_radial_segments(const int p_segments) { + radial_segments = p_segments > 4 ? p_segments : 4; + _queue_update(); +} + +int CylinderMesh::get_radial_segments() const { + return radial_segments; +} + +void CylinderMesh::set_rings(const int p_rings) { + rings = p_rings > 0 ? p_rings : 0; + _queue_update(); +} + +int CylinderMesh::get_rings() const { + return rings; +} + +CylinderMesh::CylinderMesh() { + // defaults + top_radius = 0.5; + bottom_radius = 0.5; + height = 1.0; + radial_segments = 64; + rings = 4; +} + +/** + PlaneMesh +*/ + +void PlaneMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, z; + + Size2 start_pos = size * -0.5; + + set_aabb(Rect3(Vector3(start_pos.x, 0.0, start_pos.y), Vector3(size.x, 0.0, size.y))); + + PoolVector<Vector3> points; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + PoolVector<int> indices; + point = 0; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + /* top + bottom */ + z = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_d + 1); j++) { + x = start_pos.x; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (subdivide_w + 1.0); + v /= (subdivide_d + 1.0); + + points.push_back(Vector3(-x, 0.0, -z)); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + z += size.y / (subdivide_d + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void PlaneMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaneMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &PlaneMesh::get_size); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &PlaneMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void PlaneMesh::set_size(const Size2 &p_size) { + size = p_size; + _queue_update(); +} + +Size2 PlaneMesh::get_size() const { + return size; +} + +void PlaneMesh::set_subdivide_width(const int p_subdivide) { + subdivide_w = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int PlaneMesh::get_subdivide_width() const { + return subdivide_w; +} + +void PlaneMesh::set_subdivide_depth(const int p_subdivide) { + subdivide_d = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int PlaneMesh::get_subdivide_depth() const { + return subdivide_d; +} + +PlaneMesh::PlaneMesh() { + // defaults + size = Size2(1.0, 1.0); + subdivide_w = 0; + subdivide_d = 0; +} + +/** + PrismMesh +*/ + +void PrismMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z; + float onethird = 1.0 / 3.0; + float twothirds = 2.0 / 3.0; + + Vector3 start_pos = size * -0.5; + + // set our bounding box + set_aabb(Rect3(start_pos, size)); + + PoolVector<Vector3> points; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + PoolVector<int> indices; + point = 0; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + /* front + back */ + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_h + 1); j++) { + float scale = (y - start_pos.y) / size.y; + float scaled_size_x = size.x * scale; + float start_x = start_pos.x; + float offset_front = 0.0; + float offset_back = 0.0; + + start_x += (1.0 - scale) * size.x * left_to_right; + offset_front += (1.0 - scale) * onethird * left_to_right; + offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right); + + x = 0.0; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + u *= scale; + + /* front */ + points.push_back(Vector3(start_x + x, -y, -start_pos.z)); // double negative on the Z! + normals.push_back(Vector3(0.0, 0.0, 1.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(offset_front + u, v)); + point++; + + /* back */ + points.push_back(Vector3(start_x + scaled_size_x - x, -y, start_pos.z)); + normals.push_back(Vector3(0.0, 0.0, -1.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + offset_back + u, v)); + point++; + + if (i > 0 && j == 1) { + int i2 = i * 2; + + /* front */ + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + /* back */ + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + } else if (i > 0 && j > 0) { + int i2 = i * 2; + + /* front */ + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + /* back */ + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + x += scale * size.x / (subdivide_w + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + /* left + right */ + Vector3 normal_left, normal_right; + + normal_left = Vector3(-size.y, size.x * left_to_right, 0.0); + normal_right = Vector3(size.y, size.x * left_to_right, 0.0); + normal_left.normalize(); + normal_right.normalize(); + + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_h + 1); j++) { + float left, right; + float scale = (y - start_pos.y) / size.y; + + left = start_pos.x + (size.x * (1.0 - scale) * left_to_right); + right = left + (size.x * scale); + + z = start_pos.z; + for (i = 0; i <= (subdivide_d + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_d + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + /* right */ + points.push_back(Vector3(right, -y, -z)); + normals.push_back(normal_right); + ADD_TANGENT(0.0, 0.0, 1.0, -1.0); + uvs.push_back(Vector2(onethird + u, v)); + point++; + + /* left */ + points.push_back(Vector3(left, -y, z)); + normals.push_back(normal_left); + ADD_TANGENT(0.0, 0.0, -1.0, -1.0); + uvs.push_back(Vector2(u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + /* right */ + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + /* left */ + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + z += size.z / (subdivide_d + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + /* bottom */ + z = start_pos.z; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_d + 1); j++) { + x = start_pos.x; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_d + 1.0)); + + /* bottom */ + points.push_back(Vector3(x, start_pos.y, -z)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + /* bottom */ + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + z += size.z / (subdivide_d + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void PrismMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_left_to_right", "left_to_right"), &PrismMesh::set_left_to_right); + ClassDB::bind_method(D_METHOD("get_left_to_right"), &PrismMesh::get_left_to_right); + + ClassDB::bind_method(D_METHOD("set_size", "size"), &PrismMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &PrismMesh::get_size); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "segments"), &PrismMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PrismMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_height", "segments"), &PrismMesh::set_subdivide_height); + ClassDB::bind_method(D_METHOD("get_subdivide_height"), &PrismMesh::get_subdivide_height); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "segments"), &PrismMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_height", "get_subdivide_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,128,1"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void PrismMesh::set_left_to_right(const float p_left_to_right) { + left_to_right = p_left_to_right; + _queue_update(); +} + +float PrismMesh::get_left_to_right() const { + return left_to_right; +} + +void PrismMesh::set_size(const Vector3 &p_size) { + size = p_size; + _queue_update(); +} + +Vector3 PrismMesh::get_size() const { + return size; +} + +void PrismMesh::set_subdivide_width(const int p_divisions) { + subdivide_w = p_divisions > 0 ? p_divisions : 0; + _queue_update(); +} + +int PrismMesh::get_subdivide_width() const { + return subdivide_w; +} + +void PrismMesh::set_subdivide_height(const int p_divisions) { + subdivide_h = p_divisions > 0 ? p_divisions : 0; + _queue_update(); +} + +int PrismMesh::get_subdivide_height() const { + return subdivide_h; +} + +void PrismMesh::set_subdivide_depth(const int p_divisions) { + subdivide_d = p_divisions > 0 ? p_divisions : 0; + _queue_update(); +} + +int PrismMesh::get_subdivide_depth() const { + return subdivide_d; +} + +PrismMesh::PrismMesh() { + // defaults + left_to_right = 0.5; + size = Vector3(1.0, 1.0, 1.0); + subdivide_w = 0; + subdivide_h = 0; + subdivide_d = 0; +} + +/** + QuadMesh +*/ + +void QuadMesh::_create_mesh_array(Array &p_arr) { + PoolVector<Vector3> faces; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + + faces.resize(4); + normals.resize(4); + tangents.resize(4 * 4); + uvs.resize(4); + + for (int i = 0; i < 4; i++) { + + static const Vector3 quad_faces[4] = { + Vector3(-1, -1, 0), + Vector3(-1, 1, 0), + Vector3(1, 1, 0), + Vector3(1, -1, 0), + }; + + faces.set(i, quad_faces[i]); + normals.set(i, Vector3(0, 0, 1)); + tangents.set(i * 4 + 0, 1.0); + tangents.set(i * 4 + 1, 0.0); + tangents.set(i * 4 + 2, 0.0); + tangents.set(i * 4 + 3, 1.0); + + static const Vector2 quad_uv[4] = { + Vector2(0, 1), + Vector2(0, 0), + Vector2(1, 0), + Vector2(1, 1), + }; + + uvs.set(i, quad_uv[i]); + } + + p_arr[ARRAY_VERTEX] = faces; + p_arr[ARRAY_NORMAL] = normals; + p_arr[ARRAY_TANGENT] = tangents; + p_arr[ARRAY_TEX_UV] = uvs; +}; + +void QuadMesh::_bind_methods() { + // nothing here yet... +} + +QuadMesh::QuadMesh() { + primitive_type = PRIMITIVE_TRIANGLE_FAN; +} + +/** + SphereMesh +*/ + +void SphereMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z; + + // set our bounding box + set_aabb(Rect3(Vector3(-radius, height * -0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); + + PoolVector<Vector3> points; + PoolVector<Vector3> normals; + PoolVector<float> tangents; + PoolVector<Vector2> uvs; + PoolVector<int> indices; + point = 0; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + thisrow = 0; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + float v = j; + float w; + + v /= (rings + 1); + w = sin(Math_PI * v); + y = height * (is_hemisphere ? 1.0 : 0.5) * cos(Math_PI * v); + + for (i = 0; i <= radial_segments; i++) { + float u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + if (is_hemisphere && y < 0.0) { + points.push_back(Vector3(x * radius * w, 0.0, z * radius * w)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + } else { + Vector3 p = Vector3(x * radius * w, y, z * radius * w); + points.push_back(p); + normals.push_back(p.normalized()); + }; + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void SphereMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereMesh::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &SphereMesh::get_radius); + ClassDB::bind_method(D_METHOD("set_height", "height"), &SphereMesh::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &SphereMesh::get_height); + + ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &SphereMesh::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &SphereMesh::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &SphereMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &SphereMesh::get_rings); + + ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere); + ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.1,4096.0,0.1"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere"); +} + +void SphereMesh::set_radius(const float p_radius) { + radius = p_radius; + _queue_update(); +} + +float SphereMesh::get_radius() const { + return radius; +} + +void SphereMesh::set_height(const float p_height) { + height = p_height; + _queue_update(); +} + +float SphereMesh::get_height() const { + return height; +} + +void SphereMesh::set_radial_segments(const int p_radial_segments) { + radial_segments = p_radial_segments > 4 ? p_radial_segments : 4; + _queue_update(); +} + +int SphereMesh::get_radial_segments() const { + return radial_segments; +} + +void SphereMesh::set_rings(const int p_rings) { + rings = p_rings > 1 ? p_rings : 1; + _queue_update(); +} + +int SphereMesh::get_rings() const { + return rings; +} + +void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) { + is_hemisphere = p_is_hemisphere; + _queue_update(); +} + +bool SphereMesh::get_is_hemisphere() const { + return is_hemisphere; +} + +SphereMesh::SphereMesh() { + // defaults + radius = 0.5; + height = 1.0; + radial_segments = 64; + rings = 32; + is_hemisphere = false; +} diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h new file mode 100644 index 0000000000..91d1af2ee1 --- /dev/null +++ b/scene/resources/primitive_meshes.h @@ -0,0 +1,312 @@ +/*************************************************************************/ +/* primitive_meshes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PRIMITIVE_MESHES_H +#define PRIMITIVE_MESHES_H + +#include "scene/resources/mesh.h" + +///@TODO probably should change a few integers to unsigned integers... + +/** + @author Bastiaan Olij <mux213@gmail.com> + + Base class for all the classes in this file, handles a number of code functions that are shared among all meshes. + This class is set appart that it assumes a single surface is always generated for our mesh. +*/ +class PrimitiveMesh : public Mesh { + + GDCLASS(PrimitiveMesh, Mesh); + +private: + RID mesh; + Rect3 aabb; + + Ref<Material> material; + + bool cache_is_dirty; + void _update(); + +protected: + Mesh::PrimitiveType primitive_type; + + static void _bind_methods(); + + virtual void _create_mesh_array(Array &p_arr) = 0; + void _queue_update(); + + void set_aabb(Rect3 p_aabb); + +public: + virtual int get_surface_count() const; + virtual int surface_get_array_len(int p_idx) const; + virtual int surface_get_array_index_len(int p_idx) const; + virtual Array surface_get_arrays(int p_surface) const; + virtual uint32_t surface_get_format(int p_idx) const; + virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const; + virtual Ref<Material> surface_get_material(int p_idx) const; + virtual int get_blend_shape_count() const; + virtual StringName get_blend_shape_name(int p_index) const; + virtual Rect3 get_aabb() const; + virtual RID get_rid() const; + + void set_material(const Ref<Material> &p_material); + Ref<Material> get_material() const; + + PrimitiveMesh(); + ~PrimitiveMesh(); +}; + +/** + Mesh for a simple capsule +*/ +class CapsuleMesh : public PrimitiveMesh { + GDCLASS(CapsuleMesh, PrimitiveMesh); + +private: + float radius; + float mid_height; + int radial_segments; + int rings; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_radius(const float p_radius); + float get_radius() const; + + void set_mid_height(const float p_mid_height); + float get_mid_height() const; + + void set_radial_segments(const int p_segments); + int get_radial_segments() const; + + void set_rings(const int p_rings); + int get_rings() const; + + CapsuleMesh(); +}; + +/** + Similar to test cube but with subdivision support and different texture coordinates +*/ +class CubeMesh : public PrimitiveMesh { + + GDCLASS(CubeMesh, PrimitiveMesh); + +private: + Vector3 size; + int subdivide_w; + int subdivide_h; + int subdivide_d; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_size(const Vector3 &p_size); + Vector3 get_size() const; + + void set_subdivide_width(const int p_divisions); + int get_subdivide_width() const; + + void set_subdivide_height(const int p_divisions); + int get_subdivide_height() const; + + void set_subdivide_depth(const int p_divisions); + int get_subdivide_depth() const; + + CubeMesh(); +}; + +/** + A cylinder +*/ + +class CylinderMesh : public PrimitiveMesh { + + GDCLASS(CylinderMesh, PrimitiveMesh); + +private: + float top_radius; + float bottom_radius; + float height; + int radial_segments; + int rings; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_top_radius(const float p_radius); + float get_top_radius() const; + + void set_bottom_radius(const float p_radius); + float get_bottom_radius() const; + + void set_height(const float p_height); + float get_height() const; + + void set_radial_segments(const int p_segments); + int get_radial_segments() const; + + void set_rings(const int p_rings); + int get_rings() const; + + CylinderMesh(); +}; + +/** + Similar to quadmesh but with tesselation support +*/ +class PlaneMesh : public PrimitiveMesh { + + GDCLASS(PlaneMesh, PrimitiveMesh); + +private: + Size2 size; + int subdivide_w; + int subdivide_d; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_size(const Size2 &p_size); + Size2 get_size() const; + + void set_subdivide_width(const int p_divisions); + int get_subdivide_width() const; + + void set_subdivide_depth(const int p_divisions); + int get_subdivide_depth() const; + + PlaneMesh(); +}; + +/** + A prism shapen, handy for ramps, triangles, etc. +*/ +class PrismMesh : public PrimitiveMesh { + + GDCLASS(PrismMesh, PrimitiveMesh); + +private: + float left_to_right; + Vector3 size; + int subdivide_w; + int subdivide_h; + int subdivide_d; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_left_to_right(const float p_left_to_right); + float get_left_to_right() const; + + void set_size(const Vector3 &p_size); + Vector3 get_size() const; + + void set_subdivide_width(const int p_divisions); + int get_subdivide_width() const; + + void set_subdivide_height(const int p_divisions); + int get_subdivide_height() const; + + void set_subdivide_depth(const int p_divisions); + int get_subdivide_depth() const; + + PrismMesh(); +}; + +/** + Our original quadmesh... +*/ + +class QuadMesh : public PrimitiveMesh { + + GDCLASS(QuadMesh, PrimitiveMesh) + +private: + // nothing? really? Maybe add size some day atleast... :) + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + QuadMesh(); +}; + +/** + A sphere.. +*/ +class SphereMesh : public PrimitiveMesh { + + GDCLASS(SphereMesh, PrimitiveMesh); + +private: + float radius; + float height; + int radial_segments; + int rings; + bool is_hemisphere; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_radius(const float p_radius); + float get_radius() const; + + void set_height(const float p_height); + float get_height() const; + + void set_radial_segments(const int p_radial_segments); + int get_radial_segments() const; + + void set_rings(const int p_rings); + int get_rings() const; + + void set_is_hemisphere(const bool p_is_hemisphere); + bool get_is_hemisphere() const; + + SphereMesh(); +}; + +#endif diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h index b9ec294eb8..36578ce1f7 100644 --- a/scene/resources/shader_graph.h +++ b/scene/resources/shader_graph.h @@ -37,7 +37,7 @@ class ShaderGraph : public Shader { GDCLASS( ShaderGraph, Shader ); - RES_BASE_EXTENSION("sgp"); + RES_BASE_EXTENSION("vshader"); public: diff --git a/scene/resources/shape.h b/scene/resources/shape.h index ea3ba9ab0a..c15638aeed 100644 --- a/scene/resources/shape.h +++ b/scene/resources/shape.h @@ -37,7 +37,7 @@ class Shape : public Resource { GDCLASS(Shape, Resource); OBJ_SAVE_TYPE(Shape); - RES_BASE_EXTENSION("shp"); + RES_BASE_EXTENSION("shape"); RID shape; Ref<ArrayMesh> debug_mesh_cache; diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index bbb2444bd7..97edc68bff 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -39,7 +39,7 @@ class StyleBox : public Resource { GDCLASS(StyleBox, Resource); - RES_BASE_EXTENSION("sbx"); + RES_BASE_EXTENSION("stylebox"); OBJ_SAVE_TYPE(StyleBox); float margin[4]; diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 9ee9588d2b..3a0f466b4f 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -226,7 +226,7 @@ VARIANT_ENUM_CAST(ImageTexture::Storage); class AtlasTexture : public Texture { GDCLASS(AtlasTexture, Texture); - RES_BASE_EXTENSION("atex"); + RES_BASE_EXTENSION("atlastex"); protected: Ref<Texture> atlas; @@ -265,7 +265,7 @@ public: class LargeTexture : public Texture { GDCLASS(LargeTexture, Texture); - RES_BASE_EXTENSION("ltex"); + RES_BASE_EXTENSION("largetex"); protected: struct Piece { @@ -312,7 +312,7 @@ public: class CubeMap : public Resource { GDCLASS(CubeMap, Resource); - RES_BASE_EXTENSION("cbm"); + RES_BASE_EXTENSION("cubemap"); public: enum Storage { @@ -393,7 +393,7 @@ VARIANT_ENUM_CAST(CubeMap::Storage); class CurveTexture : public Texture { GDCLASS(CurveTexture, Texture); - RES_BASE_EXTENSION("cvtex"); + RES_BASE_EXTENSION("curvetex"); private: RID texture; diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 1a5cfcf4b2..1dfea7f421 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -43,7 +43,7 @@ class Theme : public Resource { GDCLASS(Theme, Resource); - RES_BASE_EXTENSION("thm"); + RES_BASE_EXTENSION("theme"); static Ref<Theme> default_theme; diff --git a/scene/resources/world.h b/scene/resources/world.h index 96857a577a..5291b3974b 100644 --- a/scene/resources/world.h +++ b/scene/resources/world.h @@ -41,7 +41,7 @@ class VisibilityNotifier; class World : public Resource { GDCLASS(World, Resource); - RES_BASE_EXTENSION("wrd"); + RES_BASE_EXTENSION("world"); private: RID space; diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp index dc0b2fc84f..d673088304 100644 --- a/servers/physics/collision_object_sw.cpp +++ b/servers/physics/collision_object_sw.cpp @@ -208,7 +208,7 @@ CollisionObjectSW::CollisionObjectSW(Type p_type) { type = p_type; space = NULL; instance_id = 0; - layer_mask = 1; + collision_layer = 1; collision_mask = 1; ray_pickable = true; } diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index 0767f88ba1..15082a0551 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -53,7 +53,7 @@ private: Type type; RID self; ObjectID instance_id; - uint32_t layer_mask; + uint32_t collision_layer; uint32_t collision_mask; struct Shape { @@ -134,14 +134,14 @@ public: _FORCE_INLINE_ void set_shape_as_trigger(int p_idx, bool p_enable) { shapes[p_idx].trigger = p_enable; } _FORCE_INLINE_ bool is_shape_set_as_trigger(int p_idx) const { return shapes[p_idx].trigger; } - _FORCE_INLINE_ void set_layer_mask(uint32_t p_mask) { layer_mask = p_mask; } - _FORCE_INLINE_ uint32_t get_layer_mask() const { return layer_mask; } + _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; } + _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; } _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } _FORCE_INLINE_ bool test_collision_mask(CollisionObjectSW *p_other) const { - return layer_mask & p_other->collision_mask || p_other->layer_mask & collision_mask; + return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask; } void remove_shape(ShapeSW *p_shape); diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 727ff38718..455863da91 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -389,12 +389,12 @@ Transform PhysicsServerSW::area_get_transform(RID p_area) const { return area->get_transform(); }; -void PhysicsServerSW::area_set_layer_mask(RID p_area, uint32_t p_mask) { +void PhysicsServerSW::area_set_collision_layer(RID p_area, uint32_t p_layer) { AreaSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); - area->set_layer_mask(p_mask); + area->set_collision_layer(p_layer); } void PhysicsServerSW::area_set_collision_mask(RID p_area, uint32_t p_mask) { @@ -609,21 +609,21 @@ bool PhysicsServerSW::body_is_continuous_collision_detection_enabled(RID p_body) return body->is_continuous_collision_detection_enabled(); } -void PhysicsServerSW::body_set_layer_mask(RID p_body, uint32_t p_mask) { +void PhysicsServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) { BodySW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_layer_mask(p_mask); + body->set_collision_layer(p_layer); body->wakeup(); } -uint32_t PhysicsServerSW::body_get_layer_mask(RID p_body, uint32_t p_mask) const { +uint32_t PhysicsServerSW::body_get_collision_layer(RID p_body) const { const BodySW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body, 0); - return body->get_layer_mask(); + return body->get_collision_layer(); } void PhysicsServerSW::body_set_collision_mask(RID p_body, uint32_t p_mask) { @@ -635,7 +635,7 @@ void PhysicsServerSW::body_set_collision_mask(RID p_body, uint32_t p_mask) { body->wakeup(); } -uint32_t PhysicsServerSW::body_get_collision_mask(RID p_body, uint32_t p_mask) const { +uint32_t PhysicsServerSW::body_get_collision_mask(RID p_body) const { const BodySW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body, 0); @@ -665,7 +665,7 @@ void PhysicsServerSW::body_set_user_flags(RID p_body, uint32_t p_flags) { ERR_FAIL_COND(!body); }; -uint32_t PhysicsServerSW::body_get_user_flags(RID p_body, uint32_t p_flags) const { +uint32_t PhysicsServerSW::body_get_user_flags(RID p_body) const { BodySW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body, 0); diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 44f9aff662..559e9aeb51 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -130,7 +130,7 @@ public: virtual bool area_is_ray_pickable(RID p_area) const; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask); - virtual void area_set_layer_mask(RID p_area, uint32_t p_mask); + virtual void area_set_collision_layer(RID p_area, uint32_t p_layer); virtual void area_set_monitorable(RID p_area, bool p_monitorable); @@ -168,14 +168,14 @@ public: virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable); virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const; - virtual void body_set_layer_mask(RID p_body, uint32_t p_mask); - virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const; + virtual void body_set_collision_layer(RID p_body, uint32_t p_layer); + virtual uint32_t body_get_collision_layer(RID p_body) const; virtual void body_set_collision_mask(RID p_body, uint32_t p_mask); - virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const; + virtual uint32_t body_get_collision_mask(RID p_body) const; virtual void body_set_user_flags(RID p_body, uint32_t p_flags); - virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const; + virtual uint32_t body_get_user_flags(RID p_body) const; virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value); virtual real_t body_get_param(RID p_body, BodyParameter p_param) const; diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index 16562dce6b..67ac21e4f9 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -32,12 +32,12 @@ #include "global_config.h" #include "physics_server_sw.h" -_FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_layer_mask, uint32_t p_type_mask) { +_FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_collision_layer, uint32_t p_type_mask) { if (p_object->get_type() == CollisionObjectSW::TYPE_AREA) return p_type_mask & PhysicsDirectSpaceState::TYPE_MASK_AREA; - if ((p_object->get_layer_mask() & p_layer_mask) == 0) + if ((p_object->get_collision_layer() & p_collision_layer) == 0) return false; BodySW *body = static_cast<BodySW *>(p_object); @@ -45,7 +45,7 @@ _FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, return (1 << body->get_mode()) & p_type_mask; } -bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask, bool p_pick_ray) { +bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, bool p_pick_ray) { ERR_FAIL_COND_V(space->locked, false); @@ -67,7 +67,7 @@ bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3 &p_from, const Vecto for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; if (p_pick_ray && !(static_cast<CollisionObjectSW *>(space->intersection_query_results[i])->is_ray_pickable())) @@ -123,7 +123,7 @@ bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3 &p_from, const Vecto return true; } -int PhysicsDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +int PhysicsDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { if (p_result_max <= 0) return 0; @@ -144,7 +144,7 @@ int PhysicsDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transfo if (cc >= p_result_max) break; - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; //area can't be picked by ray (default) @@ -174,7 +174,7 @@ int PhysicsDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transfo return cc; } -bool PhysicsDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask, ShapeRestInfo *r_info) { +bool PhysicsDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, ShapeRestInfo *r_info) { ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape, false); @@ -204,7 +204,7 @@ bool PhysicsDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; if (p_exclude.has(space->intersection_query_results[i]->get_self())) @@ -295,7 +295,7 @@ bool PhysicsDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform return true; } -bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { if (p_result_max <= 0) return 0; @@ -325,7 +325,7 @@ bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform &p_sh for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; const CollisionObjectSW *col_obj = space->intersection_query_results[i]; @@ -374,7 +374,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, rd->best_object = rd->object; rd->best_shape = rd->shape; } -bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape, 0); @@ -391,7 +391,7 @@ bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_ for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; const CollisionObjectSW *col_obj = space->intersection_query_results[i]; diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index 20a2a06862..782bacbd65 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -47,11 +47,11 @@ class PhysicsDirectSpaceStateSW : public PhysicsDirectSpaceState { public: SpaceSW *space; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_ray = false); - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, ShapeRestInfo *r_info = NULL); - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_ray = false); + virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, ShapeRestInfo *r_info = NULL); + virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); PhysicsDirectSpaceStateSW(); }; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index b6c1d145df..0163a18850 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -214,6 +214,6 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) { space = NULL; instance_id = 0; collision_mask = 1; - layer_mask = 1; + collision_layer = 1; pickable = true; } diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 8ca6c92dbc..f2059e8618 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -67,7 +67,7 @@ private: Transform2D transform; Transform2D inv_transform; uint32_t collision_mask; - uint32_t layer_mask; + uint32_t collision_layer; bool _static; void _update_shapes(); @@ -122,8 +122,8 @@ public: void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } - void set_layer_mask(uint32_t p_mask) { layer_mask = p_mask; } - _FORCE_INLINE_ uint32_t get_layer_mask() const { return layer_mask; } + void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; } + _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; } void remove_shape(Shape2DSW *p_shape); void remove_shape(int p_index); @@ -137,7 +137,7 @@ public: _FORCE_INLINE_ bool test_collision_mask(CollisionObject2DSW *p_other) const { - return layer_mask & p_other->collision_mask || p_other->layer_mask & collision_mask; + return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask; } virtual ~CollisionObject2DSW() {} diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 03e0f8a7fd..9a31fa49b0 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -476,12 +476,12 @@ void Physics2DServerSW::area_set_collision_mask(RID p_area, uint32_t p_mask) { area->set_collision_mask(p_mask); } -void Physics2DServerSW::area_set_layer_mask(RID p_area, uint32_t p_mask) { +void Physics2DServerSW::area_set_collision_layer(RID p_area, uint32_t p_layer) { Area2DSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); - area->set_layer_mask(p_mask); + area->set_collision_layer(p_layer); } void Physics2DServerSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { @@ -691,19 +691,19 @@ uint32_t Physics2DServerSW::body_get_object_instance_ID(RID p_body) const { return body->get_instance_id(); }; -void Physics2DServerSW::body_set_layer_mask(RID p_body, uint32_t p_flags) { +void Physics2DServerSW::body_set_collision_layer(RID p_body, uint32_t p_flags) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_layer_mask(p_flags); + body->set_collision_layer(p_flags); }; -uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body) const { +uint32_t Physics2DServerSW::body_get_collision_layer(RID p_body) const { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body, 0); - return body->get_layer_mask(); + return body->get_collision_layer(); }; void Physics2DServerSW::body_set_collision_mask(RID p_body, uint32_t p_flags) { diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index a8d85932ff..be67e3157d 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -136,7 +136,7 @@ public: virtual Transform2D area_get_transform(RID p_area) const; virtual void area_set_monitorable(RID p_area, bool p_monitorable); virtual void area_set_collision_mask(RID p_area, uint32_t p_mask); - virtual void area_set_layer_mask(RID p_area, uint32_t p_mask); + virtual void area_set_collision_layer(RID p_area, uint32_t p_layer); virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method); virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method); @@ -176,8 +176,8 @@ public: virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode); virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const; - virtual void body_set_layer_mask(RID p_body, uint32_t p_mask); - virtual uint32_t body_get_layer_mask(RID p_body) const; + virtual void body_set_collision_layer(RID p_body, uint32_t p_layer); + virtual uint32_t body_get_collision_layer(RID p_body) const; virtual void body_set_collision_mask(RID p_body, uint32_t p_mask); virtual uint32_t body_get_collision_mask(RID p_) const; diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index ddcf31182a..1026d84fd9 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -162,7 +162,7 @@ public: FUNC1RC(Transform2D, area_get_transform, RID); FUNC2(area_set_collision_mask, RID, uint32_t); - FUNC2(area_set_layer_mask, RID, uint32_t); + FUNC2(area_set_collision_layer, RID, uint32_t); FUNC2(area_set_monitorable, RID, bool); FUNC2(area_set_pickable, RID, bool); @@ -203,8 +203,8 @@ public: FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode); FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID); - FUNC2(body_set_layer_mask, RID, uint32_t); - FUNC1RC(uint32_t, body_get_layer_mask, RID); + FUNC2(body_set_collision_layer, RID, uint32_t); + FUNC1RC(uint32_t, body_get_collision_layer, RID); FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 78b1e84734..fd94fc01cd 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -31,9 +31,9 @@ #include "collision_solver_2d_sw.h" #include "physics_2d_server_sw.h" -_FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_object, uint32_t p_layer_mask, uint32_t p_type_mask) { +_FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_object, uint32_t p_collision_layer, uint32_t p_type_mask) { - if ((p_object->get_layer_mask() & p_layer_mask) == 0) + if ((p_object->get_collision_layer() & p_collision_layer) == 0) return false; if (p_object->get_type() == CollisionObject2DSW::TYPE_AREA) @@ -44,7 +44,7 @@ _FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_objec return (1 << body->get_mode()) & p_type_mask; } -int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask, bool p_pick_point) { +int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, bool p_pick_point) { if (p_result_max <= 0) return 0; @@ -59,7 +59,7 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; if (p_exclude.has(space->intersection_query_results[i]->get_self())) @@ -95,7 +95,7 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe return cc; } -bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { ERR_FAIL_COND_V(space->locked, false); @@ -117,7 +117,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vec for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; if (p_exclude.has(space->intersection_query_results[i]->get_self())) @@ -175,7 +175,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vec return true; } -int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { if (p_result_max <= 0) return 0; @@ -192,7 +192,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Trans for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; if (p_exclude.has(space->intersection_query_results[i]->get_self())) @@ -217,7 +217,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Trans return cc; } -bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape, false); @@ -238,7 +238,7 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; if (p_exclude.has(space->intersection_query_results[i]->get_self())) @@ -330,7 +330,7 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor return true; } -bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { if (p_result_max <= 0) return 0; @@ -361,7 +361,7 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D & for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; @@ -428,7 +428,7 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, rd->best_shape = rd->shape; } -bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask) { +bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) { Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape, 0); @@ -446,7 +446,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh for (int i = 0; i < amount; i++) { - if (!_match_object_type_query(space->intersection_query_results[i], p_layer_mask, p_object_type_mask)) + if (!_match_object_type_query(space->intersection_query_results[i], p_collision_layer, p_object_type_mask)) continue; const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 46435b1c66..64841c4328 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -47,12 +47,12 @@ class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState { public: Space2DSW *space; - virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_point = false); - virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); - virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); - virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); - virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_point = false); + virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); + virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION); Physics2DDirectSpaceStateSW(); }; diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index 43295073aa..8ffa82214c 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -154,13 +154,13 @@ float Physics2DShapeQueryParameters::get_margin() const { return margin; } -void Physics2DShapeQueryParameters::set_layer_mask(int p_layer_mask) { +void Physics2DShapeQueryParameters::set_collision_layer(int p_collision_layer) { - layer_mask = p_layer_mask; + collision_layer = p_collision_layer; } -int Physics2DShapeQueryParameters::get_layer_mask() const { +int Physics2DShapeQueryParameters::get_collision_layer() const { - return layer_mask; + return collision_layer; } void Physics2DShapeQueryParameters::set_object_type_mask(int p_object_type_mask) { @@ -204,8 +204,8 @@ void Physics2DShapeQueryParameters::_bind_methods() { ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Physics2DShapeQueryParameters::set_margin); ClassDB::bind_method(D_METHOD("get_margin"), &Physics2DShapeQueryParameters::get_margin); - ClassDB::bind_method(D_METHOD("set_layer_mask", "layer_mask"), &Physics2DShapeQueryParameters::set_layer_mask); - ClassDB::bind_method(D_METHOD("get_layer_mask"), &Physics2DShapeQueryParameters::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Physics2DShapeQueryParameters::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &Physics2DShapeQueryParameters::get_collision_layer); ClassDB::bind_method(D_METHOD("set_object_type_mask", "object_type_mask"), &Physics2DShapeQueryParameters::set_object_type_mask); ClassDB::bind_method(D_METHOD("get_object_type_mask"), &Physics2DShapeQueryParameters::get_object_type_mask); @@ -217,7 +217,7 @@ void Physics2DShapeQueryParameters::_bind_methods() { Physics2DShapeQueryParameters::Physics2DShapeQueryParameters() { margin = 0; - layer_mask = 0x7FFFFFFF; + collision_layer = 0x7FFFFFFF; object_type_mask = Physics2DDirectSpaceState::TYPE_MASK_COLLISION; } @@ -249,7 +249,7 @@ Array Physics2DDirectSpaceState::_intersect_shape(const Ref<Physics2DShapeQueryP Vector<ShapeResult> sr; sr.resize(p_max_results); - int rc = intersect_shape(psq->shape, psq->transform, psq->motion, psq->margin, sr.ptr(), sr.size(), psq->exclude, psq->layer_mask, psq->object_type_mask); + int rc = intersect_shape(psq->shape, psq->transform, psq->motion, psq->margin, sr.ptr(), sr.size(), psq->exclude, psq->collision_layer, psq->object_type_mask); Array ret; ret.resize(rc); for (int i = 0; i < rc; i++) { @@ -269,7 +269,7 @@ Array Physics2DDirectSpaceState::_intersect_shape(const Ref<Physics2DShapeQueryP Array Physics2DDirectSpaceState::_cast_motion(const Ref<Physics2DShapeQueryParameters> &psq) { float closest_safe, closest_unsafe; - bool res = cast_motion(psq->shape, psq->transform, psq->motion, psq->margin, closest_safe, closest_unsafe, psq->exclude, psq->layer_mask, psq->object_type_mask); + bool res = cast_motion(psq->shape, psq->transform, psq->motion, psq->margin, closest_safe, closest_unsafe, psq->exclude, psq->collision_layer, psq->object_type_mask); if (!res) return Array(); Array ret; @@ -312,7 +312,7 @@ Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryPar Vector<Vector2> ret; ret.resize(p_max_results * 2); int rc = 0; - bool res = collide_shape(psq->shape, psq->transform, psq->motion, psq->margin, ret.ptr(), p_max_results, rc, psq->exclude, psq->layer_mask, psq->object_type_mask); + bool res = collide_shape(psq->shape, psq->transform, psq->motion, psq->margin, ret.ptr(), p_max_results, rc, psq->exclude, psq->collision_layer, psq->object_type_mask); if (!res) return Array(); Array r; @@ -325,7 +325,7 @@ Dictionary Physics2DDirectSpaceState::_get_rest_info(const Ref<Physics2DShapeQue ShapeRestInfo sri; - bool res = rest_info(psq->shape, psq->transform, psq->motion, psq->margin, &sri, psq->exclude, psq->layer_mask, psq->object_type_mask); + bool res = rest_info(psq->shape, psq->transform, psq->motion, psq->margin, &sri, psq->exclude, psq->collision_layer, psq->object_type_mask); Dictionary r; if (!res) return r; @@ -346,8 +346,8 @@ Physics2DDirectSpaceState::Physics2DDirectSpaceState() { void Physics2DDirectSpaceState::_bind_methods() { - ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "layer_mask", "type_mask"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(TYPE_MASK_COLLISION)); - ClassDB::bind_method(D_METHOD("intersect_ray:Dictionary", "from", "to", "exclude", "layer_mask", "type_mask"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(TYPE_MASK_COLLISION)); + ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "type_mask"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(TYPE_MASK_COLLISION)); + ClassDB::bind_method(D_METHOD("intersect_ray:Dictionary", "from", "to", "exclude", "collision_layer", "type_mask"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(TYPE_MASK_COLLISION)); ClassDB::bind_method(D_METHOD("intersect_shape", "shape:Physics2DShapeQueryParameters", "max_results"), &Physics2DDirectSpaceState::_intersect_shape, DEFVAL(32)); ClassDB::bind_method(D_METHOD("cast_motion", "shape:Physics2DShapeQueryParameters"), &Physics2DDirectSpaceState::_cast_motion); ClassDB::bind_method(D_METHOD("collide_shape", "shape:Physics2DShapeQueryParameters", "max_results"), &Physics2DDirectSpaceState::_collide_shape, DEFVAL(32)); @@ -504,7 +504,7 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("area_remove_shape", "area", "shape_idx"), &Physics2DServer::area_remove_shape); ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &Physics2DServer::area_clear_shapes); - ClassDB::bind_method(D_METHOD("area_set_layer_mask", "area", "mask"), &Physics2DServer::area_set_layer_mask); + ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &Physics2DServer::area_set_collision_layer); ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &Physics2DServer::area_set_collision_mask); ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &Physics2DServer::area_set_param); @@ -548,8 +548,8 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &Physics2DServer::body_set_continuous_collision_detection_mode); ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &Physics2DServer::body_get_continuous_collision_detection_mode); - ClassDB::bind_method(D_METHOD("body_set_layer_mask", "body", "mask"), &Physics2DServer::body_set_layer_mask); - ClassDB::bind_method(D_METHOD("body_get_layer_mask", "body"), &Physics2DServer::body_get_layer_mask); + ClassDB::bind_method(D_METHOD("body_set_collision_layer", "body", "layer"), &Physics2DServer::body_set_collision_layer); + ClassDB::bind_method(D_METHOD("body_get_collision_layer", "body"), &Physics2DServer::body_get_collision_layer); ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &Physics2DServer::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &Physics2DServer::body_get_collision_mask); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 4ea037e1b4..80113dd7d6 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -97,7 +97,7 @@ class Physics2DShapeQueryParameters : public Reference { Vector2 motion; float margin; Set<RID> exclude; - uint32_t layer_mask; + uint32_t collision_layer; uint32_t object_type_mask; protected: @@ -117,8 +117,8 @@ public: void set_margin(float p_margin); float get_margin() const; - void set_layer_mask(int p_layer_mask); - int get_layer_mask() const; + void set_collision_layer(int p_collision_layer); + int get_collision_layer() const; void set_object_type_mask(int p_object_type_mask); int get_object_type_mask() const; @@ -166,7 +166,7 @@ public: Variant metadata; }; - virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; struct ShapeResult { @@ -177,13 +177,13 @@ public: Variant metadata; }; - virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_point = false) = 0; + virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_point = false) = 0; - virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; - virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; struct ShapeRestInfo { @@ -196,7 +196,7 @@ public: Variant metadata; }; - virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; Physics2DDirectSpaceState(); }; @@ -342,7 +342,7 @@ public: virtual Transform2D area_get_transform(RID p_area) const = 0; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0; - virtual void area_set_layer_mask(RID p_area, uint32_t p_mask) = 0; + virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0; virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0; virtual void area_set_pickable(RID p_area, bool p_pickable) = 0; @@ -398,8 +398,8 @@ public: virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) = 0; virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const = 0; - virtual void body_set_layer_mask(RID p_body, uint32_t p_mask) = 0; - virtual uint32_t body_get_layer_mask(RID p_body) const = 0; + virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) = 0; + virtual uint32_t body_get_collision_layer(RID p_body) const = 0; virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; virtual uint32_t body_get_collision_mask(RID p_body) const = 0; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index b19dfc1c68..6b6db1ff8c 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -151,13 +151,13 @@ float PhysicsShapeQueryParameters::get_margin() const { return margin; } -void PhysicsShapeQueryParameters::set_layer_mask(int p_layer_mask) { +void PhysicsShapeQueryParameters::set_collision_layer(int p_collision_layer) { - layer_mask = p_layer_mask; + collision_layer = p_collision_layer; } -int PhysicsShapeQueryParameters::get_layer_mask() const { +int PhysicsShapeQueryParameters::get_collision_layer() const { - return layer_mask; + return collision_layer; } void PhysicsShapeQueryParameters::set_object_type_mask(int p_object_type_mask) { @@ -198,8 +198,8 @@ void PhysicsShapeQueryParameters::_bind_methods() { ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsShapeQueryParameters::set_margin); ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsShapeQueryParameters::get_margin); - ClassDB::bind_method(D_METHOD("set_layer_mask", "layer_mask"), &PhysicsShapeQueryParameters::set_layer_mask); - ClassDB::bind_method(D_METHOD("get_layer_mask"), &PhysicsShapeQueryParameters::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &PhysicsShapeQueryParameters::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsShapeQueryParameters::get_collision_layer); ClassDB::bind_method(D_METHOD("set_object_type_mask", "object_type_mask"), &PhysicsShapeQueryParameters::set_object_type_mask); ClassDB::bind_method(D_METHOD("get_object_type_mask"), &PhysicsShapeQueryParameters::get_object_type_mask); @@ -211,7 +211,7 @@ void PhysicsShapeQueryParameters::_bind_methods() { PhysicsShapeQueryParameters::PhysicsShapeQueryParameters() { margin = 0; - layer_mask = 0x7FFFFFFF; + collision_layer = 0x7FFFFFFF; object_type_mask = PhysicsDirectSpaceState::TYPE_MASK_COLLISION; } @@ -274,7 +274,7 @@ Array PhysicsDirectSpaceState::_intersect_shape(const Ref<PhysicsShapeQueryParam Vector<ShapeResult> sr; sr.resize(p_max_results); - int rc = intersect_shape(psq->shape, psq->transform, psq->margin, sr.ptr(), sr.size(), psq->exclude, psq->layer_mask, psq->object_type_mask); + int rc = intersect_shape(psq->shape, psq->transform, psq->margin, sr.ptr(), sr.size(), psq->exclude, psq->collision_layer, psq->object_type_mask); Array ret; ret.resize(rc); for (int i = 0; i < rc; i++) { @@ -293,7 +293,7 @@ Array PhysicsDirectSpaceState::_intersect_shape(const Ref<PhysicsShapeQueryParam Array PhysicsDirectSpaceState::_cast_motion(const Ref<PhysicsShapeQueryParameters> &psq, const Vector3 &p_motion) { float closest_safe, closest_unsafe; - bool res = cast_motion(psq->shape, psq->transform, p_motion, psq->margin, closest_safe, closest_unsafe, psq->exclude, psq->layer_mask, psq->object_type_mask); + bool res = cast_motion(psq->shape, psq->transform, p_motion, psq->margin, closest_safe, closest_unsafe, psq->exclude, psq->collision_layer, psq->object_type_mask); if (!res) return Array(); Array ret; @@ -307,7 +307,7 @@ Array PhysicsDirectSpaceState::_collide_shape(const Ref<PhysicsShapeQueryParamet Vector<Vector3> ret; ret.resize(p_max_results * 2); int rc = 0; - bool res = collide_shape(psq->shape, psq->transform, psq->margin, ret.ptr(), p_max_results, rc, psq->exclude, psq->layer_mask, psq->object_type_mask); + bool res = collide_shape(psq->shape, psq->transform, psq->margin, ret.ptr(), p_max_results, rc, psq->exclude, psq->collision_layer, psq->object_type_mask); if (!res) return Array(); Array r; @@ -320,7 +320,7 @@ Dictionary PhysicsDirectSpaceState::_get_rest_info(const Ref<PhysicsShapeQueryPa ShapeRestInfo sri; - bool res = rest_info(psq->shape, psq->transform, psq->margin, &sri, psq->exclude, psq->layer_mask, psq->object_type_mask); + bool res = rest_info(psq->shape, psq->transform, psq->margin, &sri, psq->exclude, psq->collision_layer, psq->object_type_mask); Dictionary r; if (!res) return r; @@ -343,7 +343,7 @@ void PhysicsDirectSpaceState::_bind_methods() { //ClassDB::bind_method(D_METHOD("intersect_ray","from","to","exclude","umask"),&PhysicsDirectSpaceState::_intersect_ray,DEFVAL(Array()),DEFVAL(0)); //ClassDB::bind_method(D_METHOD("intersect_shape:PhysicsShapeQueryResult","shape","xform","result_max","exclude","umask"),&PhysicsDirectSpaceState::_intersect_shape,DEFVAL(Array()),DEFVAL(0)); - ClassDB::bind_method(D_METHOD("intersect_ray:Dictionary", "from", "to", "exclude", "layer_mask", "type_mask"), &PhysicsDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(TYPE_MASK_COLLISION)); + ClassDB::bind_method(D_METHOD("intersect_ray:Dictionary", "from", "to", "exclude", "collision_layer", "type_mask"), &PhysicsDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(TYPE_MASK_COLLISION)); ClassDB::bind_method(D_METHOD("intersect_shape", "shape:PhysicsShapeQueryParameters", "max_results"), &PhysicsDirectSpaceState::_intersect_shape, DEFVAL(32)); ClassDB::bind_method(D_METHOD("cast_motion", "shape:PhysicsShapeQueryParameters", "motion"), &PhysicsDirectSpaceState::_cast_motion); ClassDB::bind_method(D_METHOD("collide_shape", "shape:PhysicsShapeQueryParameters", "max_results"), &PhysicsDirectSpaceState::_collide_shape, DEFVAL(32)); @@ -425,7 +425,7 @@ void PhysicsServer::_bind_methods() { ClassDB::bind_method(D_METHOD("area_remove_shape", "area", "shape_idx"), &PhysicsServer::area_remove_shape); ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer::area_clear_shapes); - ClassDB::bind_method(D_METHOD("area_set_layer_mask", "area", "mask"), &PhysicsServer::area_set_layer_mask); + ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer::area_set_collision_layer); ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer::area_set_collision_mask); ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer::area_set_param); @@ -450,8 +450,8 @@ void PhysicsServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_mode", "body", "mode"), &PhysicsServer::body_set_mode); ClassDB::bind_method(D_METHOD("body_get_mode", "body"), &PhysicsServer::body_get_mode); - ClassDB::bind_method(D_METHOD("body_set_layer_mask", "body", "mask"), &PhysicsServer::body_set_layer_mask); - ClassDB::bind_method(D_METHOD("body_get_layer_mask", "body"), &PhysicsServer::body_get_layer_mask); + ClassDB::bind_method(D_METHOD("body_set_collision_layer", "body", "layer"), &PhysicsServer::body_set_collision_layer); + ClassDB::bind_method(D_METHOD("body_get_collision_layer", "body"), &PhysicsServer::body_get_collision_layer); ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer::body_get_collision_mask); diff --git a/servers/physics_server.h b/servers/physics_server.h index 95f725b774..3d1a2aec7a 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -100,7 +100,7 @@ class PhysicsShapeQueryParameters : public Reference { Transform transform; float margin; Set<RID> exclude; - uint32_t layer_mask; + uint32_t collision_layer; uint32_t object_type_mask; protected: @@ -117,8 +117,8 @@ public: void set_margin(float p_margin); float get_margin() const; - void set_layer_mask(int p_layer_mask); - int get_layer_mask() const; + void set_collision_layer(int p_collision_layer); + int get_collision_layer() const; void set_object_type_mask(int p_object_type_mask); int get_object_type_mask() const; @@ -166,7 +166,7 @@ public: int shape; }; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_ray = false) = 0; + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_ray = false) = 0; struct ShapeResult { @@ -176,7 +176,7 @@ public: int shape; }; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; struct ShapeRestInfo { @@ -188,11 +188,11 @@ public: Vector3 linear_velocity; //velocity at contact point }; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, ShapeRestInfo *r_info = NULL) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, ShapeRestInfo *r_info = NULL) = 0; - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_layer_mask = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; + virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION) = 0; PhysicsDirectSpaceState(); }; @@ -332,7 +332,7 @@ public: virtual Transform area_get_transform(RID p_area) const = 0; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0; - virtual void area_set_layer_mask(RID p_area, uint32_t p_mask) = 0; + virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0; virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0; @@ -382,14 +382,14 @@ public: virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) = 0; virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const = 0; - virtual void body_set_layer_mask(RID p_body, uint32_t p_mask) = 0; - virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const = 0; + virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) = 0; + virtual uint32_t body_get_collision_layer(RID p_body) const = 0; virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; - virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const = 0; + virtual uint32_t body_get_collision_mask(RID p_body) const = 0; virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0; - virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const = 0; + virtual uint32_t body_get_user_flags(RID p_body) const = 0; // common body variables enum BodyParameter { diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index eb06c64c40..35b9d0284d 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -64,7 +64,7 @@ public: virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_treshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) = 0; virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0; - virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_accel, float p_fade, float p_depth_tolerance, bool p_smooth, bool p_roughness) = 0; + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0; virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur) = 0; virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; @@ -131,7 +131,7 @@ public: virtual RID light_instance_create(RID p_light) = 0; virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0) = 0; virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual RID reflection_atlas_create() = 0; @@ -546,6 +546,7 @@ public: float shadow_gradient_length; VS::CanvasLightShadowFilter shadow_filter; Color shadow_color; + float shadow_smooth; void *texture_cache; // implementation dependent Rect2 rect_cache; @@ -584,6 +585,7 @@ public: shadow_buffer_size = 256; shadow_gradient_length = 0; shadow_filter = VS::CANVAS_LIGHT_FILTER_NONE; + shadow_smooth = 0.0; } }; diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index e0201420fe..81139ecc1c 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -153,6 +153,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["EXTRA_MATRIX"] = ShaderLanguage::TYPE_MAT4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["PARTICLE_CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["AT_LIGHT_PASS"] = ShaderLanguage::TYPE_BOOL; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SRC_COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POSITION"] = ShaderLanguage::TYPE_VEC2; @@ -166,6 +167,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POINT_COORD"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TIME"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["AT_LIGHT_PASS"] = ShaderLanguage::TYPE_BOOL; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["POSITION"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["NORMAL"] = ShaderLanguage::TYPE_VEC3; @@ -204,7 +206,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["RESTART"] = ShaderLanguage::TYPE_BOOL; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["CUSTOM"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_VEC4; + shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["LIFETIME"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["DELTA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["NUMBER"] = ShaderLanguage::TYPE_UINT; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 14a7af3e6e..48e6a3d006 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -916,6 +916,13 @@ void VisualServerCanvas::canvas_light_set_shadow_color(RID p_light, const Color clight->shadow_color = p_color; } +void VisualServerCanvas::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) { + + RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light); + ERR_FAIL_COND(!clight); + clight->shadow_smooth = p_smooth; +} + RID VisualServerCanvas::canvas_light_occluder_create() { RasterizerCanvas::LightOccluderInstance *occluder = memnew(RasterizerCanvas::LightOccluderInstance); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 47b057f96a..b4ddf2dc8e 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -209,6 +209,7 @@ public: void canvas_light_set_shadow_gradient_length(RID p_light, float p_length); void canvas_light_set_shadow_filter(RID p_light, VS::CanvasLightShadowFilter p_filter); void canvas_light_set_shadow_color(RID p_light, const Color &p_color); + void canvas_light_set_shadow_smooth(RID p_light, float p_smooth); RID canvas_light_occluder_create(); void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index b4b43a31be..887933f7fc 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -952,7 +952,7 @@ public: BIND2(environment_set_bg_energy, RID, float) BIND2(environment_set_canvas_max_layer, RID, int) BIND4(environment_set_ambient_light, RID, const Color &, float, float) - BIND8(environment_set_ssr, RID, bool, int, float, float, float, bool, bool) + BIND7(environment_set_ssr, RID, bool, int, float, float, float, bool) BIND10(environment_set_ssao, RID, bool, float, float, float, float, float, float, const Color &, bool) BIND6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality) @@ -1082,6 +1082,7 @@ public: BIND2(canvas_light_set_shadow_gradient_length, RID, float) BIND2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter) BIND2(canvas_light_set_shadow_color, RID, const Color &) + BIND2(canvas_light_set_shadow_smooth, RID, float) BIND0R(RID, canvas_light_occluder_create) BIND2(canvas_light_occluder_attach_to_canvas, RID, RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index b905b230dc..352daa9655 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1347,6 +1347,8 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons bool overlap = VSG::storage->light_directional_get_blend_splits(p_instance->base); + float first_radius = 0.0; + for (int i = 0; i < splits; i++) { // setup a camera matrix for that range! @@ -1373,9 +1375,11 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons // obtain the light frustm ranges (given endpoints) - Vector3 x_vec = p_instance->transform.basis.get_axis(Vector3::AXIS_X).normalized(); - Vector3 y_vec = p_instance->transform.basis.get_axis(Vector3::AXIS_Y).normalized(); - Vector3 z_vec = p_instance->transform.basis.get_axis(Vector3::AXIS_Z).normalized(); + Transform transform = p_instance->transform.orthonormalized(); //discard scale and stabilize light + + Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); + Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); + Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); //z_vec points agsint the camera, like in default opengl float x_min, x_max; @@ -1386,7 +1390,10 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons float y_min_cam, y_max_cam; float z_min_cam, z_max_cam; + float bias_scale = 1.0; + //used for culling + for (int j = 0; j < 8; j++) { float d_x = x_vec.dot(endpoints[j]); @@ -1435,6 +1442,12 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons radius *= texture_size / (texture_size - 2.0); //add a texel by each side, so stepified texture will always fit + if (i == 0) { + first_radius = radius; + } else { + bias_scale = radius / first_radius; + } + x_max_cam = x_vec.dot(center) + radius; x_min_cam = x_vec.dot(center) - radius; y_max_cam = y_vec.dot(center) + radius; @@ -1493,10 +1506,10 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); Transform ortho_transform; - ortho_transform.basis = p_instance->transform.basis; + ortho_transform.basis = transform.basis; ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; - VSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, 0, distances[i + 1], i); + VSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, 0, distances[i + 1], i, bias_scale); } VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 1aab624654..92c6421987 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -118,7 +118,7 @@ public: Camera() { visible_layers = 0xFFFFFFFF; - fov = 60; + fov = 65; type = PERSPECTIVE; znear = 0.1; zfar = 100; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 6d65999df1..8df46b6bab 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -390,7 +390,7 @@ public: FUNC2(environment_set_bg_energy, RID, float) FUNC2(environment_set_canvas_max_layer, RID, int) FUNC4(environment_set_ambient_light, RID, const Color &, float, float) - FUNC8(environment_set_ssr, RID, bool, int, float, float, float, bool, bool) + FUNC7(environment_set_ssr, RID, bool, int, float, float, float, bool) FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, const Color &, bool) FUNC6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality) @@ -511,6 +511,7 @@ public: FUNC2(canvas_light_set_shadow_gradient_length, RID, float) FUNC2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter) FUNC2(canvas_light_set_shadow_color, RID, const Color &) + FUNC2(canvas_light_set_shadow_smooth, RID, float) FUNC0R(RID, canvas_light_occluder_create) FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID) diff --git a/servers/visual_server.h b/servers/visual_server.h index 3290a460a1..c41f134bcc 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -358,7 +358,6 @@ public: LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, LIGHT_PARAM_SHADOW_NORMAL_BIAS, LIGHT_PARAM_SHADOW_BIAS, - LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE, LIGHT_PARAM_MAX }; @@ -665,7 +664,7 @@ public: virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_grey) = 0; virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0; - virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_accel, float p_fade, float p_depth_tolerance, bool p_smooth, bool p_roughness) = 0; + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0; virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur) = 0; virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0; @@ -844,6 +843,7 @@ public: virtual void canvas_light_set_shadow_gradient_length(RID p_light, float p_length) = 0; virtual void canvas_light_set_shadow_filter(RID p_light, CanvasLightShadowFilter p_filter) = 0; virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0; + virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0; virtual RID canvas_light_occluder_create() = 0; virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) = 0; diff --git a/thirdparty/README.md b/thirdparty/README.md index 1f0543e6dc..c846094a6a 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -37,6 +37,18 @@ Check the diff of enet.h, protocol.c, and host.c with the 1.3.13 tarball before the next update. +## etc2comp + +- Upstream: https://github.com/google/etc2comp +- Version: 9cd0f9c (git) +- License: Apache + +Files extracted from upstream source: + +- all .cpp and .h files in EtcLib/ +- README.md, LICENSE, AUTHORS + + ## fonts - Upstream: ? @@ -60,7 +72,7 @@ Files extracted from upstream source: ## glad - Upstream: https://github.com/Dav1dde/glad -- Version: 0.1.13a0 +- Version: 0.1.14a0 - License: MIT The files we package are automatically generated. @@ -296,17 +308,6 @@ Files extracted from upstream source: - LICENSE.TXT -## rg-etc1 - -- Upstream: https://github.com/richgel999/rg-etc1 -- Version: 1.04 -- License: zlib - -Files extracted from upstream source: - -- `rg_etc1.{cpp,h}` - - ## rtaudio - Upstream: http://www.music.mcgill.ca/~gary/rtaudio/ diff --git a/thirdparty/etc2comp/AUTHORS b/thirdparty/etc2comp/AUTHORS new file mode 100644 index 0000000000..32daca27fe --- /dev/null +++ b/thirdparty/etc2comp/AUTHORS @@ -0,0 +1,7 @@ +# This is the list of Etc2Comp authors for copyright purposes.
+#
+# This does not necessarily list everyone who has contributed code, since in
+# some cases, their employer may be the copyright holder. To see the full list
+# of contributors, see the revision history in source control.
+Google Inc.
+Blue Shift Inc.
diff --git a/thirdparty/etc2comp/Etc.cpp b/thirdparty/etc2comp/Etc.cpp new file mode 100644 index 0000000000..a5ee706048 --- /dev/null +++ b/thirdparty/etc2comp/Etc.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EtcConfig.h" +#include "Etc.h" +#include "EtcFilter.h" + +#include <string.h> + +namespace Etc +{ + // ---------------------------------------------------------------------------------------------------- + // C-style inteface to the encoder + // + void Encode(float *a_pafSourceRGBA, + unsigned int a_uiSourceWidth, + unsigned int a_uiSourceHeight, + Image::Format a_format, + ErrorMetric a_eErrMetric, + float a_fEffort, + unsigned int a_uiJobs, + unsigned int a_uiMaxJobs, + unsigned char **a_ppaucEncodingBits, + unsigned int *a_puiEncodingBitsBytes, + unsigned int *a_puiExtendedWidth, + unsigned int *a_puiExtendedHeight, + int *a_piEncodingTime_ms, bool a_bVerboseOutput) + { + + Image image(a_pafSourceRGBA, a_uiSourceWidth, + a_uiSourceHeight, + a_eErrMetric); + image.m_bVerboseOutput = a_bVerboseOutput; + image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs); + + *a_ppaucEncodingBits = image.GetEncodingBits(); + *a_puiEncodingBitsBytes = image.GetEncodingBitsBytes(); + *a_puiExtendedWidth = image.GetExtendedWidth(); + *a_puiExtendedHeight = image.GetExtendedHeight(); + *a_piEncodingTime_ms = image.GetEncodingTimeMs(); + } + + void EncodeMipmaps(float *a_pafSourceRGBA, + unsigned int a_uiSourceWidth, + unsigned int a_uiSourceHeight, + Image::Format a_format, + ErrorMetric a_eErrMetric, + float a_fEffort, + unsigned int a_uiJobs, + unsigned int a_uiMaxJobs, + unsigned int a_uiMaxMipmaps, + unsigned int a_uiMipFilterFlags, + RawImage* a_pMipmapImages, + int *a_piEncodingTime_ms, + bool a_bVerboseOutput) + { + auto mipWidth = a_uiSourceWidth; + auto mipHeight = a_uiSourceHeight; + int totalEncodingTime = 0; + for(unsigned int mip = 0; mip < a_uiMaxMipmaps && mipWidth >= 1 && mipHeight >= 1; mip++) + { + float* pImageData = nullptr; + float* pMipImage = nullptr; + + if(mip == 0) + { + pImageData = a_pafSourceRGBA; + } + else + { + pMipImage = new float[mipWidth*mipHeight*4]; + if(FilterTwoPass(a_pafSourceRGBA, a_uiSourceWidth, a_uiSourceHeight, pMipImage, mipWidth, mipHeight, a_uiMipFilterFlags, Etc::FilterLanczos3) ) + { + pImageData = pMipImage; + } + } + + if ( pImageData ) + { + + Image image(pImageData, mipWidth, mipHeight, a_eErrMetric); + + image.m_bVerboseOutput = a_bVerboseOutput; + image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs); + + a_pMipmapImages[mip].paucEncodingBits = std::shared_ptr<unsigned char>(image.GetEncodingBits(), [](unsigned char *p) { delete[] p; }); + a_pMipmapImages[mip].uiEncodingBitsBytes = image.GetEncodingBitsBytes(); + a_pMipmapImages[mip].uiExtendedWidth = image.GetExtendedWidth(); + a_pMipmapImages[mip].uiExtendedHeight = image.GetExtendedHeight(); + + totalEncodingTime += image.GetEncodingTimeMs(); + } + + if(pMipImage) + { + delete[] pMipImage; + } + + if (!pImageData) + { + break; + } + + mipWidth >>= 1; + mipHeight >>= 1; + } + + *a_piEncodingTime_ms = totalEncodingTime; + } + + + // ---------------------------------------------------------------------------------------------------- + // + +} diff --git a/thirdparty/etc2comp/Etc.h b/thirdparty/etc2comp/Etc.h new file mode 100644 index 0000000000..439388d649 --- /dev/null +++ b/thirdparty/etc2comp/Etc.h @@ -0,0 +1,71 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcConfig.h" +#include "EtcImage.h" +#include "EtcColor.h" +#include "EtcErrorMetric.h" +#include <memory> + +#define ETCCOMP_MIN_EFFORT_LEVEL (0.0f) +#define ETCCOMP_DEFAULT_EFFORT_LEVEL (40.0f) +#define ETCCOMP_MAX_EFFORT_LEVEL (100.0f) + +namespace Etc +{ + class Block4x4EncodingBits; + + struct RawImage + { + int uiExtendedWidth; + int uiExtendedHeight; + unsigned int uiEncodingBitsBytes; + std::shared_ptr<unsigned char> paucEncodingBits; + }; + + + + // C-style inteface to the encoder + void Encode(float *a_pafSourceRGBA, + unsigned int a_uiSourceWidth, + unsigned int a_uiSourceHeight, + Image::Format a_format, + ErrorMetric a_eErrMetric, + float a_fEffort, + unsigned int a_uiJobs, + unsigned int a_uimaxJobs, + unsigned char **a_ppaucEncodingBits, + unsigned int *a_puiEncodingBitsBytes, + unsigned int *a_puiExtendedWidth, + unsigned int *a_puiExtendedHeight, + int *a_piEncodingTime_ms, bool a_bVerboseOutput = false); + + void EncodeMipmaps(float *a_pafSourceRGBA, + unsigned int a_uiSourceWidth, + unsigned int a_uiSourceHeight, + Image::Format a_format, + ErrorMetric a_eErrMetric, + float a_fEffort, + unsigned int a_uiJobs, + unsigned int a_uiMaxJobs, + unsigned int a_uiMaxMipmaps, + unsigned int a_uiMipFilterFlags, + RawImage* a_pMipmaps, + int *a_piEncodingTime_ms, bool a_bVerboseOutput = false); + +} diff --git a/thirdparty/etc2comp/EtcBlock4x4.cpp b/thirdparty/etc2comp/EtcBlock4x4.cpp new file mode 100644 index 0000000000..3082fe60db --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4.cpp @@ -0,0 +1,425 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4.cpp + +Implements the state associated with each 4x4 block of pixels in an image + +Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an +alpha of NAN + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4.h" + +#include "EtcBlock4x4EncodingBits.h" +#include "EtcColor.h" +#include "EtcImage.h" +#include "EtcColorFloatRGBA.h" +#include "EtcBlock4x4Encoding_RGB8.h" +#include "EtcBlock4x4Encoding_RGBA8.h" +#include "EtcBlock4x4Encoding_RGB8A1.h" +#include "EtcBlock4x4Encoding_R11.h" +#include "EtcBlock4x4Encoding_RG11.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +namespace Etc +{ + // ETC pixels are scanned vertically. + // this mapping is for when someone wants to scan the ETC pixels horizontally + const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 }; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4::Block4x4(void) + { + m_pimageSource = nullptr; + m_uiSourceH = 0; + m_uiSourceV = 0; + + m_sourcealphamix = SourceAlphaMix::UNKNOWN; + m_boolBorderPixels = false; + m_boolPunchThroughPixels = false; + + m_pencoding = nullptr; + + m_errormetric = ErrorMetric::NUMERIC; + + } + Block4x4::~Block4x4() + { + m_pimageSource = nullptr; + if (m_pencoding) + { + delete m_pencoding; + m_pencoding = nullptr; + } + } + // ---------------------------------------------------------------------------------------------------- + // initialization prior to encoding from a source image + // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource + // a_paucEncodingBits is the place to store the final encoding + // a_errormetric is used for finding the best encoding + // + void Block4x4::InitFromSource(Image *a_pimageSource, + unsigned int a_uiSourceH, unsigned int a_uiSourceV, + unsigned char *a_paucEncodingBits, + ErrorMetric a_errormetric) + { + + Block4x4(); + + m_pimageSource = a_pimageSource; + m_uiSourceH = a_uiSourceH; + m_uiSourceV = a_uiSourceV; + m_errormetric = a_errormetric; + + SetSourcePixels(); + + // set block encoder function + switch (m_pimageSource->GetFormat()) + { + case Image::Format::ETC1: + m_pencoding = new Block4x4Encoding_ETC1; + break; + + case Image::Format::RGB8: + case Image::Format::SRGB8: + m_pencoding = new Block4x4Encoding_RGB8; + break; + + case Image::Format::RGBA8: + case Image::Format::SRGBA8: + if (a_errormetric == RGBX) + { + m_pencoding = new Block4x4Encoding_RGBA8; + } + else + { + switch (m_sourcealphamix) + { + case SourceAlphaMix::OPAQUE: + m_pencoding = new Block4x4Encoding_RGBA8_Opaque; + break; + + case SourceAlphaMix::TRANSPARENT: + m_pencoding = new Block4x4Encoding_RGBA8_Transparent; + break; + + case SourceAlphaMix::TRANSLUCENT: + m_pencoding = new Block4x4Encoding_RGBA8; + break; + + default: + assert(0); + break; + } + break; + } + break; + + case Image::Format::RGB8A1: + case Image::Format::SRGB8A1: + switch (m_sourcealphamix) + { + case SourceAlphaMix::OPAQUE: + m_pencoding = new Block4x4Encoding_RGB8A1_Opaque; + break; + + case SourceAlphaMix::TRANSPARENT: + m_pencoding = new Block4x4Encoding_RGB8A1_Transparent; + break; + + case SourceAlphaMix::TRANSLUCENT: + if (m_boolPunchThroughPixels) + { + m_pencoding = new Block4x4Encoding_RGB8A1; + } + else + { + m_pencoding = new Block4x4Encoding_RGB8A1_Opaque; + } + break; + + default: + assert(0); + break; + } + break; + + case Image::Format::R11: + case Image::Format::SIGNED_R11: + m_pencoding = new Block4x4Encoding_R11; + break; + case Image::Format::RG11: + case Image::Format::SIGNED_RG11: + m_pencoding = new Block4x4Encoding_RG11; + break; + default: + assert(0); + break; + } + + m_pencoding->InitFromSource(this, m_afrgbaSource, + a_paucEncodingBits, a_errormetric); + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization of encoding state from a prior encoding using encoding bits + // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource + // a_paucEncodingBits is the place to read the prior encoding + // a_imageformat is used to determine how to interpret a_paucEncodingBits + // a_errormetric was used for the prior encoding + // + void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat, + unsigned int a_uiSourceH, unsigned int a_uiSourceV, + unsigned char *a_paucEncodingBits, + Image *a_pimageSource, + ErrorMetric a_errormetric) + { + Block4x4(); + + m_pimageSource = a_pimageSource; + m_uiSourceH = a_uiSourceH; + m_uiSourceV = a_uiSourceV; + m_errormetric = a_errormetric; + + SetSourcePixels(); + + // set block encoder function + switch (a_imageformat) + { + case Image::Format::ETC1: + m_pencoding = new Block4x4Encoding_ETC1; + break; + + case Image::Format::RGB8: + case Image::Format::SRGB8: + m_pencoding = new Block4x4Encoding_RGB8; + break; + + case Image::Format::RGBA8: + case Image::Format::SRGBA8: + m_pencoding = new Block4x4Encoding_RGBA8; + break; + + case Image::Format::RGB8A1: + case Image::Format::SRGB8A1: + m_pencoding = new Block4x4Encoding_RGB8A1; + break; + + case Image::Format::R11: + case Image::Format::SIGNED_R11: + m_pencoding = new Block4x4Encoding_R11; + break; + case Image::Format::RG11: + case Image::Format::SIGNED_RG11: + m_pencoding = new Block4x4Encoding_RG11; + break; + default: + assert(0); + break; + } + + m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource, + m_pimageSource->GetErrorMetric()); + + } + + // ---------------------------------------------------------------------------------------------------- + // set source pixels from m_pimageSource + // set m_alphamix + // + void Block4x4::SetSourcePixels(void) + { + + Image::Format imageformat = m_pimageSource->GetFormat(); + + // alpha census + unsigned int uiTransparentSourcePixels = 0; + unsigned int uiOpaqueSourcePixels = 0; + + // copy source to consecutive memory locations + // convert from image horizontal scan to block vertical scan + unsigned int uiPixel = 0; + for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++) + { + unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH; + + for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++) + { + unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV; + + ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV); + + // if pixel extends beyond source image because of block padding + if (pfrgbaSource == nullptr) + { + m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel + m_boolBorderPixels = true; + uiTransparentSourcePixels++; + } + else + { + //get teh current pixel data, and store some of the attributes + //before capping values to fit the encoder type + + m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA(); + + if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX) + { + m_pimageSource->m_iNumOpaquePixels++; + } + else if (m_afrgbaSource[uiPixel].fA == 0.0f) + { + m_pimageSource->m_iNumTransparentPixels++; + } + else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f) + { + m_pimageSource->m_iNumTranslucentPixels++; + } + else + { + m_pimageSource->m_numOutOfRangeValues.fA++; + } + + if (m_afrgbaSource[uiPixel].fR != 0.0f) + { + m_pimageSource->m_numColorValues.fR++; + //make sure we are getting a float between 0-1 + if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f) + { + m_pimageSource->m_numOutOfRangeValues.fR++; + } + } + + if (m_afrgbaSource[uiPixel].fG != 0.0f) + { + m_pimageSource->m_numColorValues.fG++; + if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f) + { + m_pimageSource->m_numOutOfRangeValues.fG++; + } + } + if (m_afrgbaSource[uiPixel].fB != 0.0f) + { + m_pimageSource->m_numColorValues.fB++; + if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f) + { + m_pimageSource->m_numOutOfRangeValues.fB++; + } + } + // for formats with no alpha, set source alpha to 1 + if (imageformat == Image::Format::ETC1 || + imageformat == Image::Format::RGB8 || + imageformat == Image::Format::SRGB8) + { + m_afrgbaSource[uiPixel].fA = 1.0f; + } + + if (imageformat == Image::Format::R11 || + imageformat == Image::Format::SIGNED_R11) + { + m_afrgbaSource[uiPixel].fA = 1.0f; + m_afrgbaSource[uiPixel].fG = 0.0f; + m_afrgbaSource[uiPixel].fB = 0.0f; + } + + if (imageformat == Image::Format::RG11 || + imageformat == Image::Format::SIGNED_RG11) + { + m_afrgbaSource[uiPixel].fA = 1.0f; + m_afrgbaSource[uiPixel].fB = 0.0f; + } + + + // for RGB8A1, set source alpha to 0.0 or 1.0 + // set punch through flag + if (imageformat == Image::Format::RGB8A1 || + imageformat == Image::Format::SRGB8A1) + { + if (m_afrgbaSource[uiPixel].fA >= 0.5f) + { + m_afrgbaSource[uiPixel].fA = 1.0f; + } + else + { + m_afrgbaSource[uiPixel].fA = 0.0f; + m_boolPunchThroughPixels = true; + } + } + + if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX) + { + uiOpaqueSourcePixels++; + } + else if (m_afrgbaSource[uiPixel].fA == 0.0f) + { + uiTransparentSourcePixels++; + } + + } + + uiPixel += 1; + } + } + + if (uiOpaqueSourcePixels == PIXELS) + { + m_sourcealphamix = SourceAlphaMix::OPAQUE; + } + else if (uiTransparentSourcePixels == PIXELS) + { + m_sourcealphamix = SourceAlphaMix::TRANSPARENT; + } + else + { + m_sourcealphamix = SourceAlphaMix::TRANSLUCENT; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // return a name for the encoding mode + // + const char * Block4x4::GetEncodingModeName(void) + { + + switch (m_pencoding->GetMode()) + { + case Block4x4Encoding::MODE_ETC1: + return "ETC1"; + case Block4x4Encoding::MODE_T: + return "T"; + case Block4x4Encoding::MODE_H: + return "H"; + case Block4x4Encoding::MODE_PLANAR: + return "PLANAR"; + default: + return "???"; + } + } + + // ---------------------------------------------------------------------------------------------------- + // + +} diff --git a/thirdparty/etc2comp/EtcBlock4x4.h b/thirdparty/etc2comp/EtcBlock4x4.h new file mode 100644 index 0000000000..0fd30c598d --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4.h @@ -0,0 +1,172 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcColor.h" +#include "EtcColorFloatRGBA.h" +#include "EtcErrorMetric.h" +#include "EtcImage.h" +#include "EtcBlock4x4Encoding.h" + +namespace Etc +{ + class Block4x4EncodingBits; + + class Block4x4 + { + public: + + static const unsigned int ROWS = 4; + static const unsigned int COLUMNS = 4; + static const unsigned int PIXELS = ROWS * COLUMNS; + + // the alpha mix for a 4x4 block of pixels + enum class SourceAlphaMix + { + UNKNOWN, + // + OPAQUE, // all 1.0 + TRANSPARENT, // all 0.0 or NAN + TRANSLUCENT // not all opaque or transparent + }; + + typedef void (Block4x4::*EncoderFunctionPtr)(void); + + Block4x4(void); + ~Block4x4(); + void InitFromSource(Image *a_pimageSource, + unsigned int a_uiSourceH, + unsigned int a_uiSourceV, + unsigned char *a_paucEncodingBits, + ErrorMetric a_errormetric); + + void InitFromEtcEncodingBits(Image::Format a_imageformat, + unsigned int a_uiSourceH, + unsigned int a_uiSourceV, + unsigned char *a_paucEncodingBits, + Image *a_pimageSource, + ErrorMetric a_errormetric); + + // return true if final iteration was performed + inline void PerformEncodingIteration(float a_fEffort) + { + m_pencoding->PerformIteration(a_fEffort); + } + + inline void SetEncodingBitsFromEncoding(void) + { + m_pencoding->SetEncodingBits(); + } + + inline unsigned int GetSourceH(void) + { + return m_uiSourceH; + } + + inline unsigned int GetSourceV(void) + { + return m_uiSourceV; + } + + inline float GetError(void) + { + return m_pencoding->GetError(); + } + + static const unsigned int s_auiPixelOrderHScan[PIXELS]; + + inline ColorFloatRGBA * GetDecodedColors(void) + { + return m_pencoding->GetDecodedColors(); + } + + inline float * GetDecodedAlphas(void) + { + return m_pencoding->GetDecodedAlphas(); + } + + inline Block4x4Encoding::Mode GetEncodingMode(void) + { + return m_pencoding->GetMode(); + } + + inline bool GetFlip(void) + { + return m_pencoding->GetFlip(); + } + + inline bool IsDifferential(void) + { + return m_pencoding->IsDifferential(); + } + + inline ColorFloatRGBA * GetSource() + { + return m_afrgbaSource; + } + + inline ErrorMetric GetErrorMetric() + { + return m_errormetric; + } + + const char * GetEncodingModeName(void); + + inline Block4x4Encoding * GetEncoding(void) + { + return m_pencoding; + } + + inline SourceAlphaMix GetSourceAlphaMix(void) + { + return m_sourcealphamix; + } + + inline Image * GetImageSource(void) + { + return m_pimageSource; + } + + inline bool HasBorderPixels(void) + { + return m_boolBorderPixels; + } + + inline bool HasPunchThroughPixels(void) + { + return m_boolPunchThroughPixels; + } + + private: + + void SetSourcePixels(void); + + Image *m_pimageSource; + unsigned int m_uiSourceH; + unsigned int m_uiSourceV; + ErrorMetric m_errormetric; + ColorFloatRGBA m_afrgbaSource[PIXELS]; // vertical scan + + SourceAlphaMix m_sourcealphamix; + bool m_boolBorderPixels; // marked as rgba(NAN, NAN, NAN, NAN) + bool m_boolPunchThroughPixels; // RGB8A1 or SRGB8A1 with any pixels with alpha < 0.5 + + Block4x4Encoding *m_pencoding; + + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp new file mode 100644 index 0000000000..7a9e68c4cf --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp @@ -0,0 +1,261 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding.cpp + +Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a +particular file format (e.g. ETC1, RGB8, RGBA8, R11) + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding.h" + +#include "EtcBlock4x4EncodingBits.h" +#include "EtcBlock4x4.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +namespace Etc +{ + // ---------------------------------------------------------------------------------------------------- + // + const float Block4x4Encoding::LUMA_WEIGHT = 3.0f; + const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding::Block4x4Encoding(void) + { + + m_pblockParent = nullptr; + + m_pafrgbaSource = nullptr; + + m_boolBorderPixels = false; + + m_fError = -1.0f; + + m_mode = MODE_UNKNOWN; + + m_uiEncodingIterations = 0; + m_boolDone = false; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f); + m_afDecodedAlphas[uiPixel] = -1.0f; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // initialize the generic encoding for a 4x4 block + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // init the decoded pixels to -1 to mark them as undefined + // init the error to -1 to mark it as undefined + // + void Block4x4Encoding::Init(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + + m_pblockParent = a_pblockParent; + + m_pafrgbaSource = a_pafrgbaSource; + + m_boolBorderPixels = m_pblockParent->HasBorderPixels(); + + m_fError = -1.0f; + + m_uiEncodingIterations = 0; + + m_errormetric = a_errormetric; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f); + m_afDecodedAlphas[uiPixel] = -1.0f; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // calculate the error for the block by summing the pixel errors + // + void Block4x4Encoding::CalcBlockError(void) + { + m_fError = 0.0f; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel], + m_pafrgbaSource[uiPixel]); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // calculate the error between the source pixel and the decoded pixel + // the error amount is base on the error metric + // + float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha, + ColorFloatRGBA a_frgbaSourcePixel) + { + + // if a border pixel + if (isnan(a_frgbaSourcePixel.fA)) + { + return 0.0f; + } + + if (m_errormetric == ErrorMetric::RGBA) + { + assert(a_fDecodedAlpha >= 0.0f); + + float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) - + (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR); + float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) - + (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG); + float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) - + (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB); + + float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA; + + return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha; + } + else if (m_errormetric == ErrorMetric::RGBX) + { + assert(a_fDecodedAlpha >= 0.0f); + + float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR; + float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG; + float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB; + float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA; + + return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha; + } + else if (m_errormetric == ErrorMetric::REC709) + { + assert(a_fDecodedAlpha >= 0.0f); + + float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f; + float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f))); + float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f))); + + float fLuma2 = a_frgbaDecodedColor.fR*0.2126f + + a_frgbaDecodedColor.fG*0.7152f + + a_frgbaDecodedColor.fB*0.0722f; + float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f))); + float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f))); + + float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2; + float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2; + float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2; + + float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA; + + // Favor Luma accuracy over Chroma, and Red over Blue + return LUMA_WEIGHT*fDeltaL*fDeltaL + + fDeltaCr*fDeltaCr + + CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb + + fDAlpha*fDAlpha; + #if 0 + float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR; + float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG; + float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB; + return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue; +#endif + } + else if (m_errormetric == ErrorMetric::NORMALXYZ) + { + float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f; + float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f; + float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f; + + float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ); + + if (fDecodedLength < 0.5f) + { + return 1.0f; + } + else if (fDecodedLength == 0.0f) + { + fDecodedX = 1.0f; + fDecodedY = 0.0f; + fDecodedZ = 0.0f; + } + else + { + fDecodedX /= fDecodedLength; + fDecodedY /= fDecodedLength; + fDecodedZ /= fDecodedLength; + } + + float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f; + float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f; + float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f; + + float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ); + + if (fSourceLength == 0.0f) + { + fSourceX = 1.0f; + fSourceY = 0.0f; + fSourceZ = 0.0f; + } + else + { + fSourceX /= fSourceLength; + fSourceY /= fSourceLength; + fSourceZ /= fSourceLength; + } + + float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ; + float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f); + float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct; + + float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ; + float fLength2Error = fabsf(1.0f - fLength2); + + float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA; + float fErrorW = fDeltaW * fDeltaW; + + return fDotProductError + fLength2Error + fErrorW; + } + else // ErrorMetric::NUMERIC + { + assert(a_fDecodedAlpha >= 0.0f); + + float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR; + float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG; + float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB; + float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA; + + return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc + diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.h b/thirdparty/etc2comp/EtcBlock4x4Encoding.h new file mode 100644 index 0000000000..c14c3b8616 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding.h @@ -0,0 +1,148 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcColorFloatRGBA.h" + +#include "EtcErrorMetric.h" + +#include <assert.h> +#include <float.h> + +namespace Etc +{ + class Block4x4; + + // abstract base class for specific encodings + class Block4x4Encoding + { + public: + + static const unsigned int ROWS = 4; + static const unsigned int COLUMNS = 4; + static const unsigned int PIXELS = ROWS * COLUMNS; + static const float LUMA_WEIGHT; + static const float CHROMA_BLUE_WEIGHT; + + typedef enum + { + MODE_UNKNOWN, + // + MODE_ETC1, + MODE_T, + MODE_H, + MODE_PLANAR, + MODE_R11, + MODE_RG11, + // + MODES + } Mode; + + Block4x4Encoding(void); + //virtual ~Block4x4Encoding(void) =0; + virtual ~Block4x4Encoding(void) {} + virtual void InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) = 0; + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + + ErrorMetric a_errormetric) = 0; + + // perform an iteration of the encoding + // the first iteration must generate a complete, valid (if poor) encoding + virtual void PerformIteration(float a_fEffort) = 0; + + void CalcBlockError(void); + + inline float GetError(void) + { + assert(m_fError >= 0.0f); + + return m_fError; + } + + inline ColorFloatRGBA * GetDecodedColors(void) + { + return m_afrgbaDecodedColors; + } + + inline float * GetDecodedAlphas(void) + { + return m_afDecodedAlphas; + } + + virtual void SetEncodingBits(void) = 0; + + virtual bool GetFlip(void) = 0; + + virtual bool IsDifferential(void) = 0; + + virtual bool HasSeverelyBentDifferentialColors(void) const = 0; + + inline Mode GetMode(void) + { + return m_mode; + } + + inline bool IsDone(void) + { + return m_boolDone; + } + + inline void SetDoneIfPerfect() + { + if (GetError() == 0.0f) + { + m_boolDone = true; + } + } + + float CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha, + ColorFloatRGBA a_frgbaSourcePixel); + + protected: + + void Init(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + + ErrorMetric a_errormetric); + + Block4x4 *m_pblockParent; + ColorFloatRGBA *m_pafrgbaSource; + + bool m_boolBorderPixels; // if block has any border pixels + + ColorFloatRGBA m_afrgbaDecodedColors[PIXELS]; // decoded RGB components, ignore Alpha + float m_afDecodedAlphas[PIXELS]; // decoded alpha component + float m_fError; // error for RGBA relative to m_pafrgbaSource + + // intermediate encoding + Mode m_mode; + + unsigned int m_uiEncodingIterations; + bool m_boolDone; // all iterations have been done + ErrorMetric m_errormetric; + + private: + + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h b/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h new file mode 100644 index 0000000000..4065700379 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h @@ -0,0 +1,315 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <assert.h> + +namespace Etc +{ + + // ################################################################################ + // Block4x4EncodingBits + // Base class for Block4x4EncodingBits_XXXX + // ################################################################################ + + class Block4x4EncodingBits + { + public: + + enum class Format + { + UNKNOWN, + // + RGB8, + RGBA8, + R11, + RG11, + RGB8A1, + // + FORMATS + }; + + static unsigned int GetBytesPerBlock(Format a_format) + { + switch (a_format) + { + case Format::RGB8: + case Format::R11: + case Format::RGB8A1: + return 8; + break; + + case Format::RGBA8: + case Format::RG11: + return 16; + break; + + default: + return 0; + break; + } + + } + + }; + + // ################################################################################ + // Block4x4EncodingBits_RGB8 + // Encoding bits for the RGB portion of ETC1, RGB8, RGB8A1 and RGBA8 + // ################################################################################ + + class Block4x4EncodingBits_RGB8 + { + public: + + static const unsigned int BYTES_PER_BLOCK = 8; + + inline Block4x4EncodingBits_RGB8(void) + { + assert(sizeof(Block4x4EncodingBits_RGB8) == BYTES_PER_BLOCK); + + for (unsigned int uiByte = 0; uiByte < BYTES_PER_BLOCK; uiByte++) + { + auc[uiByte] = 0; + } + + } + + typedef struct + { + unsigned red2 : 4; + unsigned red1 : 4; + // + unsigned green2 : 4; + unsigned green1 : 4; + // + unsigned blue2 : 4; + unsigned blue1 : 4; + // + unsigned flip : 1; + unsigned diff : 1; + unsigned cw2 : 3; + unsigned cw1 : 3; + // + unsigned int selectors; + } Individual; + + typedef struct + { + signed dred2 : 3; + unsigned red1 : 5; + // + signed dgreen2 : 3; + unsigned green1 : 5; + // + signed dblue2 : 3; + unsigned blue1 : 5; + // + unsigned flip : 1; + unsigned diff : 1; + unsigned cw2 : 3; + unsigned cw1 : 3; + // + unsigned int selectors; + } Differential; + + typedef struct + { + unsigned red1b : 2; + unsigned detect2 : 1; + unsigned red1a : 2; + unsigned detect1 : 3; + // + unsigned blue1 : 4; + unsigned green1 : 4; + // + unsigned green2 : 4; + unsigned red2 : 4; + // + unsigned db : 1; + unsigned diff : 1; + unsigned da : 2; + unsigned blue2 : 4; + // + unsigned int selectors; + } T; + + typedef struct + { + unsigned green1a : 3; + unsigned red1 : 4; + unsigned detect1 : 1; + // + unsigned blue1b : 2; + unsigned detect3 : 1; + unsigned blue1a : 1; + unsigned green1b : 1; + unsigned detect2 : 3; + // + unsigned green2a : 3; + unsigned red2 : 4; + unsigned blue1c : 1; + // + unsigned db : 1; + unsigned diff : 1; + unsigned da : 1; + unsigned blue2 : 4; + unsigned green2b : 1; + // + unsigned int selectors; + } H; + + typedef struct + { + unsigned originGreen1 : 1; + unsigned originRed : 6; + unsigned detect1 : 1; + // + unsigned originBlue1 : 1; + unsigned originGreen2 : 6; + unsigned detect2 : 1; + // + unsigned originBlue3 : 2; + unsigned detect4 : 1; + unsigned originBlue2 : 2; + unsigned detect3 : 3; + // + unsigned horizRed2 : 1; + unsigned diff : 1; + unsigned horizRed1 : 5; + unsigned originBlue4 : 1; + // + unsigned horizBlue1: 1; + unsigned horizGreen : 7; + // + unsigned vertRed1 : 3; + unsigned horizBlue2 : 5; + // + unsigned vertGreen1 : 5; + unsigned vertRed2 : 3; + // + unsigned vertBlue : 6; + unsigned vertGreen2 : 2; + } Planar; + + union + { + unsigned char auc[BYTES_PER_BLOCK]; + unsigned long int ul; + Individual individual; + Differential differential; + T t; + H h; + Planar planar; + }; + + }; + + // ################################################################################ + // Block4x4EncodingBits_A8 + // Encoding bits for the A portion of RGBA8 + // ################################################################################ + + class Block4x4EncodingBits_A8 + { + public: + + static const unsigned int BYTES_PER_BLOCK = 8; + static const unsigned int SELECTOR_BYTES = 6; + + typedef struct + { + unsigned base : 8; + unsigned table : 4; + unsigned multiplier : 4; + unsigned selectors0 : 8; + unsigned selectors1 : 8; + unsigned selectors2 : 8; + unsigned selectors3 : 8; + unsigned selectors4 : 8; + unsigned selectors5 : 8; + } Data; + + Data data; + + }; + + // ################################################################################ + // Block4x4EncodingBits_R11 + // Encoding bits for the R portion of R11 + // ################################################################################ + + class Block4x4EncodingBits_R11 + { + public: + + static const unsigned int BYTES_PER_BLOCK = 8; + static const unsigned int SELECTOR_BYTES = 6; + + typedef struct + { + unsigned base : 8; + unsigned table : 4; + unsigned multiplier : 4; + unsigned selectors0 : 8; + unsigned selectors1 : 8; + unsigned selectors2 : 8; + unsigned selectors3 : 8; + unsigned selectors4 : 8; + unsigned selectors5 : 8; + } Data; + + Data data; + + }; + + class Block4x4EncodingBits_RG11 + { + public: + + static const unsigned int BYTES_PER_BLOCK = 16; + static const unsigned int SELECTOR_BYTES = 12; + + typedef struct + { + //Red portion + unsigned baseR : 8; + unsigned tableIndexR : 4; + unsigned multiplierR : 4; + unsigned selectorsR0 : 8; + unsigned selectorsR1 : 8; + unsigned selectorsR2 : 8; + unsigned selectorsR3 : 8; + unsigned selectorsR4 : 8; + unsigned selectorsR5 : 8; + //Green portion + unsigned baseG : 8; + unsigned tableIndexG : 4; + unsigned multiplierG : 4; + unsigned selectorsG0 : 8; + unsigned selectorsG1 : 8; + unsigned selectorsG2 : 8; + unsigned selectorsG3 : 8; + unsigned selectorsG4 : 8; + unsigned selectorsG5 : 8; + } Data; + + Data data; + + }; + +} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp new file mode 100644 index 0000000000..a27f74c0d5 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp @@ -0,0 +1,1281 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding_ETC1.cpp + +Block4x4Encoding_ETC1 is the encoder to use when targetting file format ETC1. This encoder is also +used for the ETC1 subset of file format RGB8, RGBA8 and RGB8A1 + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding_ETC1.h" + +#include "EtcBlock4x4.h" +#include "EtcBlock4x4EncodingBits.h" +#include "EtcDifferentialTrys.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <float.h> +#include <limits> + +namespace Etc +{ + + // pixel processing order if the flip bit = 0 (horizontal split) + const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip0[PIXELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + + // pixel processing order if the flip bit = 1 (vertical split) + const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip1[PIXELS] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 }; + + // pixel processing order for horizontal scan (ETC normally does a vertical scan) + const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 }; + + // pixel indices for different block halves + const unsigned int Block4x4Encoding_ETC1::s_auiLeftPixelMapping[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + const unsigned int Block4x4Encoding_ETC1::s_auiRightPixelMapping[8] = { 8, 9, 10, 11, 12, 13, 14, 15 }; + const unsigned int Block4x4Encoding_ETC1::s_auiTopPixelMapping[8] = { 0, 1, 4, 5, 8, 9, 12, 13 }; + const unsigned int Block4x4Encoding_ETC1::s_auiBottomPixelMapping[8] = { 2, 3, 6, 7, 10, 11, 14, 15 }; + + // CW ranges that the ETC1 decoders use + // CW is basically a contrast for the different selector bits, since these values are offsets to the base color + // the first axis in the array is indexed by the CW in the encoding bits + // the second axis in the array is indexed by the selector bits + float Block4x4Encoding_ETC1::s_aafCwTable[CW_RANGES][SELECTORS] = + { + { 2.0f / 255.0f, 8.0f / 255.0f, -2.0f / 255.0f, -8.0f / 255.0f }, + { 5.0f / 255.0f, 17.0f / 255.0f, -5.0f / 255.0f, -17.0f / 255.0f }, + { 9.0f / 255.0f, 29.0f / 255.0f, -9.0f / 255.0f, -29.0f / 255.0f }, + { 13.0f / 255.0f, 42.0f / 255.0f, -13.0f / 255.0f, -42.0f / 255.0f }, + { 18.0f / 255.0f, 60.0f / 255.0f, -18.0f / 255.0f, -60.0f / 255.0f }, + { 24.0f / 255.0f, 80.0f / 255.0f, -24.0f / 255.0f, -80.0f / 255.0f }, + { 33.0f / 255.0f, 106.0f / 255.0f, -33.0f / 255.0f, -106.0f / 255.0f }, + { 47.0f / 255.0f, 183.0f / 255.0f, -47.0f / 255.0f, -183.0f / 255.0f } + }; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding_ETC1::Block4x4Encoding_ETC1(void) + { + m_mode = MODE_ETC1; + m_boolDiff = false; + m_boolFlip = false; + m_frgbaColor1 = ColorFloatRGBA(); + m_frgbaColor2 = ColorFloatRGBA(); + m_uiCW1 = 0; + m_uiCW2 = 0; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = 0; + m_afDecodedAlphas[uiPixel] = 1.0f; + } + + m_boolMostLikelyFlip = false; + + m_fError = -1.0f; + + m_fError1 = -1.0f; + m_fError2 = -1.0f; + m_boolSeverelyBentDifferentialColors = false; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afDecodedAlphas[uiPixel] = 1.0f; + } + + } + + Block4x4Encoding_ETC1::~Block4x4Encoding_ETC1(void) {} + + // ---------------------------------------------------------------------------------------------------- + // initialization prior to encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits + // + void Block4x4Encoding_ETC1::InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) + { + + Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afDecodedAlphas[uiPixel] = 1.0f; + } + + m_fError = -1.0f; + + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits); + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits of a previous encoding + // + void Block4x4Encoding_ETC1::InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + + Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); + m_fError = -1.0f; + + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; + + m_mode = MODE_ETC1; + m_boolDiff = m_pencodingbitsRGB8->individual.diff; + m_boolFlip = m_pencodingbitsRGB8->individual.flip; + if (m_boolDiff) + { + int iR2 = (int)(m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2); + if (iR2 < 0) + { + iR2 = 0; + } + else if (iR2 > 31) + { + iR2 = 31; + } + + int iG2 = (int)(m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2); + if (iG2 < 0) + { + iG2 = 0; + } + else if (iG2 > 31) + { + iG2 = 31; + } + + int iB2 = (int)(m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2); + if (iB2 < 0) + { + iB2 = 0; + } + else if (iB2 > 31) + { + iB2 = 31; + } + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2); + + } + else + { + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red1, m_pencodingbitsRGB8->individual.green1, m_pencodingbitsRGB8->individual.blue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red2, m_pencodingbitsRGB8->individual.green2, m_pencodingbitsRGB8->individual.blue2); + } + + m_uiCW1 = m_pencodingbitsRGB8->individual.cw1; + m_uiCW2 = m_pencodingbitsRGB8->individual.cw2; + + InitFromEncodingBits_Selectors(); + + Decode(); + + CalcBlockError(); + } + + // ---------------------------------------------------------------------------------------------------- + // init the selectors from a prior encoding + // + void Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(void) + { + + unsigned char *paucSelectors = (unsigned char *)&m_pencodingbitsRGB8->individual.selectors; + + for (unsigned int iPixel = 0; iPixel < PIXELS; iPixel++) + { + unsigned int uiByteMSB = (unsigned int)(1 - (iPixel / 8)); + unsigned int uiByteLSB = (unsigned int)(3 - (iPixel / 8)); + unsigned int uiShift = (unsigned int)(iPixel & 7); + + unsigned int uiSelectorMSB = (unsigned int)((paucSelectors[uiByteMSB] >> uiShift) & 1); + unsigned int uiSelectorLSB = (unsigned int)((paucSelectors[uiByteLSB] >> uiShift) & 1); + + m_auiSelectors[iPixel] = (uiSelectorMSB << 1) + uiSelectorLSB; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_ETC1::PerformIteration(float a_fEffort) + { + assert(!m_boolDone); + + switch (m_uiEncodingIterations) + { + case 0: + PerformFirstIteration(); + break; + + case 1: + TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); + break; + + case 2: + TryIndividual(m_boolMostLikelyFlip, 1); + if (a_fEffort <= 49.5f) + { + m_boolDone = true; + } + break; + + case 3: + TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); + if (a_fEffort <= 59.5f) + { + m_boolDone = true; + } + break; + + case 4: + TryIndividual(!m_boolMostLikelyFlip, 1); + if (a_fEffort <= 69.5f) + { + m_boolDone = true; + } + break; + + case 5: + TryDegenerates1(); + if (a_fEffort <= 79.5f) + { + m_boolDone = true; + } + break; + + case 6: + TryDegenerates2(); + if (a_fEffort <= 89.5f) + { + m_boolDone = true; + } + break; + + case 7: + TryDegenerates3(); + if (a_fEffort <= 99.5f) + { + m_boolDone = true; + } + break; + + case 8: + TryDegenerates4(); + m_boolDone = true; + break; + + default: + assert(0); + break; + } + + m_uiEncodingIterations++; + SetDoneIfPerfect(); + } + + // ---------------------------------------------------------------------------------------------------- + // find best initial encoding to ensure block has a valid encoding + // + void Block4x4Encoding_ETC1::PerformFirstIteration(void) + { + CalculateMostLikelyFlip(); + + m_fError = FLT_MAX; + + TryDifferential(m_boolMostLikelyFlip, 0, 0, 0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + + TryIndividual(m_boolMostLikelyFlip, 0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + TryIndividual(!m_boolMostLikelyFlip, 0); + + } + + // ---------------------------------------------------------------------------------------------------- + // algorithm: + // create a source average color for the Left, Right, Top and Bottom halves using the 8 pixels in each half + // note: the "gray line" is the line of equal delta RGB that goes thru the average color + // for each half: + // see how close each of the 8 pixels are to the "gray line" that goes thru the source average color + // create an error value that is the sum of the distances from the gray line + // h_error is the sum of Left and Right errors + // v_error is the sum of Top and Bottom errors + // + void Block4x4Encoding_ETC1::CalculateMostLikelyFlip(void) + { + static const bool DEBUG_PRINT = false; + + CalculateSourceAverages(); + + float fLeftGrayErrorSum = 0.0f; + float fRightGrayErrorSum = 0.0f; + float fTopGrayErrorSum = 0.0f; + float fBottomGrayErrorSum = 0.0f; + + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ColorFloatRGBA *pfrgbaLeft = &m_pafrgbaSource[uiPixel]; + ColorFloatRGBA *pfrgbaRight = &m_pafrgbaSource[uiPixel + 8]; + ColorFloatRGBA *pfrgbaTop = &m_pafrgbaSource[s_auiTopPixelMapping[uiPixel]]; + ColorFloatRGBA *pfrgbaBottom = &m_pafrgbaSource[s_auiBottomPixelMapping[uiPixel]]; + + float fLeftGrayError = CalcGrayDistance2(*pfrgbaLeft, m_frgbaSourceAverageLeft); + float fRightGrayError = CalcGrayDistance2(*pfrgbaRight, m_frgbaSourceAverageRight); + float fTopGrayError = CalcGrayDistance2(*pfrgbaTop, m_frgbaSourceAverageTop); + float fBottomGrayError = CalcGrayDistance2(*pfrgbaBottom, m_frgbaSourceAverageBottom); + + fLeftGrayErrorSum += fLeftGrayError; + fRightGrayErrorSum += fRightGrayError; + fTopGrayErrorSum += fTopGrayError; + fBottomGrayErrorSum += fBottomGrayError; + } + + if (DEBUG_PRINT) + { + printf("\n%.2f %.2f\n", fLeftGrayErrorSum + fRightGrayErrorSum, fTopGrayErrorSum + fBottomGrayErrorSum); + } + + m_boolMostLikelyFlip = (fTopGrayErrorSum + fBottomGrayErrorSum) < (fLeftGrayErrorSum + fRightGrayErrorSum); + + } + + // ---------------------------------------------------------------------------------------------------- + // calculate source pixel averages for each 2x2 quadrant in a 4x4 block + // these are used to determine the averages for each of the 4 different halves (left, right, top, bottom) + // ignore pixels that have alpha == NAN (these are border pixels outside of the source image) + // weight the averages based on a pixel's alpha + // + void Block4x4Encoding_ETC1::CalculateSourceAverages(void) + { + static const bool DEBUG_PRINT = false; + + bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX; + + if (m_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE || boolRGBX) + { + ColorFloatRGBA frgbaSumUL = m_pafrgbaSource[0] + m_pafrgbaSource[1] + m_pafrgbaSource[4] + m_pafrgbaSource[5]; + ColorFloatRGBA frgbaSumLL = m_pafrgbaSource[2] + m_pafrgbaSource[3] + m_pafrgbaSource[6] + m_pafrgbaSource[7]; + ColorFloatRGBA frgbaSumUR = m_pafrgbaSource[8] + m_pafrgbaSource[9] + m_pafrgbaSource[12] + m_pafrgbaSource[13]; + ColorFloatRGBA frgbaSumLR = m_pafrgbaSource[10] + m_pafrgbaSource[11] + m_pafrgbaSource[14] + m_pafrgbaSource[15]; + + m_frgbaSourceAverageLeft = (frgbaSumUL + frgbaSumLL) * 0.125f; + m_frgbaSourceAverageRight = (frgbaSumUR + frgbaSumLR) * 0.125f; + m_frgbaSourceAverageTop = (frgbaSumUL + frgbaSumUR) * 0.125f; + m_frgbaSourceAverageBottom = (frgbaSumLL + frgbaSumLR) * 0.125f; + } + else + { + float afSourceAlpha[PIXELS]; + + // treat alpha NAN as 0.0f + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + afSourceAlpha[uiPixel] = isnan(m_pafrgbaSource[uiPixel].fA) ? + 0.0f : + m_pafrgbaSource[uiPixel].fA; + } + + ColorFloatRGBA afrgbaAlphaWeightedSource[PIXELS]; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + afrgbaAlphaWeightedSource[uiPixel] = m_pafrgbaSource[uiPixel] * afSourceAlpha[uiPixel]; + } + + ColorFloatRGBA frgbaSumUL = afrgbaAlphaWeightedSource[0] + + afrgbaAlphaWeightedSource[1] + + afrgbaAlphaWeightedSource[4] + + afrgbaAlphaWeightedSource[5]; + + ColorFloatRGBA frgbaSumLL = afrgbaAlphaWeightedSource[2] + + afrgbaAlphaWeightedSource[3] + + afrgbaAlphaWeightedSource[6] + + afrgbaAlphaWeightedSource[7]; + + ColorFloatRGBA frgbaSumUR = afrgbaAlphaWeightedSource[8] + + afrgbaAlphaWeightedSource[9] + + afrgbaAlphaWeightedSource[12] + + afrgbaAlphaWeightedSource[13]; + + ColorFloatRGBA frgbaSumLR = afrgbaAlphaWeightedSource[10] + + afrgbaAlphaWeightedSource[11] + + afrgbaAlphaWeightedSource[14] + + afrgbaAlphaWeightedSource[15]; + + float fWeightSumUL = afSourceAlpha[0] + + afSourceAlpha[1] + + afSourceAlpha[4] + + afSourceAlpha[5]; + + float fWeightSumLL = afSourceAlpha[2] + + afSourceAlpha[3] + + afSourceAlpha[6] + + afSourceAlpha[7]; + + float fWeightSumUR = afSourceAlpha[8] + + afSourceAlpha[9] + + afSourceAlpha[12] + + afSourceAlpha[13]; + + float fWeightSumLR = afSourceAlpha[10] + + afSourceAlpha[11] + + afSourceAlpha[14] + + afSourceAlpha[15]; + + ColorFloatRGBA frgbaSumLeft = frgbaSumUL + frgbaSumLL; + ColorFloatRGBA frgbaSumRight = frgbaSumUR + frgbaSumLR; + ColorFloatRGBA frgbaSumTop = frgbaSumUL + frgbaSumUR; + ColorFloatRGBA frgbaSumBottom = frgbaSumLL + frgbaSumLR; + + float fWeightSumLeft = fWeightSumUL + fWeightSumLL; + float fWeightSumRight = fWeightSumUR + fWeightSumLR; + float fWeightSumTop = fWeightSumUL + fWeightSumUR; + float fWeightSumBottom = fWeightSumLL + fWeightSumLR; + + // check to see if there is at least 1 pixel with non-zero alpha + // completely transparent block should not make it to this code + assert((fWeightSumLeft + fWeightSumRight) > 0.0f); + assert((fWeightSumTop + fWeightSumBottom) > 0.0f); + + if (fWeightSumLeft > 0.0f) + { + m_frgbaSourceAverageLeft = frgbaSumLeft * (1.0f/fWeightSumLeft); + } + if (fWeightSumRight > 0.0f) + { + m_frgbaSourceAverageRight = frgbaSumRight * (1.0f/fWeightSumRight); + } + if (fWeightSumTop > 0.0f) + { + m_frgbaSourceAverageTop = frgbaSumTop * (1.0f/fWeightSumTop); + } + if (fWeightSumBottom > 0.0f) + { + m_frgbaSourceAverageBottom = frgbaSumBottom * (1.0f/fWeightSumBottom); + } + + if (fWeightSumLeft == 0.0f) + { + assert(fWeightSumRight > 0.0f); + m_frgbaSourceAverageLeft = m_frgbaSourceAverageRight; + } + if (fWeightSumRight == 0.0f) + { + assert(fWeightSumLeft > 0.0f); + m_frgbaSourceAverageRight = m_frgbaSourceAverageLeft; + } + if (fWeightSumTop == 0.0f) + { + assert(fWeightSumBottom > 0.0f); + m_frgbaSourceAverageTop = m_frgbaSourceAverageBottom; + } + if (fWeightSumBottom == 0.0f) + { + assert(fWeightSumTop > 0.0f); + m_frgbaSourceAverageBottom = m_frgbaSourceAverageTop; + } + } + + + + if (DEBUG_PRINT) + { + printf("\ntarget: [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f]\n", + m_frgbaSourceAverageLeft.fR, m_frgbaSourceAverageLeft.fG, m_frgbaSourceAverageLeft.fB, + m_frgbaSourceAverageRight.fR, m_frgbaSourceAverageRight.fG, m_frgbaSourceAverageRight.fB, + m_frgbaSourceAverageTop.fR, m_frgbaSourceAverageTop.fG, m_frgbaSourceAverageTop.fB, + m_frgbaSourceAverageBottom.fR, m_frgbaSourceAverageBottom.fG, m_frgbaSourceAverageBottom.fB); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try an ETC1 differential mode encoding + // use a_boolFlip to set the encoding F bit + // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius] + // use a_iGrayOffset1 and a_iGrayOffset2 to offset the basecolor to search for degenerate encodings + // replace the encoding if the encoding error is less than previous encoding + // + void Block4x4Encoding_ETC1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, + int a_iGrayOffset1, int a_iGrayOffset2) + { + + ColorFloatRGBA frgbaColor1; + ColorFloatRGBA frgbaColor2; + + const unsigned int *pauiPixelMapping1; + const unsigned int *pauiPixelMapping2; + + if (a_boolFlip) + { + frgbaColor1 = m_frgbaSourceAverageTop; + frgbaColor2 = m_frgbaSourceAverageBottom; + + pauiPixelMapping1 = s_auiTopPixelMapping; + pauiPixelMapping2 = s_auiBottomPixelMapping; + } + else + { + frgbaColor1 = m_frgbaSourceAverageLeft; + frgbaColor2 = m_frgbaSourceAverageRight; + + pauiPixelMapping1 = s_auiLeftPixelMapping; + pauiPixelMapping2 = s_auiRightPixelMapping; + } + + DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, + a_uiRadius, a_iGrayOffset1, a_iGrayOffset2); + + Block4x4Encoding_ETC1 encodingTry = *this; + encodingTry.m_boolFlip = a_boolFlip; + + encodingTry.TryDifferentialHalf(&trys.m_half1); + encodingTry.TryDifferentialHalf(&trys.m_half2); + + // find best halves that are within differential range + DifferentialTrys::Try *ptryBest1 = nullptr; + DifferentialTrys::Try *ptryBest2 = nullptr; + encodingTry.m_fError = FLT_MAX; + + // see if the best of each half are in differential range + int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed; + int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen; + int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue; + if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3) + { + ptryBest1 = trys.m_half1.m_ptryBest; + ptryBest2 = trys.m_half2.m_ptryBest; + encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError; + } + else + { + // else, find the next best halves that are in differential range + for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0]; + ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys]; + ptry1++) + { + for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0]; + ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys]; + ptry2++) + { + iDRed = ptry2->m_iRed - ptry1->m_iRed; + bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4; + iDGreen = ptry2->m_iGreen - ptry1->m_iGreen; + bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4; + iDBlue = ptry2->m_iBlue - ptry1->m_iBlue; + bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4; + + if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta) + { + float fError = ptry1->m_fError + ptry2->m_fError; + + if (fError < encodingTry.m_fError) + { + encodingTry.m_fError = fError; + + ptryBest1 = ptry1; + ptryBest2 = ptry2; + } + } + + } + } + assert(encodingTry.m_fError < FLT_MAX); + assert(ptryBest1 != nullptr); + assert(ptryBest2 != nullptr); + } + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_ETC1; + m_boolDiff = true; + m_boolFlip = encodingTry.m_boolFlip; + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue); + m_uiCW1 = ptryBest1->m_uiCW; + m_uiCW2 = ptryBest2->m_uiCW; + + for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++) + { + unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder]; + unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder]; + + unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder]; + unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder]; + + m_auiSelectors[uiPixel1] = uiSelector1; + m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder]; + + float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1]; + float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2]; + + m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB(); + m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB(); + } + + m_fError1 = ptryBest1->m_fError; + m_fError2 = ptryBest2->m_fError; + m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors; + m_fError = m_fError1 + m_fError2; + + // sanity check + { + int iRed1 = m_frgbaColor1.IntRed(31.0f); + int iGreen1 = m_frgbaColor1.IntGreen(31.0f); + int iBlue1 = m_frgbaColor1.IntBlue(31.0f); + + int iRed2 = m_frgbaColor2.IntRed(31.0f); + int iGreen2 = m_frgbaColor2.IntGreen(31.0f); + int iBlue2 = m_frgbaColor2.IntBlue(31.0f); + + iDRed = iRed2 - iRed1; + iDGreen = iGreen2 - iGreen1; + iDBlue = iBlue2 - iBlue1; + + assert(iDRed >= -4 && iDRed < 4); + assert(iDGreen >= -4 && iDGreen < 4); + assert(iDBlue >= -4 && iDBlue < 4); + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try an ETC1 differential mode encoding for a half of a 4x4 block + // vary the basecolor components using a radius + // + void Block4x4Encoding_ETC1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf) + { + + a_phalf->m_ptryBest = nullptr; + float fBestTryError = FLT_MAX; + + a_phalf->m_uiTrys = 0; + for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius; + iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius; + iRed++) + { + assert(iRed >= 0 && iRed <= 31); + + for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius; + iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius; + iGreen++) + { + assert(iGreen >= 0 && iGreen <= 31); + + for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius; + iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius; + iBlue++) + { + assert(iBlue >= 0 && iBlue <= 31); + + DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys]; + assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]); + + ptry->m_iRed = iRed; + ptry->m_iGreen = iGreen; + ptry->m_iBlue = iBlue; + ptry->m_fError = FLT_MAX; + ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue); + + // try each CW + for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) + { + unsigned int auiPixelSelectors[PIXELS / 2]; + ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2]; + float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + + // pre-compute decoded pixels for each selector + ColorFloatRGBA afrgbaSelectors[SELECTORS]; + assert(SELECTORS == 4); + afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB(); + afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB(); + afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB(); + afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB(); + + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]]; + ColorFloatRGBA frgbaDecodedPixel; + + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + frgbaDecodedPixel = afrgbaSelectors[uiSelector]; + + float fPixelError; + + fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]], + *pfrgbaSourcePixel); + + if (fPixelError < afPixelErrors[uiPixel]) + { + auiPixelSelectors[uiPixel] = uiSelector; + afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel; + afPixelErrors[uiPixel] = fPixelError; + } + + } + } + + // add up all pixel errors + float fCWError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + fCWError += afPixelErrors[uiPixel]; + } + + // if best CW so far + if (fCWError < ptry->m_fError) + { + ptry->m_uiCW = uiCW; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel]; + } + ptry->m_fError = fCWError; + } + + } + + if (ptry->m_fError < fBestTryError) + { + a_phalf->m_ptryBest = ptry; + fBestTryError = ptry->m_fError; + } + + assert(ptry->m_fError < FLT_MAX); + + a_phalf->m_uiTrys++; + } + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try an ETC1 individual mode encoding + // use a_boolFlip to set the encoding F bit + // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius] + // replace the encoding if the encoding error is less than previous encoding + // + void Block4x4Encoding_ETC1::TryIndividual(bool a_boolFlip, unsigned int a_uiRadius) + { + + ColorFloatRGBA frgbaColor1; + ColorFloatRGBA frgbaColor2; + + const unsigned int *pauiPixelMapping1; + const unsigned int *pauiPixelMapping2; + + if (a_boolFlip) + { + frgbaColor1 = m_frgbaSourceAverageTop; + frgbaColor2 = m_frgbaSourceAverageBottom; + + pauiPixelMapping1 = s_auiTopPixelMapping; + pauiPixelMapping2 = s_auiBottomPixelMapping; + } + else + { + frgbaColor1 = m_frgbaSourceAverageLeft; + frgbaColor2 = m_frgbaSourceAverageRight; + + pauiPixelMapping1 = s_auiLeftPixelMapping; + pauiPixelMapping2 = s_auiRightPixelMapping; + } + + IndividualTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, a_uiRadius); + + Block4x4Encoding_ETC1 encodingTry = *this; + encodingTry.m_boolFlip = a_boolFlip; + + encodingTry.TryIndividualHalf(&trys.m_half1); + encodingTry.TryIndividualHalf(&trys.m_half2); + + // use the best of each half + IndividualTrys::Try *ptryBest1 = trys.m_half1.m_ptryBest; + IndividualTrys::Try *ptryBest2 = trys.m_half2.m_ptryBest; + encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError; + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_ETC1; + m_boolDiff = false; + m_boolFlip = encodingTry.m_boolFlip; + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue); + m_uiCW1 = ptryBest1->m_uiCW; + m_uiCW2 = ptryBest2->m_uiCW; + + for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++) + { + unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder]; + unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder]; + + unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder]; + unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder]; + + m_auiSelectors[uiPixel1] = uiSelector1; + m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder]; + + float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1]; + float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2]; + + m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB(); + m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB(); + } + + m_fError1 = ptryBest1->m_fError; + m_fError2 = ptryBest2->m_fError; + m_fError = m_fError1 + m_fError2; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try an ETC1 differential mode encoding for a half of a 4x4 block + // vary the basecolor components using a radius + // + void Block4x4Encoding_ETC1::TryIndividualHalf(IndividualTrys::Half *a_phalf) + { + + a_phalf->m_ptryBest = nullptr; + float fBestTryError = FLT_MAX; + + a_phalf->m_uiTrys = 0; + for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius; + iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius; + iRed++) + { + assert(iRed >= 0 && iRed <= 15); + + for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius; + iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius; + iGreen++) + { + assert(iGreen >= 0 && iGreen <= 15); + + for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius; + iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius; + iBlue++) + { + assert(iBlue >= 0 && iBlue <= 15); + + IndividualTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys]; + assert(ptry < &a_phalf->m_atry[IndividualTrys::Half::MAX_TRYS]); + + ptry->m_iRed = iRed; + ptry->m_iGreen = iGreen; + ptry->m_iBlue = iBlue; + ptry->m_fError = FLT_MAX; + ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue); + + // try each CW + for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) + { + unsigned int auiPixelSelectors[PIXELS / 2]; + ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2]; + float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + + // pre-compute decoded pixels for each selector + ColorFloatRGBA afrgbaSelectors[SELECTORS]; + assert(SELECTORS == 4); + afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB(); + afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB(); + afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB(); + afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB(); + + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]]; + ColorFloatRGBA frgbaDecodedPixel; + + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + frgbaDecodedPixel = afrgbaSelectors[uiSelector]; + + float fPixelError; + + fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]], + *pfrgbaSourcePixel); + + if (fPixelError < afPixelErrors[uiPixel]) + { + auiPixelSelectors[uiPixel] = uiSelector; + afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel; + afPixelErrors[uiPixel] = fPixelError; + } + + } + } + + // add up all pixel errors + float fCWError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + fCWError += afPixelErrors[uiPixel]; + } + + // if best CW so far + if (fCWError < ptry->m_fError) + { + ptry->m_uiCW = uiCW; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel]; + } + ptry->m_fError = fCWError; + } + + } + + if (ptry->m_fError < fBestTryError) + { + a_phalf->m_ptryBest = ptry; + fBestTryError = ptry->m_fError; + } + + assert(ptry->m_fError < FLT_MAX); + + a_phalf->m_uiTrys++; + } + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 1 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_ETC1::TryDegenerates1(void) + { + + TryDifferential(m_boolMostLikelyFlip, 1, -2, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 2, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 0, 2); + TryDifferential(m_boolMostLikelyFlip, 1, 0, -2); + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 2 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_ETC1::TryDegenerates2(void) + { + + TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0); + TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0); + TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2); + TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2); + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 3 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_ETC1::TryDegenerates3(void) + { + + TryDifferential(m_boolMostLikelyFlip, 1, -2, -2); + TryDifferential(m_boolMostLikelyFlip, 1, -2, 2); + TryDifferential(m_boolMostLikelyFlip, 1, 2, -2); + TryDifferential(m_boolMostLikelyFlip, 1, 2, 2); + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 4 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_ETC1::TryDegenerates4(void) + { + + TryDifferential(m_boolMostLikelyFlip, 1, -4, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 4, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 0, 4); + TryDifferential(m_boolMostLikelyFlip, 1, 0, -4); + + } + + // ---------------------------------------------------------------------------------------------------- + // find the best selector for each pixel based on a particular basecolor and CW that have been previously set + // calculate the selectors for each half of the block separately + // set the block error as the sum of each half's error + // + void Block4x4Encoding_ETC1::CalculateSelectors() + { + if (m_boolFlip) + { + CalculateHalfOfTheSelectors(0, s_auiTopPixelMapping); + CalculateHalfOfTheSelectors(1, s_auiBottomPixelMapping); + } + else + { + CalculateHalfOfTheSelectors(0, s_auiLeftPixelMapping); + CalculateHalfOfTheSelectors(1, s_auiRightPixelMapping); + } + + m_fError = m_fError1 + m_fError2; + } + + // ---------------------------------------------------------------------------------------------------- + // choose best selectors for half of the block + // calculate the error for half of the block + // + void Block4x4Encoding_ETC1::CalculateHalfOfTheSelectors(unsigned int a_uiHalf, + const unsigned int *pauiPixelMapping) + { + static const bool DEBUG_PRINT = false; + + ColorFloatRGBA *pfrgbaColor = a_uiHalf ? &m_frgbaColor2 : &m_frgbaColor1; + unsigned int *puiCW = a_uiHalf ? &m_uiCW2 : &m_uiCW1; + + float *pfHalfError = a_uiHalf ? &m_fError2 : &m_fError1; + *pfHalfError = FLT_MAX; + + // try each CW + for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) + { + if (DEBUG_PRINT) + { + printf("\ncw=%u\n", uiCW); + } + + unsigned int auiPixelSelectors[PIXELS / 2]; + ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2]; + float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + if (DEBUG_PRINT) + { + printf("\tsource [%.2f,%.2f,%.2f]\n", m_pafrgbaSource[pauiPixelMapping[uiPixel]].fR, + m_pafrgbaSource[pauiPixelMapping[uiPixel]].fG, m_pafrgbaSource[pauiPixelMapping[uiPixel]].fB); + } + + ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[pauiPixelMapping[uiPixel]]; + ColorFloatRGBA frgbaDecodedPixel; + + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + float fDeltaRGB = s_aafCwTable[uiCW][uiSelector]; + + frgbaDecodedPixel = (*pfrgbaColor + fDeltaRGB).ClampRGB(); + + float fPixelError; + + fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[pauiPixelMapping[uiPixel]], + *pfrgbaSourcePixel); + + if (DEBUG_PRINT) + { + printf("\tpixel %u, index %u [%.2f,%.2f,%.2f], error %.2f", uiPixel, uiSelector, + frgbaDecodedPixel.fR, + frgbaDecodedPixel.fG, + frgbaDecodedPixel.fB, + fPixelError); + } + + if (fPixelError < afPixelErrors[uiPixel]) + { + if (DEBUG_PRINT) + { + printf(" *"); + } + + auiPixelSelectors[uiPixel] = uiSelector; + afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel; + afPixelErrors[uiPixel] = fPixelError; + } + + if (DEBUG_PRINT) + { + printf("\n"); + } + } + } + + // add up all pixel errors + float fCWError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + fCWError += afPixelErrors[uiPixel]; + } + if (DEBUG_PRINT) + { + printf("\terror %.2f\n", fCWError); + } + + // if best CW so far + if (fCWError < *pfHalfError) + { + *pfHalfError = fCWError; + *puiCW = uiCW; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + m_auiSelectors[pauiPixelMapping[uiPixel]] = auiPixelSelectors[uiPixel]; + m_afrgbaDecodedColors[pauiPixelMapping[uiPixel]] = afrgbaDecodedPixels[uiPixel]; + } + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_ETC1::SetEncodingBits(void) + { + assert(m_mode == MODE_ETC1); + + if (m_boolDiff) + { + int iRed1 = m_frgbaColor1.IntRed(31.0f); + int iGreen1 = m_frgbaColor1.IntGreen(31.0f); + int iBlue1 = m_frgbaColor1.IntBlue(31.0f); + + int iRed2 = m_frgbaColor2.IntRed(31.0f); + int iGreen2 = m_frgbaColor2.IntGreen(31.0f); + int iBlue2 = m_frgbaColor2.IntBlue(31.0f); + + int iDRed2 = iRed2 - iRed1; + int iDGreen2 = iGreen2 - iGreen1; + int iDBlue2 = iBlue2 - iBlue1; + + assert(iDRed2 >= -4 && iDRed2 < 4); + assert(iDGreen2 >= -4 && iDGreen2 < 4); + assert(iDBlue2 >= -4 && iDBlue2 < 4); + + m_pencodingbitsRGB8->differential.red1 = (unsigned int)iRed1; + m_pencodingbitsRGB8->differential.green1 = (unsigned int)iGreen1; + m_pencodingbitsRGB8->differential.blue1 = (unsigned int)iBlue1; + + m_pencodingbitsRGB8->differential.dred2 = iDRed2; + m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2; + m_pencodingbitsRGB8->differential.dblue2 = iDBlue2; + } + else + { + m_pencodingbitsRGB8->individual.red1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); + m_pencodingbitsRGB8->individual.green1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); + m_pencodingbitsRGB8->individual.blue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); + + m_pencodingbitsRGB8->individual.red2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); + m_pencodingbitsRGB8->individual.green2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); + m_pencodingbitsRGB8->individual.blue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); + } + + m_pencodingbitsRGB8->individual.cw1 = m_uiCW1; + m_pencodingbitsRGB8->individual.cw2 = m_uiCW2; + + SetEncodingBits_Selectors(); + + m_pencodingbitsRGB8->individual.diff = (unsigned int)m_boolDiff; + m_pencodingbitsRGB8->individual.flip = (unsigned int)m_boolFlip; + + } + + // ---------------------------------------------------------------------------------------------------- + // set the selectors in the encoding bits + // + void Block4x4Encoding_ETC1::SetEncodingBits_Selectors(void) + { + + m_pencodingbitsRGB8->individual.selectors = 0; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiSelector = m_auiSelectors[uiPixel]; + + // set index msb + m_pencodingbitsRGB8->individual.selectors |= (uiSelector >> 1) << (uiPixel ^ 8); + + // set index lsb + m_pencodingbitsRGB8->individual.selectors |= (uiSelector & 1) << ((16 + uiPixel) ^ 8); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the decoded colors and decoded alpha based on the encoding state + // + void Block4x4Encoding_ETC1::Decode(void) + { + + const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0; + + for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++) + { + ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2; + unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2; + + unsigned int uiPixel = pauiPixelOrder[uiPixelOrder]; + + float fDelta = s_aafCwTable[uiCW][m_auiSelectors[uiPixel]]; + m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h new file mode 100644 index 0000000000..c0dc84d5d5 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h @@ -0,0 +1,186 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcBlock4x4Encoding.h" +#include "EtcBlock4x4EncodingBits.h" +#include "EtcDifferentialTrys.h" +#include "EtcIndividualTrys.h" + +namespace Etc +{ + + // base class for Block4x4Encoding_RGB8 + class Block4x4Encoding_ETC1 : public Block4x4Encoding + { + public: + + Block4x4Encoding_ETC1(void); + virtual ~Block4x4Encoding_ETC1(void); + + virtual void InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + + unsigned char *a_paucEncodingBits, + ErrorMetric a_errormetric); + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + + ErrorMetric a_errormetric); + + virtual void PerformIteration(float a_fEffort); + + inline virtual bool GetFlip(void) + { + return m_boolFlip; + } + + inline virtual bool IsDifferential(void) + { + return m_boolDiff; + } + + virtual void SetEncodingBits(void); + + void Decode(void); + + inline ColorFloatRGBA GetColor1(void) const + { + return m_frgbaColor1; + } + + inline ColorFloatRGBA GetColor2(void) const + { + return m_frgbaColor2; + } + + inline const unsigned int * GetSelectors(void) const + { + return m_auiSelectors; + } + + inline unsigned int GetCW1(void) const + { + return m_uiCW1; + } + + inline unsigned int GetCW2(void) const + { + return m_uiCW2; + } + + inline bool HasSeverelyBentDifferentialColors(void) const + { + return m_boolSeverelyBentDifferentialColors; + } + + protected: + + static const unsigned int s_auiPixelOrderFlip0[PIXELS]; + static const unsigned int s_auiPixelOrderFlip1[PIXELS]; + static const unsigned int s_auiPixelOrderHScan[PIXELS]; + + static const unsigned int s_auiLeftPixelMapping[8]; + static const unsigned int s_auiRightPixelMapping[8]; + static const unsigned int s_auiTopPixelMapping[8]; + static const unsigned int s_auiBottomPixelMapping[8]; + + static const unsigned int SELECTOR_BITS = 2; + static const unsigned int SELECTORS = 1 << SELECTOR_BITS; + + static const unsigned int CW_BITS = 3; + static const unsigned int CW_RANGES = 1 << CW_BITS; + + static float s_aafCwTable[CW_RANGES][SELECTORS]; + static unsigned char s_aucDifferentialCwRange[256]; + + static const int MAX_DIFFERENTIAL = 3; + static const int MIN_DIFFERENTIAL = -4; + + void InitFromEncodingBits_Selectors(void); + + void PerformFirstIteration(void); + void CalculateMostLikelyFlip(void); + + void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, + int a_iGrayOffset1, int a_iGrayOffset2); + void TryDifferentialHalf(DifferentialTrys::Half *a_phalf); + + void TryIndividual(bool a_boolFlip, unsigned int a_uiRadius); + void TryIndividualHalf(IndividualTrys::Half *a_phalf); + + void TryDegenerates1(void); + void TryDegenerates2(void); + void TryDegenerates3(void); + void TryDegenerates4(void); + + void CalculateSelectors(); + void CalculateHalfOfTheSelectors(unsigned int a_uiHalf, + const unsigned int *pauiPixelMapping); + + // calculate the distance2 of r_frgbaPixel from r_frgbaTarget's gray line + inline float CalcGrayDistance2(ColorFloatRGBA &r_frgbaPixel, + ColorFloatRGBA &r_frgbaTarget) + { + float fDeltaGray = ((r_frgbaPixel.fR - r_frgbaTarget.fR) + + (r_frgbaPixel.fG - r_frgbaTarget.fG) + + (r_frgbaPixel.fB - r_frgbaTarget.fB)) / 3.0f; + + ColorFloatRGBA frgbaPointOnGrayLine = (r_frgbaTarget + fDeltaGray).ClampRGB(); + + float fDR = r_frgbaPixel.fR - frgbaPointOnGrayLine.fR; + float fDG = r_frgbaPixel.fG - frgbaPointOnGrayLine.fG; + float fDB = r_frgbaPixel.fB - frgbaPointOnGrayLine.fB; + + return (fDR*fDR) + (fDG*fDG) + (fDB*fDB); + } + + void SetEncodingBits_Selectors(void); + + // intermediate encoding + bool m_boolDiff; + bool m_boolFlip; + ColorFloatRGBA m_frgbaColor1; + ColorFloatRGBA m_frgbaColor2; + unsigned int m_uiCW1; + unsigned int m_uiCW2; + unsigned int m_auiSelectors[PIXELS]; + + // state shared between iterations + ColorFloatRGBA m_frgbaSourceAverageLeft; + ColorFloatRGBA m_frgbaSourceAverageRight; + ColorFloatRGBA m_frgbaSourceAverageTop; + ColorFloatRGBA m_frgbaSourceAverageBottom; + bool m_boolMostLikelyFlip; + + // stats + float m_fError1; // error for Etc1 half 1 + float m_fError2; // error for Etc1 half 2 + bool m_boolSeverelyBentDifferentialColors; // only valid if m_boolDiff; + + // final encoding + Block4x4EncodingBits_RGB8 *m_pencodingbitsRGB8; // or RGB8 portion of Block4x4EncodingBits_RGB8A8 + + private: + + void CalculateSourceAverages(void); + + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp new file mode 100644 index 0000000000..4c012fbbf1 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp @@ -0,0 +1,429 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding_R11.cpp + +Block4x4Encoding_R11 is the encoder to use when targetting file format R11 and SR11 (signed R11). + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding_R11.h" + +#include "EtcBlock4x4EncodingBits.h" +#include "EtcBlock4x4.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <float.h> +#include <limits> + +namespace Etc +{ + + // modifier values to use for R11, SR11, RG11 and SRG11 + float Block4x4Encoding_R11::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS] + { + { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f }, + { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f }, + { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f }, + { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f }, + + { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f }, + { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f }, + { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, + { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, + + { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, + { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, + { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, + { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, + + { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, + { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f }, + { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f }, + { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f } + }; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding_R11::Block4x4Encoding_R11(void) + { + + m_pencodingbitsR11 = nullptr; + + } + + Block4x4Encoding_R11::~Block4x4Encoding_R11(void) {} + // ---------------------------------------------------------------------------------------------------- + // initialization prior to encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits + // + void Block4x4Encoding_R11::InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) + { + Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); + + m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits; + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits of a previous encoding + // + void Block4x4Encoding_R11::InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits; + + // init RGB portion + Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent, + (unsigned char *)m_pencodingbitsR11, + a_pafrgbaSource, + a_errormetric); + + // init R11 portion + { + m_mode = MODE_R11; + if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_fRedBase = (float)(signed char)m_pencodingbitsR11->data.base; + } + else + { + m_fRedBase = (float)(unsigned char)m_pencodingbitsR11->data.base; + } + m_fRedMultiplier = (float)m_pencodingbitsR11->data.multiplier; + m_uiRedModifierTableIndex = m_pencodingbitsR11->data.table; + + unsigned long long int ulliSelectorBits = 0; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors0 << 40; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors1 << 32; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors2 << 24; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors3 << 16; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors4 << 8; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors5; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiShift = 45 - (3 * uiPixel); + m_auiRedSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (SELECTORS - 1); + } + + // decode the red channel + // calc red error + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + float fDecodedPixelData = 0.0f; + if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + fDecodedPixelData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, + m_uiRedModifierTableIndex, + m_auiRedSelectors[uiPixel]); + } + else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + fDecodedPixelData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, + m_uiRedModifierTableIndex, + m_auiRedSelectors[uiPixel]); + } + else + { + assert(0); + } + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fDecodedPixelData, 0.0f, 0.0f, 1.0f); + } + CalcBlockError(); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_R11::PerformIteration(float a_fEffort) + { + assert(!m_boolDone); + m_mode = MODE_R11; + + switch (m_uiEncodingIterations) + { + case 0: + m_fError = FLT_MAX; + m_fRedBlockError = FLT_MAX; // artificially high value + CalculateR11(8, 0.0f, 0.0f); + m_fError = m_fRedBlockError; + break; + + case 1: + CalculateR11(8, 2.0f, 1.0f); + m_fError = m_fRedBlockError; + if (a_fEffort <= 24.5f) + { + m_boolDone = true; + } + break; + + case 2: + CalculateR11(8, 12.0f, 1.0f); + m_fError = m_fRedBlockError; + if (a_fEffort <= 49.5f) + { + m_boolDone = true; + } + break; + + case 3: + CalculateR11(7, 6.0f, 1.0f); + m_fError = m_fRedBlockError; + break; + + case 4: + CalculateR11(6, 3.0f, 1.0f); + m_fError = m_fRedBlockError; + break; + + case 5: + CalculateR11(5, 1.0f, 0.0f); + m_fError = m_fRedBlockError; + m_boolDone = true; + break; + + default: + assert(0); + break; + } + + m_uiEncodingIterations++; + SetDoneIfPerfect(); + } + + // ---------------------------------------------------------------------------------------------------- + // find the best combination of base color, multiplier and selectors + // + // a_uiSelectorsUsed limits the number of selector combinations to try + // a_fBaseRadius limits the range of base colors to try + // a_fMultiplierRadius limits the range of multipliers to try + // + void Block4x4Encoding_R11::CalculateR11(unsigned int a_uiSelectorsUsed, + float a_fBaseRadius, float a_fMultiplierRadius) + { + // maps from virtual (monotonic) selector to ETC selector + static const unsigned int auiVirtualSelectorMap[8] = {3, 2, 1, 0, 4, 5, 6, 7}; + + // find min/max red + float fMinRed = 1.0f; + float fMaxRed = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + // ignore border pixels + float fAlpha = m_pafrgbaSource[uiPixel].fA; + if (isnan(fAlpha)) + { + continue; + } + + float fRed = m_pafrgbaSource[uiPixel].fR; + + if (fRed < fMinRed) + { + fMinRed = fRed; + } + if (fRed > fMaxRed) + { + fMaxRed = fRed; + } + } + assert(fMinRed <= fMaxRed); + + float fRedRange = (fMaxRed - fMinRed); + + // try each modifier table entry + for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++) + { + for (unsigned int uiMinVirtualSelector = 0; + uiMinVirtualSelector <= (8- a_uiSelectorsUsed); + uiMinVirtualSelector++) + { + unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1; + + unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector]; + unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector]; + + float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector]; + + float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] - + s_aafModifierTable[uiTableEntry][uiMinSelector]; + + float fCenterRatio = fTableEntryCenter / fTableEntryRange; + + float fCenter = fMinRed + fCenterRatio*fRedRange; + fCenter = roundf(255.0f * fCenter) / 255.0f; + + float fMinBase = fCenter - (a_fBaseRadius / 255.0f); + if (fMinBase < 0.0f) + { + fMinBase = 0.0f; + } + + float fMaxBase = fCenter + (a_fBaseRadius / 255.0f); + if (fMaxBase > 1.0f) + { + fMaxBase = 1.0f; + } + + for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f)) + { + float fRangeMultiplier = roundf(fRedRange / fTableEntryRange); + + float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius; + if (fMinMultiplier < 1.0f) + { + fMinMultiplier = 0.0f; + } + else if (fMinMultiplier > 15.0f) + { + fMinMultiplier = 15.0f; + } + + float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius; + if (fMaxMultiplier < 1.0f) + { + fMaxMultiplier = 1.0f; + } + else if (fMaxMultiplier > 15.0f) + { + fMaxMultiplier = 15.0f; + } + + for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f) + { + // find best selector for each pixel + unsigned int auiBestSelectors[PIXELS]; + float afBestRedError[PIXELS]; + float afBestPixelRed[PIXELS]; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + float fBestPixelRedError = FLT_MAX; + + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + float fPixelRed = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector); + + ColorFloatRGBA frgba(fPixelRed, m_pafrgbaSource[uiPixel].fG,0.0f,1.0f); + + float fPixelRedError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]); + + if (fPixelRedError < fBestPixelRedError) + { + fBestPixelRedError = fPixelRedError; + auiBestSelectors[uiPixel] = uiSelector; + afBestRedError[uiPixel] = fBestPixelRedError; + afBestPixelRed[uiPixel] = fPixelRed; + } + } + } + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestRedError[uiPixel]; + } + if (fBlockError < m_fRedBlockError) + { + m_fRedBlockError = fBlockError; + + if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + m_fRedBase = 255.0f * fBase; + } + else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_fRedBase = (fBase * 255) - 128; + } + else + { + assert(0); + } + m_fRedMultiplier = fMultiplier; + m_uiRedModifierTableIndex = uiTableEntry; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiRedSelectors[uiPixel] = auiBestSelectors[uiPixel]; + float fBestPixelRed = afBestPixelRed[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fBestPixelRed, 0.0f, 0.0f, 1.0f); + m_afDecodedAlphas[uiPixel] = 1.0f; + } + } + } + } + + } + } + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_R11::SetEncodingBits(void) + { + if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + m_pencodingbitsR11->data.base = (unsigned char)roundf(m_fRedBase); + } + else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_pencodingbitsR11->data.base = (signed char)roundf(m_fRedBase); + } + else + { + assert(0); + } + m_pencodingbitsR11->data.table = m_uiRedModifierTableIndex; + m_pencodingbitsR11->data.multiplier = (unsigned char)roundf(m_fRedMultiplier); + + unsigned long long int ulliSelectorBits = 0; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiShift = 45 - (3 * uiPixel); + ulliSelectorBits |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift; + } + + m_pencodingbitsR11->data.selectors0 = ulliSelectorBits >> 40; + m_pencodingbitsR11->data.selectors1 = ulliSelectorBits >> 32; + m_pencodingbitsR11->data.selectors2 = ulliSelectorBits >> 24; + m_pencodingbitsR11->data.selectors3 = ulliSelectorBits >> 16; + m_pencodingbitsR11->data.selectors4 = ulliSelectorBits >> 8; + m_pencodingbitsR11->data.selectors5 = ulliSelectorBits; + } + + // ---------------------------------------------------------------------------------------------------- + // +} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h new file mode 100644 index 0000000000..b40c1e0036 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h @@ -0,0 +1,122 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcBlock4x4Encoding_RGB8.h" + +namespace Etc +{ + class Block4x4EncodingBits_R11; + + // ################################################################################ + // Block4x4Encoding_R11 + // ################################################################################ + + class Block4x4Encoding_R11 : public Block4x4Encoding_RGB8 + { + public: + + Block4x4Encoding_R11(void); + virtual ~Block4x4Encoding_R11(void); + + virtual void InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric); + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric); + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + inline float GetRedBase(void) const + { + return m_fRedBase; + } + + inline float GetRedMultiplier(void) const + { + return m_fRedMultiplier; + } + + inline int GetRedTableIndex(void) const + { + return m_uiRedModifierTableIndex; + } + + inline const unsigned int * GetRedSelectors(void) const + { + return m_auiRedSelectors; + } + + protected: + + static const unsigned int MODIFIER_TABLE_ENTRYS = 16; + static const unsigned int SELECTOR_BITS = 3; + static const unsigned int SELECTORS = 1 << SELECTOR_BITS; + + static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS]; + + void CalculateR11(unsigned int a_uiSelectorsUsed, + float a_fBaseRadius, float a_fMultiplierRadius); + + + + + inline float DecodePixelRed(float a_fBase, float a_fMultiplier, + unsigned int a_uiTableIndex, unsigned int a_uiSelector) + { + float fMultiplier = a_fMultiplier; + if (fMultiplier <= 0.0f) + { + fMultiplier = 1.0f / 8.0f; + } + + float fPixelRed = a_fBase * 8 + 4 + + 8 * fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]*255; + fPixelRed /= 2047.0f; + + if (fPixelRed < 0.0f) + { + fPixelRed = 0.0f; + } + else if (fPixelRed > 1.0f) + { + fPixelRed = 1.0f; + } + + return fPixelRed; + } + + Block4x4EncodingBits_R11 *m_pencodingbitsR11; + + float m_fRedBase; + float m_fRedMultiplier; + float m_fRedBlockError; + unsigned int m_uiRedModifierTableIndex; + unsigned int m_auiRedSelectors[PIXELS]; + + + }; + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp new file mode 100644 index 0000000000..417835db51 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp @@ -0,0 +1,447 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding_RG11.cpp + +Block4x4Encoding_RG11 is the encoder to use when targetting file format RG11 and SRG11 (signed RG11). + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding_RG11.h" + +#include "EtcBlock4x4EncodingBits.h" +#include "EtcBlock4x4.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <float.h> +#include <limits> + +namespace Etc +{ + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding_RG11::Block4x4Encoding_RG11(void) + { + m_pencodingbitsRG11 = nullptr; + } + + Block4x4Encoding_RG11::~Block4x4Encoding_RG11(void) {} + // ---------------------------------------------------------------------------------------------------- + // initialization prior to encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits + // + void Block4x4Encoding_RG11::InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) + { + Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); + + m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits; + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits of a previous encoding + // + void Block4x4Encoding_RG11::InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + + m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits; + + // init RGB portion + Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent, + (unsigned char *)m_pencodingbitsRG11, + a_pafrgbaSource, + a_errormetric); + m_fError = 0.0f; + + { + m_mode = MODE_RG11; + if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_fRedBase = (float)(signed char)m_pencodingbitsRG11->data.baseR; + m_fGrnBase = (float)(signed char)m_pencodingbitsRG11->data.baseG; + } + else + { + m_fRedBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseR; + m_fGrnBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseG; + } + m_fRedMultiplier = (float)m_pencodingbitsRG11->data.multiplierR; + m_fGrnMultiplier = (float)m_pencodingbitsRG11->data.multiplierG; + m_uiRedModifierTableIndex = m_pencodingbitsRG11->data.tableIndexR; + m_uiGrnModifierTableIndex = m_pencodingbitsRG11->data.tableIndexG; + + unsigned long long int ulliSelectorBitsR = 0; + ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR0 << 40; + ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR1 << 32; + ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR2 << 24; + ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR3 << 16; + ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR4 << 8; + ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR5; + + unsigned long long int ulliSelectorBitsG = 0; + ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG0 << 40; + ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG1 << 32; + ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG2 << 24; + ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG3 << 16; + ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG4 << 8; + ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG5; + + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiShift = 45 - (3 * uiPixel); + m_auiRedSelectors[uiPixel] = (ulliSelectorBitsR >> uiShift) & (SELECTORS - 1); + m_auiGrnSelectors[uiPixel] = (ulliSelectorBitsG >> uiShift) & (SELECTORS - 1); + } + + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + float fRedDecodedData = 0.0f; + float fGrnDecodedData = 0.0f; + if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + fRedDecodedData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]); + fGrnDecodedData = DecodePixelRed(m_fGrnBase, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]); + } + else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + fRedDecodedData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]); + fGrnDecodedData = DecodePixelRed(m_fGrnBase + 128, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]); + } + else + { + assert(0); + } + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fRedDecodedData, fGrnDecodedData, 0.0f, 1.0f); + } + + } + + CalcBlockError(); + } + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_RG11::PerformIteration(float a_fEffort) + { + assert(!m_boolDone); + + switch (m_uiEncodingIterations) + { + case 0: + m_fError = FLT_MAX; + m_fGrnBlockError = FLT_MAX; // artificially high value + m_fRedBlockError = FLT_MAX; + CalculateR11(8, 0.0f, 0.0f); + CalculateG11(8, 0.0f, 0.0f); + m_fError = (m_fGrnBlockError + m_fRedBlockError); + break; + + case 1: + CalculateR11(8, 2.0f, 1.0f); + CalculateG11(8, 2.0f, 1.0f); + m_fError = (m_fGrnBlockError + m_fRedBlockError); + if (a_fEffort <= 24.5f) + { + m_boolDone = true; + } + break; + + case 2: + CalculateR11(8, 12.0f, 1.0f); + CalculateG11(8, 12.0f, 1.0f); + m_fError = (m_fGrnBlockError + m_fRedBlockError); + if (a_fEffort <= 49.5f) + { + m_boolDone = true; + } + break; + + case 3: + CalculateR11(7, 6.0f, 1.0f); + CalculateG11(7, 6.0f, 1.0f); + m_fError = (m_fGrnBlockError + m_fRedBlockError); + break; + + case 4: + CalculateR11(6, 3.0f, 1.0f); + CalculateG11(6, 3.0f, 1.0f); + m_fError = (m_fGrnBlockError + m_fRedBlockError); + break; + + case 5: + CalculateR11(5, 1.0f, 0.0f); + CalculateG11(5, 1.0f, 0.0f); + m_fError = (m_fGrnBlockError + m_fRedBlockError); + m_boolDone = true; + break; + + default: + assert(0); + break; + } + + m_uiEncodingIterations++; + SetDoneIfPerfect(); + } + + // ---------------------------------------------------------------------------------------------------- + // find the best combination of base color, multiplier and selectors + // + // a_uiSelectorsUsed limits the number of selector combinations to try + // a_fBaseRadius limits the range of base colors to try + // a_fMultiplierRadius limits the range of multipliers to try + // + void Block4x4Encoding_RG11::CalculateG11(unsigned int a_uiSelectorsUsed, + float a_fBaseRadius, float a_fMultiplierRadius) + { + // maps from virtual (monotonic) selector to etc selector + static const unsigned int auiVirtualSelectorMap[8] = { 3, 2, 1, 0, 4, 5, 6, 7 }; + + // find min/max Grn + float fMinGrn = 1.0f; + float fMaxGrn = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + // ignore border pixels + float fAlpha = m_pafrgbaSource[uiPixel].fA; + if (isnan(fAlpha)) + { + continue; + } + + float fGrn = m_pafrgbaSource[uiPixel].fG; + + if (fGrn < fMinGrn) + { + fMinGrn = fGrn; + } + if (fGrn > fMaxGrn) + { + fMaxGrn = fGrn; + } + } + assert(fMinGrn <= fMaxGrn); + + float fGrnRange = (fMaxGrn - fMinGrn); + + // try each modifier table entry + for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++) + { + for (unsigned int uiMinVirtualSelector = 0; + uiMinVirtualSelector <= (8 - a_uiSelectorsUsed); + uiMinVirtualSelector++) + { + unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1; + + unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector]; + unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector]; + + float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector]; + + float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] - + s_aafModifierTable[uiTableEntry][uiMinSelector]; + + float fCenterRatio = fTableEntryCenter / fTableEntryRange; + + float fCenter = fMinGrn + fCenterRatio*fGrnRange; + fCenter = roundf(255.0f * fCenter) / 255.0f; + + float fMinBase = fCenter - (a_fBaseRadius / 255.0f); + if (fMinBase < 0.0f) + { + fMinBase = 0.0f; + } + + float fMaxBase = fCenter + (a_fBaseRadius / 255.0f); + if (fMaxBase > 1.0f) + { + fMaxBase = 1.0f; + } + + for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f)) + { + float fRangeMultiplier = roundf(fGrnRange / fTableEntryRange); + + float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius; + if (fMinMultiplier < 1.0f) + { + fMinMultiplier = 0.0f; + } + else if (fMinMultiplier > 15.0f) + { + fMinMultiplier = 15.0f; + } + + float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius; + if (fMaxMultiplier < 1.0f) + { + fMaxMultiplier = 1.0f; + } + else if (fMaxMultiplier > 15.0f) + { + fMaxMultiplier = 15.0f; + } + + for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f) + { + // find best selector for each pixel + unsigned int auiBestSelectors[PIXELS]; + float afBestGrnError[PIXELS]; + float afBestPixelGrn[PIXELS]; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + float fBestPixelGrnError = FLT_MAX; + + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + //DecodePixelRed is not red channel specific + float fPixelGrn = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector); + + ColorFloatRGBA frgba(m_pafrgbaSource[uiPixel].fR, fPixelGrn, 0.0f, 1.0f); + + float fPixelGrnError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]); + + if (fPixelGrnError < fBestPixelGrnError) + { + fBestPixelGrnError = fPixelGrnError; + auiBestSelectors[uiPixel] = uiSelector; + afBestGrnError[uiPixel] = fBestPixelGrnError; + afBestPixelGrn[uiPixel] = fPixelGrn; + } + } + } + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestGrnError[uiPixel]; + } + + if (fBlockError < m_fGrnBlockError) + { + m_fGrnBlockError = fBlockError; + + if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + m_fGrnBase = 255.0f * fBase; + } + else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_fGrnBase = (fBase * 255) - 128; + } + else + { + assert(0); + } + m_fGrnMultiplier = fMultiplier; + m_uiGrnModifierTableIndex = uiTableEntry; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiGrnSelectors[uiPixel] = auiBestSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel].fG = afBestPixelGrn[uiPixel]; + m_afDecodedAlphas[uiPixel] = 1.0f; + } + } + } + } + + } + } + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_RG11::SetEncodingBits(void) + { + unsigned long long int ulliSelectorBitsR = 0; + unsigned long long int ulliSelectorBitsG = 0; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiShift = 45 - (3 * uiPixel); + ulliSelectorBitsR |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift; + ulliSelectorBitsG |= ((unsigned long long int)m_auiGrnSelectors[uiPixel]) << uiShift; + } + if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + m_pencodingbitsRG11->data.baseR = (unsigned char)roundf(m_fRedBase); + } + else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_pencodingbitsRG11->data.baseR = (signed char)roundf(m_fRedBase); + } + else + { + assert(0); + } + m_pencodingbitsRG11->data.tableIndexR = m_uiRedModifierTableIndex; + m_pencodingbitsRG11->data.multiplierR = (unsigned char)roundf(m_fRedMultiplier); + + m_pencodingbitsRG11->data.selectorsR0 = ulliSelectorBitsR >> 40; + m_pencodingbitsRG11->data.selectorsR1 = ulliSelectorBitsR >> 32; + m_pencodingbitsRG11->data.selectorsR2 = ulliSelectorBitsR >> 24; + m_pencodingbitsRG11->data.selectorsR3 = ulliSelectorBitsR >> 16; + m_pencodingbitsRG11->data.selectorsR4 = ulliSelectorBitsR >> 8; + m_pencodingbitsRG11->data.selectorsR5 = ulliSelectorBitsR; + + if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) + { + m_pencodingbitsRG11->data.baseG = (unsigned char)roundf(m_fGrnBase); + } + else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) + { + m_pencodingbitsRG11->data.baseG = (signed char)roundf(m_fGrnBase); + } + else + { + assert(0); + } + m_pencodingbitsRG11->data.tableIndexG = m_uiGrnModifierTableIndex; + m_pencodingbitsRG11->data.multiplierG = (unsigned char)roundf(m_fGrnMultiplier); + + m_pencodingbitsRG11->data.selectorsG0 = ulliSelectorBitsG >> 40; + m_pencodingbitsRG11->data.selectorsG1 = ulliSelectorBitsG >> 32; + m_pencodingbitsRG11->data.selectorsG2 = ulliSelectorBitsG >> 24; + m_pencodingbitsRG11->data.selectorsG3 = ulliSelectorBitsG >> 16; + m_pencodingbitsRG11->data.selectorsG4 = ulliSelectorBitsG >> 8; + m_pencodingbitsRG11->data.selectorsG5 = ulliSelectorBitsG; + + } + + // ---------------------------------------------------------------------------------------------------- + // +} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h new file mode 100644 index 0000000000..d4993b8c5f --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h @@ -0,0 +1,86 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcBlock4x4Encoding_RGB8.h" +#include "EtcBlock4x4Encoding_R11.h" + +namespace Etc +{ + class Block4x4EncodingBits_RG11; + + // ################################################################################ + // Block4x4Encoding_RG11 + // ################################################################################ + + class Block4x4Encoding_RG11 : public Block4x4Encoding_R11 + { + float m_fGrnBase; + float m_fGrnMultiplier; + float m_fGrnBlockError; + unsigned int m_auiGrnSelectors[PIXELS]; + unsigned int m_uiGrnModifierTableIndex; + public: + + Block4x4Encoding_RG11(void); + virtual ~Block4x4Encoding_RG11(void); + + virtual void InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric); + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + + ErrorMetric a_errormetric); + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + Block4x4EncodingBits_RG11 *m_pencodingbitsRG11; + + void CalculateG11(unsigned int a_uiSelectorsUsed, float a_fBaseRadius, float a_fMultiplierRadius); + + inline float GetGrnBase(void) const + { + return m_fGrnBase; + } + + inline float GetGrnMultiplier(void) const + { + return m_fGrnMultiplier; + } + + inline int GetGrnTableIndex(void) const + { + return m_uiGrnModifierTableIndex; + } + + inline const unsigned int * GetGrnSelectors(void) const + { + return m_auiGrnSelectors; + } + + }; + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp new file mode 100644 index 0000000000..5656556db9 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp @@ -0,0 +1,1730 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding_RGB8.cpp + +Block4x4Encoding_RGB8 is the encoder to use for the ETC2 extensions when targetting file format RGB8. +This encoder is also used for the ETC2 subset of file format RGBA8. + +Block4x4Encoding_ETC1 encodes the ETC1 subset of RGB8. + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding_RGB8.h" + +#include "EtcBlock4x4EncodingBits.h" +#include "EtcBlock4x4.h" +#include "EtcMath.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <float.h> +#include <limits> + +namespace Etc +{ + float Block4x4Encoding_RGB8::s_afTHDistanceTable[TH_DISTANCES] = + { + 3.0f / 255.0f, + 6.0f / 255.0f, + 11.0f / 255.0f, + 16.0f / 255.0f, + 23.0f / 255.0f, + 32.0f / 255.0f, + 41.0f / 255.0f, + 64.0f / 255.0f + }; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding_RGB8::Block4x4Encoding_RGB8(void) + { + + m_pencodingbitsRGB8 = nullptr; + + } + + Block4x4Encoding_RGB8::~Block4x4Encoding_RGB8(void) {} + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits of a previous encoding + // + void Block4x4Encoding_RGB8::InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + + // handle ETC1 modes + Block4x4Encoding_ETC1::InitFromEncodingBits(a_pblockParent, + a_paucEncodingBits, a_pafrgbaSource,a_errormetric); + + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; + + // detect if there is a T, H or Planar mode present + if (m_pencodingbitsRGB8->differential.diff) + { + int iRed1 = (int)m_pencodingbitsRGB8->differential.red1; + int iDRed2 = m_pencodingbitsRGB8->differential.dred2; + int iRed2 = iRed1 + iDRed2; + + int iGreen1 = (int)m_pencodingbitsRGB8->differential.green1; + int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2; + int iGreen2 = iGreen1 + iDGreen2; + + int iBlue1 = (int)m_pencodingbitsRGB8->differential.blue1; + int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2; + int iBlue2 = iBlue1 + iDBlue2; + + if (iRed2 < 0 || iRed2 > 31) + { + InitFromEncodingBits_T(); + } + else if (iGreen2 < 0 || iGreen2 > 31) + { + InitFromEncodingBits_H(); + } + else if (iBlue2 < 0 || iBlue2 > 31) + { + InitFromEncodingBits_Planar(); + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding if T mode is detected + // + void Block4x4Encoding_RGB8::InitFromEncodingBits_T(void) + { + + m_mode = MODE_T; + + unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) + + m_pencodingbitsRGB8->t.red1b); + unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1; + unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1; + + unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2; + unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2; + unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2; + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); + + m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db; + + Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); + + DecodePixels_T(); + + CalcBlockError(); + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding if H mode is detected + // + void Block4x4Encoding_RGB8::InitFromEncodingBits_H(void) + { + + m_mode = MODE_H; + + unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1; + unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) + + m_pencodingbitsRGB8->h.green1b); + unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) + + (m_pencodingbitsRGB8->h.blue1b << 1) + + m_pencodingbitsRGB8->h.blue1c); + + unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2; + unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) + + m_pencodingbitsRGB8->h.green2b); + unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2; + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); + + // used to determine the LSB of the CW + unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1); + unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2); + + m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1); + if (uiRGB1 >= uiRGB2) + { + m_uiCW1++; + } + + Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); + + DecodePixels_H(); + + CalcBlockError(); + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding if Planar mode is detected + // + void Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(void) + { + + m_mode = MODE_PLANAR; + + unsigned char ucOriginRed = m_pencodingbitsRGB8->planar.originRed; + unsigned char ucOriginGreen = (unsigned char)((m_pencodingbitsRGB8->planar.originGreen1 << 6) + + m_pencodingbitsRGB8->planar.originGreen2); + unsigned char ucOriginBlue = (unsigned char)((m_pencodingbitsRGB8->planar.originBlue1 << 5) + + (m_pencodingbitsRGB8->planar.originBlue2 << 3) + + (m_pencodingbitsRGB8->planar.originBlue3 << 1) + + m_pencodingbitsRGB8->planar.originBlue4); + + unsigned char ucHorizRed = (unsigned char)((m_pencodingbitsRGB8->planar.horizRed1 << 1) + + m_pencodingbitsRGB8->planar.horizRed2); + unsigned char ucHorizGreen = m_pencodingbitsRGB8->planar.horizGreen; + unsigned char ucHorizBlue = (unsigned char)((m_pencodingbitsRGB8->planar.horizBlue1 << 5) + + m_pencodingbitsRGB8->planar.horizBlue2); + + unsigned char ucVertRed = (unsigned char)((m_pencodingbitsRGB8->planar.vertRed1 << 3) + + m_pencodingbitsRGB8->planar.vertRed2); + unsigned char ucVertGreen = (unsigned char)((m_pencodingbitsRGB8->planar.vertGreen1 << 2) + + m_pencodingbitsRGB8->planar.vertGreen2); + unsigned char ucVertBlue = m_pencodingbitsRGB8->planar.vertBlue; + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromR6G7B6(ucOriginRed, ucOriginGreen, ucOriginBlue); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromR6G7B6(ucHorizRed, ucHorizGreen, ucHorizBlue); + m_frgbaColor3 = ColorFloatRGBA::ConvertFromR6G7B6(ucVertRed, ucVertGreen, ucVertBlue); + + DecodePixels_Planar(); + + CalcBlockError(); + + } + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_RGB8::PerformIteration(float a_fEffort) + { + assert(!m_boolDone); + + switch (m_uiEncodingIterations) + { + case 0: + Block4x4Encoding_ETC1::PerformFirstIteration(); + if (m_boolDone) + { + break; + } + TryPlanar(0); + SetDoneIfPerfect(); + if (m_boolDone) + { + break; + } + TryTAndH(0); + break; + + case 1: + Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); + break; + + case 2: + Block4x4Encoding_ETC1::TryIndividual(m_boolMostLikelyFlip, 1); + break; + + case 3: + Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); + break; + + case 4: + Block4x4Encoding_ETC1::TryIndividual(!m_boolMostLikelyFlip, 1); + break; + + case 5: + TryPlanar(1); + if (a_fEffort <= 49.5f) + { + m_boolDone = true; + } + break; + + case 6: + TryTAndH(1); + if (a_fEffort <= 59.5f) + { + m_boolDone = true; + } + break; + + case 7: + Block4x4Encoding_ETC1::TryDegenerates1(); + if (a_fEffort <= 69.5f) + { + m_boolDone = true; + } + break; + + case 8: + Block4x4Encoding_ETC1::TryDegenerates2(); + if (a_fEffort <= 79.5f) + { + m_boolDone = true; + } + break; + + case 9: + Block4x4Encoding_ETC1::TryDegenerates3(); + if (a_fEffort <= 89.5f) + { + m_boolDone = true; + } + break; + + case 10: + Block4x4Encoding_ETC1::TryDegenerates4(); + m_boolDone = true; + break; + + default: + assert(0); + break; + } + + m_uiEncodingIterations++; + + SetDoneIfPerfect(); + } + + // ---------------------------------------------------------------------------------------------------- + // try encoding in Planar mode + // save this encoding if it improves the error + // + void Block4x4Encoding_RGB8::TryPlanar(unsigned int a_uiRadius) + { + Block4x4Encoding_RGB8 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_PLANAR; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + } + + encodingTry.CalculatePlanarCornerColors(); + + encodingTry.DecodePixels_Planar(); + + encodingTry.CalcBlockError(); + + if (a_uiRadius > 0) + { + encodingTry.TwiddlePlanar(); + } + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_PLANAR; + m_boolDiff = true; + m_boolFlip = false; + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_frgbaColor3 = encodingTry.m_frgbaColor3; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try encoding in T mode or H mode + // save this encoding if it improves the error + // + void Block4x4Encoding_RGB8::TryTAndH(unsigned int a_uiRadius) + { + + CalculateBaseColorsForTAndH(); + + TryT(a_uiRadius); + + TryH(a_uiRadius); + + } + + // ---------------------------------------------------------------------------------------------------- + // calculate original values for base colors + // store them in m_frgbaOriginalColor1 and m_frgbaOriginalColor2 + // + void Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(void) + { + + bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX; + + ColorFloatRGBA frgbaBlockAverage = (m_frgbaSourceAverageLeft + m_frgbaSourceAverageRight) * 0.5f; + + // find pixel farthest from average gray line + unsigned int uiFarthestPixel = 0; + float fFarthestGrayDistance2 = 0.0f; + unsigned int uiTransparentPixels = 0; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + // don't count transparent + if (m_pafrgbaSource[uiPixel].fA == 0.0f && !boolRGBX) + { + uiTransparentPixels++; + } + else + { + float fGrayDistance2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], frgbaBlockAverage); + + if (fGrayDistance2 > fFarthestGrayDistance2) + { + uiFarthestPixel = uiPixel; + fFarthestGrayDistance2 = fGrayDistance2; + } + } + } + // a transparent block should not reach this method + assert(uiTransparentPixels < PIXELS); + + // set the original base colors to: + // half way to the farthest pixel and + // the mirror color on the other side of the average + ColorFloatRGBA frgbaOffset = (m_pafrgbaSource[uiFarthestPixel] - frgbaBlockAverage) * 0.5f; + m_frgbaOriginalColor1_TAndH = (frgbaBlockAverage + frgbaOffset).QuantizeR4G4B4(); + m_frgbaOriginalColor2_TAndH = (frgbaBlockAverage - frgbaOffset).ClampRGB().QuantizeR4G4B4(); // the "other side" might be out of range + + // move base colors to find best fit + for (unsigned int uiIteration = 0; uiIteration < 10; uiIteration++) + { + // find the center of pixels closest to each color + float fPixelsCloserToColor1 = 0.0f; + ColorFloatRGBA frgbSumPixelsCloserToColor1; + float fPixelsCloserToColor2 = 0.0f; + ColorFloatRGBA frgbSumPixelsCloserToColor2; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + // don't count transparent pixels + if (m_pafrgbaSource[uiPixel].fA == 0.0f) + { + continue; + } + + float fGrayDistance2ToColor1 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor1_TAndH); + float fGrayDistance2ToColor2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor2_TAndH); + + ColorFloatRGBA frgbaAlphaWeightedSource = m_pafrgbaSource[uiPixel] * m_pafrgbaSource[uiPixel].fA; + + if (fGrayDistance2ToColor1 <= fGrayDistance2ToColor2) + { + fPixelsCloserToColor1 += m_pafrgbaSource[uiPixel].fA; + frgbSumPixelsCloserToColor1 = frgbSumPixelsCloserToColor1 + frgbaAlphaWeightedSource; + } + else + { + fPixelsCloserToColor2 += m_pafrgbaSource[uiPixel].fA; + frgbSumPixelsCloserToColor2 = frgbSumPixelsCloserToColor2 + frgbaAlphaWeightedSource; + } + } + if (fPixelsCloserToColor1 == 0.0f || fPixelsCloserToColor2 == 0.0f) + { + break; + } + + ColorFloatRGBA frgbAvgColor1Pixels = (frgbSumPixelsCloserToColor1 * (1.0f / fPixelsCloserToColor1)).QuantizeR4G4B4(); + ColorFloatRGBA frgbAvgColor2Pixels = (frgbSumPixelsCloserToColor2 * (1.0f / fPixelsCloserToColor2)).QuantizeR4G4B4(); + + if (frgbAvgColor1Pixels.fR == m_frgbaOriginalColor1_TAndH.fR && + frgbAvgColor1Pixels.fG == m_frgbaOriginalColor1_TAndH.fG && + frgbAvgColor1Pixels.fB == m_frgbaOriginalColor1_TAndH.fB && + frgbAvgColor2Pixels.fR == m_frgbaOriginalColor2_TAndH.fR && + frgbAvgColor2Pixels.fG == m_frgbaOriginalColor2_TAndH.fG && + frgbAvgColor2Pixels.fB == m_frgbaOriginalColor2_TAndH.fB) + { + break; + } + + m_frgbaOriginalColor1_TAndH = frgbAvgColor1Pixels; + m_frgbaOriginalColor2_TAndH = frgbAvgColor2Pixels; + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try encoding in T mode + // save this encoding if it improves the error + // + // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently + // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower + // + void Block4x4Encoding_RGB8::TryT(unsigned int a_uiRadius) + { + Block4x4Encoding_RGB8 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_T; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + encodingTry.m_fError = FLT_MAX; + } + + int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); + int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); + int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); + + int iMinRed1 = iColor1Red - (int)a_uiRadius; + if (iMinRed1 < 0) + { + iMinRed1 = 0; + } + int iMaxRed1 = iColor1Red + (int)a_uiRadius; + if (iMaxRed1 > 15) + { + iMinRed1 = 15; + } + + int iMinGreen1 = iColor1Green - (int)a_uiRadius; + if (iMinGreen1 < 0) + { + iMinGreen1 = 0; + } + int iMaxGreen1 = iColor1Green + (int)a_uiRadius; + if (iMaxGreen1 > 15) + { + iMinGreen1 = 15; + } + + int iMinBlue1 = iColor1Blue - (int)a_uiRadius; + if (iMinBlue1 < 0) + { + iMinBlue1 = 0; + } + int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; + if (iMaxBlue1 > 15) + { + iMinBlue1 = 15; + } + + int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); + int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); + int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); + + int iMinRed2 = iColor2Red - (int)a_uiRadius; + if (iMinRed2 < 0) + { + iMinRed2 = 0; + } + int iMaxRed2 = iColor2Red + (int)a_uiRadius; + if (iMaxRed2 > 15) + { + iMinRed2 = 15; + } + + int iMinGreen2 = iColor2Green - (int)a_uiRadius; + if (iMinGreen2 < 0) + { + iMinGreen2 = 0; + } + int iMaxGreen2 = iColor2Green + (int)a_uiRadius; + if (iMaxGreen2 > 15) + { + iMinGreen2 = 15; + } + + int iMinBlue2 = iColor2Blue - (int)a_uiRadius; + if (iMinBlue2 < 0) + { + iMinBlue2 = 0; + } + int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; + if (iMaxBlue2 > 15) + { + iMinBlue2 = 15; + } + + for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) + { + encodingTry.m_uiCW1 = uiDistance; + + // twiddle m_frgbaOriginalColor2_TAndH + // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector + // + for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) + { + for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) + { + for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) + { + for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) + { + if (uiBaseColorSwaps == 0) + { + encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; + encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); + } + else + { + encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); + encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH; + } + + encodingTry.TryT_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + } + + // twiddle m_frgbaOriginalColor1_TAndH + for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) + { + for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) + { + for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) + { + for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) + { + if (uiBaseColorSwaps == 0) + { + encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); + encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; + } + else + { + encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH; + encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); + } + + encodingTry.TryT_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // find best selector combination for TryT + // called on an encodingTry + // + void Block4x4Encoding_RGB8::TryT_BestSelectorCombination(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + + unsigned int auiBestPixelSelectors[PIXELS]; + float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; + ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; + + assert(SELECTORS == 4); + afrgbaDecodedPixel[0] = m_frgbaColor1; + afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB(); + afrgbaDecodedPixel[2] = m_frgbaColor2; + afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); + + // try each selector + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + + float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], + m_pafrgbaSource[uiPixel]); + + if (fPixelError < afBestPixelErrors[uiPixel]) + { + afBestPixelErrors[uiPixel] = fPixelError; + auiBestPixelSelectors[uiPixel] = uiSelector; + afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; + } + } + } + + + // add up all of the pixel errors + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestPixelErrors[uiPixel]; + } + + if (fBlockError < m_fError) + { + m_fError = fBlockError; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try encoding in T mode + // save this encoding if it improves the error + // + // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently + // TWIDDLE_RADIUS of 2 is WAY too slow + // + void Block4x4Encoding_RGB8::TryH(unsigned int a_uiRadius) + { + Block4x4Encoding_RGB8 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_H; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + encodingTry.m_fError = FLT_MAX; + } + + int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); + int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); + int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); + + int iMinRed1 = iColor1Red - (int)a_uiRadius; + if (iMinRed1 < 0) + { + iMinRed1 = 0; + } + int iMaxRed1 = iColor1Red + (int)a_uiRadius; + if (iMaxRed1 > 15) + { + iMinRed1 = 15; + } + + int iMinGreen1 = iColor1Green - (int)a_uiRadius; + if (iMinGreen1 < 0) + { + iMinGreen1 = 0; + } + int iMaxGreen1 = iColor1Green + (int)a_uiRadius; + if (iMaxGreen1 > 15) + { + iMinGreen1 = 15; + } + + int iMinBlue1 = iColor1Blue - (int)a_uiRadius; + if (iMinBlue1 < 0) + { + iMinBlue1 = 0; + } + int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; + if (iMaxBlue1 > 15) + { + iMinBlue1 = 15; + } + + int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); + int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); + int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); + + int iMinRed2 = iColor2Red - (int)a_uiRadius; + if (iMinRed2 < 0) + { + iMinRed2 = 0; + } + int iMaxRed2 = iColor2Red + (int)a_uiRadius; + if (iMaxRed2 > 15) + { + iMinRed2 = 15; + } + + int iMinGreen2 = iColor2Green - (int)a_uiRadius; + if (iMinGreen2 < 0) + { + iMinGreen2 = 0; + } + int iMaxGreen2 = iColor2Green + (int)a_uiRadius; + if (iMaxGreen2 > 15) + { + iMinGreen2 = 15; + } + + int iMinBlue2 = iColor2Blue - (int)a_uiRadius; + if (iMinBlue2 < 0) + { + iMinBlue2 = 0; + } + int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; + if (iMaxBlue2 > 15) + { + iMinBlue2 = 15; + } + + for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) + { + encodingTry.m_uiCW1 = uiDistance; + + // twiddle m_frgbaOriginalColor1_TAndH + for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) + { + for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) + { + for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) + { + encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); + encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; + + // if color1 == color2, H encoding issues can pop up, so abort + if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue) + { + continue; + } + + encodingTry.TryH_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + + // twiddle m_frgbaOriginalColor2_TAndH + for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) + { + for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) + { + for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) + { + encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; + encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); + + // if color1 == color2, H encoding issues can pop up, so abort + if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue) + { + continue; + } + + encodingTry.TryH_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // find best selector combination for TryH + // called on an encodingTry + // + void Block4x4Encoding_RGB8::TryH_BestSelectorCombination(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + + unsigned int auiBestPixelSelectors[PIXELS]; + float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; + ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; + + assert(SELECTORS == 4); + afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB(); + afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB(); + afrgbaDecodedPixel[2] = (m_frgbaColor2 + fDistance).ClampRGB(); + afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); + + // try each selector + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + + float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], + m_pafrgbaSource[uiPixel]); + + if (fPixelError < afBestPixelErrors[uiPixel]) + { + afBestPixelErrors[uiPixel] = fPixelError; + auiBestPixelSelectors[uiPixel] = uiSelector; + afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; + } + } + } + + + // add up all of the pixel errors + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestPixelErrors[uiPixel]; + } + + if (fBlockError < m_fError) + { + m_fError = fBlockError; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // use linear regression to find the best fit for colors along the edges of the 4x4 block + // + void Block4x4Encoding_RGB8::CalculatePlanarCornerColors(void) + { + ColorFloatRGBA afrgbaRegression[MAX_PLANAR_REGRESSION_SIZE]; + ColorFloatRGBA frgbaSlope; + ColorFloatRGBA frgbaOffset; + + // top edge + afrgbaRegression[0] = m_pafrgbaSource[0]; + afrgbaRegression[1] = m_pafrgbaSource[4]; + afrgbaRegression[2] = m_pafrgbaSource[8]; + afrgbaRegression[3] = m_pafrgbaSource[12]; + ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); + m_frgbaColor1 = frgbaOffset; + m_frgbaColor2 = (frgbaSlope * 4.0f) + frgbaOffset; + + // left edge + afrgbaRegression[0] = m_pafrgbaSource[0]; + afrgbaRegression[1] = m_pafrgbaSource[1]; + afrgbaRegression[2] = m_pafrgbaSource[2]; + afrgbaRegression[3] = m_pafrgbaSource[3]; + ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); + m_frgbaColor1 = (m_frgbaColor1 + frgbaOffset) * 0.5f; // average with top edge + m_frgbaColor3 = (frgbaSlope * 4.0f) + frgbaOffset; + + // right edge + afrgbaRegression[0] = m_pafrgbaSource[12]; + afrgbaRegression[1] = m_pafrgbaSource[13]; + afrgbaRegression[2] = m_pafrgbaSource[14]; + afrgbaRegression[3] = m_pafrgbaSource[15]; + ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); + m_frgbaColor2 = (m_frgbaColor2 + frgbaOffset) * 0.5f; // average with top edge + + // bottom edge + afrgbaRegression[0] = m_pafrgbaSource[3]; + afrgbaRegression[1] = m_pafrgbaSource[7]; + afrgbaRegression[2] = m_pafrgbaSource[11]; + afrgbaRegression[3] = m_pafrgbaSource[15]; + ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); + m_frgbaColor3 = (m_frgbaColor3 + frgbaOffset) * 0.5f; // average with left edge + + // quantize corner colors to 6/7/6 + m_frgbaColor1 = m_frgbaColor1.QuantizeR6G7B6(); + m_frgbaColor2 = m_frgbaColor2.QuantizeR6G7B6(); + m_frgbaColor3 = m_frgbaColor3.QuantizeR6G7B6(); + + } + + // ---------------------------------------------------------------------------------------------------- + // try different corner colors by slightly changing R, G and B independently + // + // R, G and B decoding and errors are independent, so R, G and B twiddles can be independent + // + // return true if improvement + // + bool Block4x4Encoding_RGB8::TwiddlePlanar(void) + { + bool boolImprovement = false; + + while (TwiddlePlanarR()) + { + boolImprovement = true; + } + + while (TwiddlePlanarG()) + { + boolImprovement = true; + } + + while (TwiddlePlanarB()) + { + boolImprovement = true; + } + + return boolImprovement; + } + + // ---------------------------------------------------------------------------------------------------- + // try different corner colors by slightly changing R + // + bool Block4x4Encoding_RGB8::TwiddlePlanarR() + { + bool boolImprovement = false; + + Block4x4Encoding_RGB8 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_PLANAR; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + } + + int iOriginRed = encodingTry.m_frgbaColor1.IntRed(63.0f); + int iHorizRed = encodingTry.m_frgbaColor2.IntRed(63.0f); + int iVertRed = encodingTry.m_frgbaColor3.IntRed(63.0f); + + for (int iTryOriginRed = iOriginRed - 1; iTryOriginRed <= iOriginRed + 1; iTryOriginRed++) + { + // check for out of range + if (iTryOriginRed < 0 || iTryOriginRed > 63) + { + continue; + } + + encodingTry.m_frgbaColor1.fR = ((iTryOriginRed << 2) + (iTryOriginRed >> 4)) / 255.0f; + + for (int iTryHorizRed = iHorizRed - 1; iTryHorizRed <= iHorizRed + 1; iTryHorizRed++) + { + // check for out of range + if (iTryHorizRed < 0 || iTryHorizRed > 63) + { + continue; + } + + encodingTry.m_frgbaColor2.fR = ((iTryHorizRed << 2) + (iTryHorizRed >> 4)) / 255.0f; + + for (int iTryVertRed = iVertRed - 1; iTryVertRed <= iVertRed + 1; iTryVertRed++) + { + // check for out of range + if (iTryVertRed < 0 || iTryVertRed > 63) + { + continue; + } + + // don't bother with null twiddle + if (iTryOriginRed == iOriginRed && iTryHorizRed == iHorizRed && iTryVertRed == iVertRed) + { + continue; + } + + encodingTry.m_frgbaColor3.fR = ((iTryVertRed << 2) + (iTryVertRed >> 4)) / 255.0f; + + encodingTry.DecodePixels_Planar(); + + encodingTry.CalcBlockError(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_PLANAR; + m_boolDiff = true; + m_boolFlip = false; + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_frgbaColor3 = encodingTry.m_frgbaColor3; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + + boolImprovement = true; + } + } + } + } + + return boolImprovement; + } + + // ---------------------------------------------------------------------------------------------------- + // try different corner colors by slightly changing G + // + bool Block4x4Encoding_RGB8::TwiddlePlanarG() + { + bool boolImprovement = false; + + Block4x4Encoding_RGB8 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_PLANAR; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + } + + int iOriginGreen = encodingTry.m_frgbaColor1.IntGreen(127.0f); + int iHorizGreen = encodingTry.m_frgbaColor2.IntGreen(127.0f); + int iVertGreen = encodingTry.m_frgbaColor3.IntGreen(127.0f); + + for (int iTryOriginGreen = iOriginGreen - 1; iTryOriginGreen <= iOriginGreen + 1; iTryOriginGreen++) + { + // check for out of range + if (iTryOriginGreen < 0 || iTryOriginGreen > 127) + { + continue; + } + + encodingTry.m_frgbaColor1.fG = ((iTryOriginGreen << 1) + (iTryOriginGreen >> 6)) / 255.0f; + + for (int iTryHorizGreen = iHorizGreen - 1; iTryHorizGreen <= iHorizGreen + 1; iTryHorizGreen++) + { + // check for out of range + if (iTryHorizGreen < 0 || iTryHorizGreen > 127) + { + continue; + } + + encodingTry.m_frgbaColor2.fG = ((iTryHorizGreen << 1) + (iTryHorizGreen >> 6)) / 255.0f; + + for (int iTryVertGreen = iVertGreen - 1; iTryVertGreen <= iVertGreen + 1; iTryVertGreen++) + { + // check for out of range + if (iTryVertGreen < 0 || iTryVertGreen > 127) + { + continue; + } + + // don't bother with null twiddle + if (iTryOriginGreen == iOriginGreen && + iTryHorizGreen == iHorizGreen && + iTryVertGreen == iVertGreen) + { + continue; + } + + encodingTry.m_frgbaColor3.fG = ((iTryVertGreen << 1) + (iTryVertGreen >> 6)) / 255.0f; + + encodingTry.DecodePixels_Planar(); + + encodingTry.CalcBlockError(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_PLANAR; + m_boolDiff = true; + m_boolFlip = false; + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_frgbaColor3 = encodingTry.m_frgbaColor3; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + + boolImprovement = true; + } + } + } + } + + return boolImprovement; + } + + // ---------------------------------------------------------------------------------------------------- + // try different corner colors by slightly changing B + // + bool Block4x4Encoding_RGB8::TwiddlePlanarB() + { + bool boolImprovement = false; + + Block4x4Encoding_RGB8 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_PLANAR; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + } + + int iOriginBlue = encodingTry.m_frgbaColor1.IntBlue(63.0f); + int iHorizBlue = encodingTry.m_frgbaColor2.IntBlue(63.0f); + int iVertBlue = encodingTry.m_frgbaColor3.IntBlue(63.0f); + + for (int iTryOriginBlue = iOriginBlue - 1; iTryOriginBlue <= iOriginBlue + 1; iTryOriginBlue++) + { + // check for out of range + if (iTryOriginBlue < 0 || iTryOriginBlue > 63) + { + continue; + } + + encodingTry.m_frgbaColor1.fB = ((iTryOriginBlue << 2) + (iTryOriginBlue >> 4)) / 255.0f; + + for (int iTryHorizBlue = iHorizBlue - 1; iTryHorizBlue <= iHorizBlue + 1; iTryHorizBlue++) + { + // check for out of range + if (iTryHorizBlue < 0 || iTryHorizBlue > 63) + { + continue; + } + + encodingTry.m_frgbaColor2.fB = ((iTryHorizBlue << 2) + (iTryHorizBlue >> 4)) / 255.0f; + + for (int iTryVertBlue = iVertBlue - 1; iTryVertBlue <= iVertBlue + 1; iTryVertBlue++) + { + // check for out of range + if (iTryVertBlue < 0 || iTryVertBlue > 63) + { + continue; + } + + // don't bother with null twiddle + if (iTryOriginBlue == iOriginBlue && iTryHorizBlue == iHorizBlue && iTryVertBlue == iVertBlue) + { + continue; + } + + encodingTry.m_frgbaColor3.fB = ((iTryVertBlue << 2) + (iTryVertBlue >> 4)) / 255.0f; + + encodingTry.DecodePixels_Planar(); + + encodingTry.CalcBlockError(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_PLANAR; + m_boolDiff = true; + m_boolFlip = false; + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_frgbaColor3 = encodingTry.m_frgbaColor3; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + + boolImprovement = true; + } + } + } + } + + return boolImprovement; + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_RGB8::SetEncodingBits(void) + { + + switch (m_mode) + { + case MODE_ETC1: + Block4x4Encoding_ETC1::SetEncodingBits(); + break; + + case MODE_T: + SetEncodingBits_T(); + break; + + case MODE_H: + SetEncodingBits_H(); + break; + + case MODE_PLANAR: + SetEncodingBits_Planar(); + break; + + default: + assert(false); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state for T mode + // + void Block4x4Encoding_RGB8::SetEncodingBits_T(void) + { + static const bool SANITY_CHECK = true; + + assert(m_mode == MODE_T); + assert(m_boolDiff == true); + + unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); + unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); + unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); + + unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); + unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); + unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); + + m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2; + m_pencodingbitsRGB8->t.red1b = uiRed1; + m_pencodingbitsRGB8->t.green1 = uiGreen1; + m_pencodingbitsRGB8->t.blue1 = uiBlue1; + + m_pencodingbitsRGB8->t.red2 = uiRed2; + m_pencodingbitsRGB8->t.green2 = uiGreen2; + m_pencodingbitsRGB8->t.blue2 = uiBlue2; + + m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1; + m_pencodingbitsRGB8->t.db = m_uiCW1; + + m_pencodingbitsRGB8->t.diff = 1; + + Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); + + // create an invalid R differential to trigger T mode + m_pencodingbitsRGB8->t.detect1 = 0; + m_pencodingbitsRGB8->t.detect2 = 0; + int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + if (iRed2 >= 4) + { + m_pencodingbitsRGB8->t.detect1 = 7; + m_pencodingbitsRGB8->t.detect2 = 0; + } + else + { + m_pencodingbitsRGB8->t.detect1 = 0; + m_pencodingbitsRGB8->t.detect2 = 1; + } + + if (SANITY_CHECK) + { + iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + + // make sure red overflows + assert(iRed2 < 0 || iRed2 > 31); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state for H mode + // + // colors and selectors may need to swap in order to generate lsb of distance index + // + void Block4x4Encoding_RGB8::SetEncodingBits_H(void) + { + static const bool SANITY_CHECK = true; + + assert(m_mode == MODE_H); + assert(m_boolDiff == true); + + unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); + unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); + unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); + + unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); + unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); + unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); + + unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1; + unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2; + + bool boolOddDistance = m_uiCW1 & 1; + bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance; + + if (boolSwapColors) + { + m_pencodingbitsRGB8->h.red1 = uiRed2; + m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1; + m_pencodingbitsRGB8->h.green1b = uiGreen2; + m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3; + m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1; + m_pencodingbitsRGB8->h.blue1c = uiBlue2; + + m_pencodingbitsRGB8->h.red2 = uiRed1; + m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1; + m_pencodingbitsRGB8->h.green2b = uiGreen1; + m_pencodingbitsRGB8->h.blue2 = uiBlue1; + + m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; + m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; + } + else + { + m_pencodingbitsRGB8->h.red1 = uiRed1; + m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1; + m_pencodingbitsRGB8->h.green1b = uiGreen1; + m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3; + m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1; + m_pencodingbitsRGB8->h.blue1c = uiBlue1; + + m_pencodingbitsRGB8->h.red2 = uiRed2; + m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1; + m_pencodingbitsRGB8->h.green2b = uiGreen2; + m_pencodingbitsRGB8->h.blue2 = uiBlue2; + + m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; + m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; + } + + m_pencodingbitsRGB8->h.diff = 1; + + Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); + + if (boolSwapColors) + { + m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF; + } + + // create an invalid R differential to trigger T mode + m_pencodingbitsRGB8->h.detect1 = 0; + m_pencodingbitsRGB8->h.detect2 = 0; + m_pencodingbitsRGB8->h.detect3 = 0; + int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; + if (iRed2 < 0 || iRed2 > 31) + { + m_pencodingbitsRGB8->h.detect1 = 1; + } + if (iGreen2 >= 4) + { + m_pencodingbitsRGB8->h.detect2 = 7; + m_pencodingbitsRGB8->h.detect3 = 0; + } + else + { + m_pencodingbitsRGB8->h.detect2 = 0; + m_pencodingbitsRGB8->h.detect3 = 1; + } + + if (SANITY_CHECK) + { + iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; + + // make sure red doesn't overflow and green does + assert(iRed2 >= 0 && iRed2 <= 31); + assert(iGreen2 < 0 || iGreen2 > 31); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state for Planar mode + // + void Block4x4Encoding_RGB8::SetEncodingBits_Planar(void) + { + static const bool SANITY_CHECK = true; + + assert(m_mode == MODE_PLANAR); + assert(m_boolDiff == true); + + unsigned int uiOriginRed = (unsigned int)m_frgbaColor1.IntRed(63.0f); + unsigned int uiOriginGreen = (unsigned int)m_frgbaColor1.IntGreen(127.0f); + unsigned int uiOriginBlue = (unsigned int)m_frgbaColor1.IntBlue(63.0f); + + unsigned int uiHorizRed = (unsigned int)m_frgbaColor2.IntRed(63.0f); + unsigned int uiHorizGreen = (unsigned int)m_frgbaColor2.IntGreen(127.0f); + unsigned int uiHorizBlue = (unsigned int)m_frgbaColor2.IntBlue(63.0f); + + unsigned int uiVertRed = (unsigned int)m_frgbaColor3.IntRed(63.0f); + unsigned int uiVertGreen = (unsigned int)m_frgbaColor3.IntGreen(127.0f); + unsigned int uiVertBlue = (unsigned int)m_frgbaColor3.IntBlue(63.0f); + + m_pencodingbitsRGB8->planar.originRed = uiOriginRed; + m_pencodingbitsRGB8->planar.originGreen1 = uiOriginGreen >> 6; + m_pencodingbitsRGB8->planar.originGreen2 = uiOriginGreen; + m_pencodingbitsRGB8->planar.originBlue1 = uiOriginBlue >> 5; + m_pencodingbitsRGB8->planar.originBlue2 = uiOriginBlue >> 3; + m_pencodingbitsRGB8->planar.originBlue3 = uiOriginBlue >> 1; + m_pencodingbitsRGB8->planar.originBlue4 = uiOriginBlue; + + m_pencodingbitsRGB8->planar.horizRed1 = uiHorizRed >> 1; + m_pencodingbitsRGB8->planar.horizRed2 = uiHorizRed; + m_pencodingbitsRGB8->planar.horizGreen = uiHorizGreen; + m_pencodingbitsRGB8->planar.horizBlue1 = uiHorizBlue >> 5; + m_pencodingbitsRGB8->planar.horizBlue2 = uiHorizBlue; + + m_pencodingbitsRGB8->planar.vertRed1 = uiVertRed >> 3; + m_pencodingbitsRGB8->planar.vertRed2 = uiVertRed; + m_pencodingbitsRGB8->planar.vertGreen1 = uiVertGreen >> 2; + m_pencodingbitsRGB8->planar.vertGreen2 = uiVertGreen; + m_pencodingbitsRGB8->planar.vertBlue = uiVertBlue; + + m_pencodingbitsRGB8->planar.diff = 1; + + // create valid RG differentials and an invalid B differential to trigger planar mode + m_pencodingbitsRGB8->planar.detect1 = 0; + m_pencodingbitsRGB8->planar.detect2 = 0; + m_pencodingbitsRGB8->planar.detect3 = 0; + m_pencodingbitsRGB8->planar.detect4 = 0; + int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; + int iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2; + if (iRed2 < 0 || iRed2 > 31) + { + m_pencodingbitsRGB8->planar.detect1 = 1; + } + if (iGreen2 < 0 || iGreen2 > 31) + { + m_pencodingbitsRGB8->planar.detect2 = 1; + } + if (iBlue2 >= 4) + { + m_pencodingbitsRGB8->planar.detect3 = 7; + m_pencodingbitsRGB8->planar.detect4 = 0; + } + else + { + m_pencodingbitsRGB8->planar.detect3 = 0; + m_pencodingbitsRGB8->planar.detect4 = 1; + } + + if (SANITY_CHECK) + { + iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; + iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2; + + // make sure red and green don't overflow and blue does + assert(iRed2 >= 0 && iRed2 <= 31); + assert(iGreen2 >= 0 && iGreen2 <= 31); + assert(iBlue2 < 0 || iBlue2 > 31); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the decoded colors and decoded alpha based on the encoding state for T mode + // + void Block4x4Encoding_RGB8::DecodePixels_T(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + switch (m_auiSelectors[uiPixel]) + { + case 0: + m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1; + break; + + case 1: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); + break; + + case 2: + m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2; + break; + + case 3: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); + break; + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the decoded colors and decoded alpha based on the encoding state for H mode + // + void Block4x4Encoding_RGB8::DecodePixels_H(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + switch (m_auiSelectors[uiPixel]) + { + case 0: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB(); + break; + + case 1: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB(); + break; + + case 2: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); + break; + + case 3: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); + break; + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the decoded colors and decoded alpha based on the encoding state for Planar mode + // + void Block4x4Encoding_RGB8::DecodePixels_Planar(void) + { + + int iRO = (int)roundf(m_frgbaColor1.fR * 255.0f); + int iGO = (int)roundf(m_frgbaColor1.fG * 255.0f); + int iBO = (int)roundf(m_frgbaColor1.fB * 255.0f); + + int iRH = (int)roundf(m_frgbaColor2.fR * 255.0f); + int iGH = (int)roundf(m_frgbaColor2.fG * 255.0f); + int iBH = (int)roundf(m_frgbaColor2.fB * 255.0f); + + int iRV = (int)roundf(m_frgbaColor3.fR * 255.0f); + int iGV = (int)roundf(m_frgbaColor3.fG * 255.0f); + int iBV = (int)roundf(m_frgbaColor3.fB * 255.0f); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + int iX = (int)(uiPixel >> 2); + int iY = (int)(uiPixel & 3); + + int iR = (iX*(iRH - iRO) + iY*(iRV - iRO) + 4*iRO + 2) >> 2; + int iG = (iX*(iGH - iGO) + iY*(iGV - iGO) + 4*iGO + 2) >> 2; + int iB = (iX*(iBH - iBO) + iY*(iBV - iBO) + 4*iBO + 2) >> 2; + + ColorFloatRGBA frgba; + frgba.fR = (float)iR / 255.0f; + frgba.fG = (float)iG / 255.0f; + frgba.fB = (float)iB / 255.0f; + frgba.fA = 1.0f; + + m_afrgbaDecodedColors[uiPixel] = frgba.ClampRGB(); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // perform a linear regression for the a_uiPixels in a_pafrgbaPixels[] + // + // output the closest color line using a_pfrgbaSlope and a_pfrgbaOffset + // + void Block4x4Encoding_RGB8::ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels, + ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset) + { + typedef struct + { + float f[4]; + } Float4; + + Float4 *paf4Pixels = (Float4 *)(a_pafrgbaPixels); + Float4 *pf4Slope = (Float4 *)(a_pfrgbaSlope); + Float4 *pf4Offset = (Float4 *)(a_pfrgbaOffset); + + float afX[MAX_PLANAR_REGRESSION_SIZE]; + float afY[MAX_PLANAR_REGRESSION_SIZE]; + + // handle r, g and b separately. don't bother with a + for (unsigned int uiComponent = 0; uiComponent < 3; uiComponent++) + { + for (unsigned int uiPixel = 0; uiPixel < a_uiPixels; uiPixel++) + { + afX[uiPixel] = (float)uiPixel; + afY[uiPixel] = paf4Pixels[uiPixel].f[uiComponent]; + + } + Etc::Regression(afX, afY, a_uiPixels, + &(pf4Slope->f[uiComponent]), &(pf4Offset->f[uiComponent])); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // +} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h new file mode 100644 index 0000000000..03754d5e3b --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h @@ -0,0 +1,96 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcBlock4x4Encoding_ETC1.h" + +namespace Etc +{ + + class Block4x4Encoding_RGB8 : public Block4x4Encoding_ETC1 + { + public: + + Block4x4Encoding_RGB8(void); + virtual ~Block4x4Encoding_RGB8(void); + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + + ErrorMetric a_errormetric); + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + inline ColorFloatRGBA GetColor3(void) const + { + return m_frgbaColor3; + } + + protected: + + static const unsigned int PLANAR_CORNER_COLORS = 3; + static const unsigned int MAX_PLANAR_REGRESSION_SIZE = 4; + static const unsigned int TH_DISTANCES = 8; + + static float s_afTHDistanceTable[TH_DISTANCES]; + + void TryPlanar(unsigned int a_uiRadius); + void TryTAndH(unsigned int a_uiRadius); + + void InitFromEncodingBits_Planar(void); + + ColorFloatRGBA m_frgbaColor3; // used for planar + + void SetEncodingBits_T(void); + void SetEncodingBits_H(void); + void SetEncodingBits_Planar(void); + + // state shared between iterations + ColorFloatRGBA m_frgbaOriginalColor1_TAndH; + ColorFloatRGBA m_frgbaOriginalColor2_TAndH; + + void CalculateBaseColorsForTAndH(void); + void TryT(unsigned int a_uiRadius); + void TryT_BestSelectorCombination(void); + void TryH(unsigned int a_uiRadius); + void TryH_BestSelectorCombination(void); + + private: + + void InitFromEncodingBits_T(void); + void InitFromEncodingBits_H(void); + + void CalculatePlanarCornerColors(void); + + void ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels, + ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset); + + bool TwiddlePlanar(void); + bool TwiddlePlanarR(); + bool TwiddlePlanarG(); + bool TwiddlePlanarB(); + + void DecodePixels_T(void); + void DecodePixels_H(void); + void DecodePixels_Planar(void); + + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp new file mode 100644 index 0000000000..ba2b42fb05 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp @@ -0,0 +1,1819 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding_RGB8A1.cpp contains: + Block4x4Encoding_RGB8A1 + Block4x4Encoding_RGB8A1_Opaque + Block4x4Encoding_RGB8A1_Transparent + +These encoders are used when targetting file format RGB8A1. + +Block4x4Encoding_RGB8A1_Opaque is used when all pixels in the 4x4 block are opaque +Block4x4Encoding_RGB8A1_Transparent is used when all pixels in the 4x4 block are transparent +Block4x4Encoding_RGB8A1 is used when there is a mixture of alphas in the 4x4 block + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding_RGB8A1.h" + +#include "EtcBlock4x4.h" +#include "EtcBlock4x4EncodingBits.h" +#include "EtcBlock4x4Encoding_RGB8.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +namespace Etc +{ + + // #################################################################################################### + // Block4x4Encoding_RGB8A1 + // #################################################################################################### + + float Block4x4Encoding_RGB8A1::s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS] = + { + { 0.0f / 255.0f, 8.0f / 255.0f, 0.0f / 255.0f, -8.0f / 255.0f }, + { 0.0f / 255.0f, 17.0f / 255.0f, 0.0f / 255.0f, -17.0f / 255.0f }, + { 0.0f / 255.0f, 29.0f / 255.0f, 0.0f / 255.0f, -29.0f / 255.0f }, + { 0.0f / 255.0f, 42.0f / 255.0f, 0.0f / 255.0f, -42.0f / 255.0f }, + { 0.0f / 255.0f, 60.0f / 255.0f, 0.0f / 255.0f, -60.0f / 255.0f }, + { 0.0f / 255.0f, 80.0f / 255.0f, 0.0f / 255.0f, -80.0f / 255.0f }, + { 0.0f / 255.0f, 106.0f / 255.0f, 0.0f / 255.0f, -106.0f / 255.0f }, + { 0.0f / 255.0f, 183.0f / 255.0f, 0.0f / 255.0f, -183.0f / 255.0f } + }; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding_RGB8A1::Block4x4Encoding_RGB8A1(void) + { + m_pencodingbitsRGB8 = nullptr; + m_boolOpaque = false; + m_boolTransparent = false; + m_boolPunchThroughPixels = true; + + } + Block4x4Encoding_RGB8A1::~Block4x4Encoding_RGB8A1(void) {} + // ---------------------------------------------------------------------------------------------------- + // initialization prior to encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits + // + void Block4x4Encoding_RGB8A1::InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, + ErrorMetric a_errormetric) + { + + Block4x4Encoding_RGB8::InitFromSource(a_pblockParent, + a_pafrgbaSource, + a_paucEncodingBits, + a_errormetric); + + m_boolOpaque = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE; + m_boolTransparent = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::TRANSPARENT; + m_boolPunchThroughPixels = a_pblockParent->HasPunchThroughPixels(); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + if (m_pafrgbaSource[uiPixel].fA >= 0.5f) + { + m_afDecodedAlphas[uiPixel] = 1.0f; + } + else + { + m_afDecodedAlphas[uiPixel] = 0.0f; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits of a previous encoding + // + void Block4x4Encoding_RGB8A1::InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + + + InitFromEncodingBits_ETC1(a_pblockParent, + a_paucEncodingBits, + a_pafrgbaSource, + a_errormetric); + + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; + + // detect if there is a T, H or Planar mode present + int iRed1 = m_pencodingbitsRGB8->differential.red1; + int iDRed2 = m_pencodingbitsRGB8->differential.dred2; + int iRed2 = iRed1 + iDRed2; + + int iGreen1 = m_pencodingbitsRGB8->differential.green1; + int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2; + int iGreen2 = iGreen1 + iDGreen2; + + int iBlue1 = m_pencodingbitsRGB8->differential.blue1; + int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2; + int iBlue2 = iBlue1 + iDBlue2; + + if (iRed2 < 0 || iRed2 > 31) + { + InitFromEncodingBits_T(); + } + else if (iGreen2 < 0 || iGreen2 > 31) + { + InitFromEncodingBits_H(); + } + else if (iBlue2 < 0 || iBlue2 > 31) + { + Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding assuming the encoding is an ETC1 mode. + // if it isn't an ETC1 mode, this will be overwritten later + // + void Block4x4Encoding_RGB8A1::InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource, + a_errormetric); + + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; + + m_mode = MODE_ETC1; + m_boolDiff = true; + m_boolFlip = m_pencodingbitsRGB8->differential.flip; + m_boolOpaque = m_pencodingbitsRGB8->differential.diff; + + int iR2 = m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2; + if (iR2 < 0) + { + iR2 = 0; + } + else if (iR2 > 31) + { + iR2 = 31; + } + + int iG2 = m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2; + if (iG2 < 0) + { + iG2 = 0; + } + else if (iG2 > 31) + { + iG2 = 31; + } + + int iB2 = m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2; + if (iB2 < 0) + { + iB2 = 0; + } + else if (iB2 > 31) + { + iB2 = 31; + } + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2); + + m_uiCW1 = m_pencodingbitsRGB8->differential.cw1; + m_uiCW2 = m_pencodingbitsRGB8->differential.cw2; + + Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); + + Decode_ETC1(); + + CalcBlockError(); + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding if T mode is detected + // + void Block4x4Encoding_RGB8A1::InitFromEncodingBits_T(void) + { + m_mode = MODE_T; + + unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) + + m_pencodingbitsRGB8->t.red1b); + unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1; + unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1; + + unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2; + unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2; + unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2; + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); + + m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db; + + Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); + + DecodePixels_T(); + + CalcBlockError(); + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding if H mode is detected + // + void Block4x4Encoding_RGB8A1::InitFromEncodingBits_H(void) + { + m_mode = MODE_H; + + unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1; + unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) + + m_pencodingbitsRGB8->h.green1b); + unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) + + (m_pencodingbitsRGB8->h.blue1b << 1) + + m_pencodingbitsRGB8->h.blue1c); + + unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2; + unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) + + m_pencodingbitsRGB8->h.green2b); + unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2; + + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); + + // used to determine the LSB of the CW + unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1); + unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2); + + m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1); + if (uiRGB1 >= uiRGB2) + { + m_uiCW1++; + } + + Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); + + DecodePixels_H(); + + CalcBlockError(); + } + + // ---------------------------------------------------------------------------------------------------- + // for ETC1 modes, set the decoded colors and decoded alpha based on the encoding state + // + void Block4x4Encoding_RGB8A1::Decode_ETC1(void) + { + + const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0; + + for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++) + { + ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2; + unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2; + + unsigned int uiPixel = pauiPixelOrder[uiPixelOrder]; + + float fDelta; + if (m_boolOpaque) + fDelta = Block4x4Encoding_ETC1::s_aafCwTable[uiCW][m_auiSelectors[uiPixel]]; + else + fDelta = s_aafCwOpaqueUnsetTable[uiCW][m_auiSelectors[uiPixel]]; + + if (m_boolOpaque == false && m_auiSelectors[uiPixel] == TRANSPARENT_SELECTOR) + { + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel] = 0.0f; + } + else + { + m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // for T mode, set the decoded colors and decoded alpha based on the encoding state + // + void Block4x4Encoding_RGB8A1::DecodePixels_T(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + switch (m_auiSelectors[uiPixel]) + { + case 0: + m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1; + m_afDecodedAlphas[uiPixel] = 1.0f; + break; + + case 1: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + break; + + case 2: + if (m_boolOpaque == false) + { + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel] = 0.0f; + } + else + { + m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2; + m_afDecodedAlphas[uiPixel] = 1.0f; + } + break; + + case 3: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + break; + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // for H mode, set the decoded colors and decoded alpha based on the encoding state + // + void Block4x4Encoding_RGB8A1::DecodePixels_H(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + switch (m_auiSelectors[uiPixel]) + { + case 0: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + break; + + case 1: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + break; + + case 2: + if (m_boolOpaque == false) + { + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel] = 0.0f; + } + else + { + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + } + break; + + case 3: + m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); + m_afDecodedAlphas[uiPixel] = 1.0f; + break; + } + + } + + } + + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + // RGB8A1 can't use individual mode + // RGB8A1 with transparent pixels can't use planar mode + // + void Block4x4Encoding_RGB8A1::PerformIteration(float a_fEffort) + { + assert(!m_boolOpaque); + assert(!m_boolTransparent); + assert(!m_boolDone); + + switch (m_uiEncodingIterations) + { + case 0: + PerformFirstIteration(); + break; + + case 1: + TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); + break; + + case 2: + TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); + if (a_fEffort <= 39.5f) + { + m_boolDone = true; + } + break; + + case 3: + Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(); + TryT(1); + TryH(1); + if (a_fEffort <= 49.5f) + { + m_boolDone = true; + } + break; + + case 4: + TryDegenerates1(); + if (a_fEffort <= 59.5f) + { + m_boolDone = true; + } + break; + + case 5: + TryDegenerates2(); + if (a_fEffort <= 69.5f) + { + m_boolDone = true; + } + break; + + case 6: + TryDegenerates3(); + if (a_fEffort <= 79.5f) + { + m_boolDone = true; + } + break; + + case 7: + TryDegenerates4(); + m_boolDone = true; + break; + + default: + assert(0); + break; + } + + m_uiEncodingIterations++; + + SetDoneIfPerfect(); + + } + + // ---------------------------------------------------------------------------------------------------- + // find best initial encoding to ensure block has a valid encoding + // + void Block4x4Encoding_RGB8A1::PerformFirstIteration(void) + { + Block4x4Encoding_ETC1::CalculateMostLikelyFlip(); + + m_fError = FLT_MAX; + + TryDifferential(m_boolMostLikelyFlip, 0, 0, 0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0); + SetDoneIfPerfect(); + + } + + // ---------------------------------------------------------------------------------------------------- + // mostly copied from ETC1 + // differences: + // Block4x4Encoding_RGB8A1 encodingTry = *this; + // + void Block4x4Encoding_RGB8A1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, + int a_iGrayOffset1, int a_iGrayOffset2) + { + + ColorFloatRGBA frgbaColor1; + ColorFloatRGBA frgbaColor2; + + const unsigned int *pauiPixelMapping1; + const unsigned int *pauiPixelMapping2; + + if (a_boolFlip) + { + frgbaColor1 = m_frgbaSourceAverageTop; + frgbaColor2 = m_frgbaSourceAverageBottom; + + pauiPixelMapping1 = s_auiTopPixelMapping; + pauiPixelMapping2 = s_auiBottomPixelMapping; + } + else + { + frgbaColor1 = m_frgbaSourceAverageLeft; + frgbaColor2 = m_frgbaSourceAverageRight; + + pauiPixelMapping1 = s_auiLeftPixelMapping; + pauiPixelMapping2 = s_auiRightPixelMapping; + } + + DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, + a_uiRadius, a_iGrayOffset1, a_iGrayOffset2); + + Block4x4Encoding_RGB8A1 encodingTry = *this; + encodingTry.m_boolFlip = a_boolFlip; + + encodingTry.TryDifferentialHalf(&trys.m_half1); + encodingTry.TryDifferentialHalf(&trys.m_half2); + + // find best halves that are within differential range + DifferentialTrys::Try *ptryBest1 = nullptr; + DifferentialTrys::Try *ptryBest2 = nullptr; + encodingTry.m_fError = FLT_MAX; + + // see if the best of each half are in differential range + int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed; + int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen; + int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue; + if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3) + { + ptryBest1 = trys.m_half1.m_ptryBest; + ptryBest2 = trys.m_half2.m_ptryBest; + encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError; + } + else + { + // else, find the next best halves that are in differential range + for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0]; + ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys]; + ptry1++) + { + for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0]; + ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys]; + ptry2++) + { + iDRed = ptry2->m_iRed - ptry1->m_iRed; + bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4; + iDGreen = ptry2->m_iGreen - ptry1->m_iGreen; + bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4; + iDBlue = ptry2->m_iBlue - ptry1->m_iBlue; + bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4; + + if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta) + { + float fError = ptry1->m_fError + ptry2->m_fError; + + if (fError < encodingTry.m_fError) + { + encodingTry.m_fError = fError; + + ptryBest1 = ptry1; + ptryBest2 = ptry2; + } + } + + } + } + assert(encodingTry.m_fError < FLT_MAX); + assert(ptryBest1 != nullptr); + assert(ptryBest2 != nullptr); + } + + if (encodingTry.m_fError < m_fError) + { + m_mode = MODE_ETC1; + m_boolDiff = true; + m_boolFlip = encodingTry.m_boolFlip; + m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue); + m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue); + m_uiCW1 = ptryBest1->m_uiCW; + m_uiCW2 = ptryBest2->m_uiCW; + + m_fError = 0.0f; + for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++) + { + unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder]; + unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder]; + + unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder]; + unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder]; + + m_auiSelectors[uiPixel1] = uiSelector1; + m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder]; + + if (uiSelector1 == TRANSPARENT_SELECTOR) + { + m_afrgbaDecodedColors[uiPixel1] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel1] = 0.0f; + } + else + { + float fDeltaRGB1 = s_aafCwOpaqueUnsetTable[m_uiCW1][uiSelector1]; + m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB(); + m_afDecodedAlphas[uiPixel1] = 1.0f; + } + + if (uiSelector2 == TRANSPARENT_SELECTOR) + { + m_afrgbaDecodedColors[uiPixel2] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel2] = 0.0f; + } + else + { + float fDeltaRGB2 = s_aafCwOpaqueUnsetTable[m_uiCW2][uiSelector2]; + m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB(); + m_afDecodedAlphas[uiPixel2] = 1.0f; + } + + float fDeltaA1 = m_afDecodedAlphas[uiPixel1] - m_pafrgbaSource[uiPixel1].fA; + m_fError += fDeltaA1 * fDeltaA1; + float fDeltaA2 = m_afDecodedAlphas[uiPixel2] - m_pafrgbaSource[uiPixel2].fA; + m_fError += fDeltaA2 * fDeltaA2; + } + + m_fError1 = ptryBest1->m_fError; + m_fError2 = ptryBest2->m_fError; + m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors; + m_fError = m_fError1 + m_fError2; + + // sanity check + { + int iRed1 = m_frgbaColor1.IntRed(31.0f); + int iGreen1 = m_frgbaColor1.IntGreen(31.0f); + int iBlue1 = m_frgbaColor1.IntBlue(31.0f); + + int iRed2 = m_frgbaColor2.IntRed(31.0f); + int iGreen2 = m_frgbaColor2.IntGreen(31.0f); + int iBlue2 = m_frgbaColor2.IntBlue(31.0f); + + iDRed = iRed2 - iRed1; + iDGreen = iGreen2 - iGreen1; + iDBlue = iBlue2 - iBlue1; + + assert(iDRed >= -4 && iDRed < 4); + assert(iDGreen >= -4 && iDGreen < 4); + assert(iDBlue >= -4 && iDBlue < 4); + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // mostly copied from ETC1 + // differences: + // uses s_aafCwOpaqueUnsetTable + // color for selector set to 0,0,0,0 + // + void Block4x4Encoding_RGB8A1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf) + { + + a_phalf->m_ptryBest = nullptr; + float fBestTryError = FLT_MAX; + + a_phalf->m_uiTrys = 0; + for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius; + iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius; + iRed++) + { + assert(iRed >= 0 && iRed <= 31); + + for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius; + iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius; + iGreen++) + { + assert(iGreen >= 0 && iGreen <= 31); + + for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius; + iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius; + iBlue++) + { + assert(iBlue >= 0 && iBlue <= 31); + + DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys]; + assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]); + + ptry->m_iRed = iRed; + ptry->m_iGreen = iGreen; + ptry->m_iBlue = iBlue; + ptry->m_fError = FLT_MAX; + ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue); + + // try each CW + for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) + { + unsigned int auiPixelSelectors[PIXELS / 2]; + ColorFloatRGBA afrgbaDecodedColors[PIXELS / 2]; + float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + + // pre-compute decoded pixels for each selector + ColorFloatRGBA afrgbaSelectors[SELECTORS]; + assert(SELECTORS == 4); + afrgbaSelectors[0] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][0]).ClampRGB(); + afrgbaSelectors[1] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][1]).ClampRGB(); + afrgbaSelectors[2] = ColorFloatRGBA(); + afrgbaSelectors[3] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][3]).ClampRGB(); + + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]]; + ColorFloatRGBA frgbaDecodedPixel; + + for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) + { + if (pfrgbaSourcePixel->fA < 0.5f) + { + uiSelector = TRANSPARENT_SELECTOR; + } + else if (uiSelector == TRANSPARENT_SELECTOR) + { + continue; + } + + frgbaDecodedPixel = afrgbaSelectors[uiSelector]; + + float fPixelError; + + fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]], + *pfrgbaSourcePixel); + + if (fPixelError < afPixelErrors[uiPixel]) + { + auiPixelSelectors[uiPixel] = uiSelector; + afrgbaDecodedColors[uiPixel] = frgbaDecodedPixel; + afPixelErrors[uiPixel] = fPixelError; + } + + if (uiSelector == TRANSPARENT_SELECTOR) + { + break; + } + } + } + + // add up all pixel errors + float fCWError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + fCWError += afPixelErrors[uiPixel]; + } + + // if best CW so far + if (fCWError < ptry->m_fError) + { + ptry->m_uiCW = uiCW; + for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) + { + ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel]; + } + ptry->m_fError = fCWError; + } + + } + + if (ptry->m_fError < fBestTryError) + { + a_phalf->m_ptryBest = ptry; + fBestTryError = ptry->m_fError; + } + + assert(ptry->m_fError < FLT_MAX); + + a_phalf->m_uiTrys++; + } + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try encoding in T mode + // save this encoding if it improves the error + // + // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently + // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower + // + void Block4x4Encoding_RGB8A1::TryT(unsigned int a_uiRadius) + { + Block4x4Encoding_RGB8A1 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_T; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + encodingTry.m_fError = FLT_MAX; + } + + int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); + int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); + int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); + + int iMinRed1 = iColor1Red - (int)a_uiRadius; + if (iMinRed1 < 0) + { + iMinRed1 = 0; + } + int iMaxRed1 = iColor1Red + (int)a_uiRadius; + if (iMaxRed1 > 15) + { + iMinRed1 = 15; + } + + int iMinGreen1 = iColor1Green - (int)a_uiRadius; + if (iMinGreen1 < 0) + { + iMinGreen1 = 0; + } + int iMaxGreen1 = iColor1Green + (int)a_uiRadius; + if (iMaxGreen1 > 15) + { + iMinGreen1 = 15; + } + + int iMinBlue1 = iColor1Blue - (int)a_uiRadius; + if (iMinBlue1 < 0) + { + iMinBlue1 = 0; + } + int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; + if (iMaxBlue1 > 15) + { + iMinBlue1 = 15; + } + + int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); + int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); + int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); + + int iMinRed2 = iColor2Red - (int)a_uiRadius; + if (iMinRed2 < 0) + { + iMinRed2 = 0; + } + int iMaxRed2 = iColor2Red + (int)a_uiRadius; + if (iMaxRed2 > 15) + { + iMinRed2 = 15; + } + + int iMinGreen2 = iColor2Green - (int)a_uiRadius; + if (iMinGreen2 < 0) + { + iMinGreen2 = 0; + } + int iMaxGreen2 = iColor2Green + (int)a_uiRadius; + if (iMaxGreen2 > 15) + { + iMinGreen2 = 15; + } + + int iMinBlue2 = iColor2Blue - (int)a_uiRadius; + if (iMinBlue2 < 0) + { + iMinBlue2 = 0; + } + int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; + if (iMaxBlue2 > 15) + { + iMinBlue2 = 15; + } + + for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) + { + encodingTry.m_uiCW1 = uiDistance; + + // twiddle m_frgbaOriginalColor2_TAndH + // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector + // + for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) + { + for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) + { + for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) + { + for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) + { + if (uiBaseColorSwaps == 0) + { + encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; + encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); + } + else + { + encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); + encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH; + } + + encodingTry.TryT_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + } + + // twiddle m_frgbaOriginalColor1_TAndH + for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) + { + for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) + { + for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) + { + for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) + { + if (uiBaseColorSwaps == 0) + { + encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); + encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; + } + else + { + encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH; + encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); + } + + encodingTry.TryT_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // find best selector combination for TryT + // called on an encodingTry + // + void Block4x4Encoding_RGB8A1::TryT_BestSelectorCombination(void) + { + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + + unsigned int auiBestPixelSelectors[PIXELS]; + float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; + ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; + + assert(SELECTORS == 4); + afrgbaDecodedPixel[0] = m_frgbaColor1; + afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB(); + afrgbaDecodedPixel[2] = ColorFloatRGBA(); + afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); + + // try each selector + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiMinSelector = 0; + unsigned int uiMaxSelector = SELECTORS - 1; + + if (m_pafrgbaSource[uiPixel].fA < 0.5f) + { + uiMinSelector = 2; + uiMaxSelector = 2; + } + + for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++) + { + float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], + m_pafrgbaSource[uiPixel]); + + if (fPixelError < afBestPixelErrors[uiPixel]) + { + afBestPixelErrors[uiPixel] = fPixelError; + auiBestPixelSelectors[uiPixel] = uiSelector; + afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; + } + } + } + + + // add up all of the pixel errors + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestPixelErrors[uiPixel]; + } + + if (fBlockError < m_fError) + { + m_fError = fBlockError; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try encoding in H mode + // save this encoding if it improves the error + // + // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently + // TWIDDLE_RADIUS of 2 is WAY too slow + // + void Block4x4Encoding_RGB8A1::TryH(unsigned int a_uiRadius) + { + Block4x4Encoding_RGB8A1 encodingTry = *this; + + // init "try" + { + encodingTry.m_mode = MODE_H; + encodingTry.m_boolDiff = true; + encodingTry.m_boolFlip = false; + encodingTry.m_fError = FLT_MAX; + } + + int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); + int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); + int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); + + int iMinRed1 = iColor1Red - (int)a_uiRadius; + if (iMinRed1 < 0) + { + iMinRed1 = 0; + } + int iMaxRed1 = iColor1Red + (int)a_uiRadius; + if (iMaxRed1 > 15) + { + iMinRed1 = 15; + } + + int iMinGreen1 = iColor1Green - (int)a_uiRadius; + if (iMinGreen1 < 0) + { + iMinGreen1 = 0; + } + int iMaxGreen1 = iColor1Green + (int)a_uiRadius; + if (iMaxGreen1 > 15) + { + iMinGreen1 = 15; + } + + int iMinBlue1 = iColor1Blue - (int)a_uiRadius; + if (iMinBlue1 < 0) + { + iMinBlue1 = 0; + } + int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; + if (iMaxBlue1 > 15) + { + iMinBlue1 = 15; + } + + int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); + int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); + int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); + + int iMinRed2 = iColor2Red - (int)a_uiRadius; + if (iMinRed2 < 0) + { + iMinRed2 = 0; + } + int iMaxRed2 = iColor2Red + (int)a_uiRadius; + if (iMaxRed2 > 15) + { + iMinRed2 = 15; + } + + int iMinGreen2 = iColor2Green - (int)a_uiRadius; + if (iMinGreen2 < 0) + { + iMinGreen2 = 0; + } + int iMaxGreen2 = iColor2Green + (int)a_uiRadius; + if (iMaxGreen2 > 15) + { + iMinGreen2 = 15; + } + + int iMinBlue2 = iColor2Blue - (int)a_uiRadius; + if (iMinBlue2 < 0) + { + iMinBlue2 = 0; + } + int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; + if (iMaxBlue2 > 15) + { + iMinBlue2 = 15; + } + + for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) + { + encodingTry.m_uiCW1 = uiDistance; + + // twiddle m_frgbaOriginalColor1_TAndH + for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) + { + for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) + { + for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) + { + encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); + encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; + + // if color1 == color2, H encoding issues can pop up, so abort + if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue) + { + continue; + } + + encodingTry.TryH_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + + // twiddle m_frgbaOriginalColor2_TAndH + for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) + { + for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) + { + for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) + { + encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; + encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); + + // if color1 == color2, H encoding issues can pop up, so abort + if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue) + { + continue; + } + + encodingTry.TryH_BestSelectorCombination(); + + if (encodingTry.m_fError < m_fError) + { + m_mode = encodingTry.m_mode; + m_boolDiff = encodingTry.m_boolDiff; + m_boolFlip = encodingTry.m_boolFlip; + + m_frgbaColor1 = encodingTry.m_frgbaColor1; + m_frgbaColor2 = encodingTry.m_frgbaColor2; + m_uiCW1 = encodingTry.m_uiCW1; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; + } + + m_fError = encodingTry.m_fError; + } + } + } + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // find best selector combination for TryH + // called on an encodingTry + // + void Block4x4Encoding_RGB8A1::TryH_BestSelectorCombination(void) + { + + // abort if colors and CW will pose an encoding problem + { + unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(255.0f); + unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(255.0f); + unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(255.0f); + unsigned int uiColorValue1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1; + + unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(255.0f); + unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(255.0f); + unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(255.0f); + unsigned int uiColorValue2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2; + + unsigned int uiCWLsb = m_uiCW1 & 1; + + if ((uiColorValue1 >= (uiColorValue2 & uiCWLsb)) == 0 || + (uiColorValue1 < (uiColorValue2 & uiCWLsb)) == 1) + { + return; + } + } + + float fDistance = s_afTHDistanceTable[m_uiCW1]; + + unsigned int auiBestPixelSelectors[PIXELS]; + float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; + ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; + + assert(SELECTORS == 4); + afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB(); + afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB(); + afrgbaDecodedPixel[2] = ColorFloatRGBA();; + afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); + + + // try each selector + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiMinSelector = 0; + unsigned int uiMaxSelector = SELECTORS - 1; + + if (m_pafrgbaSource[uiPixel].fA < 0.5f) + { + uiMinSelector = 2; + uiMaxSelector = 2; + } + + for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++) + { + float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], + m_pafrgbaSource[uiPixel]); + + if (fPixelError < afBestPixelErrors[uiPixel]) + { + afBestPixelErrors[uiPixel] = fPixelError; + auiBestPixelSelectors[uiPixel] = uiSelector; + afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; + } + } + } + + + // add up all of the pixel errors + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestPixelErrors[uiPixel]; + } + + if (fBlockError < m_fError) + { + m_fError = fBlockError; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; + m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 1 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_RGB8A1::TryDegenerates1(void) + { + + TryDifferential(m_boolMostLikelyFlip, 1, -2, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 2, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 0, 2); + TryDifferential(m_boolMostLikelyFlip, 1, 0, -2); + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 2 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_RGB8A1::TryDegenerates2(void) + { + + TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0); + TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0); + TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2); + TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2); + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 3 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_RGB8A1::TryDegenerates3(void) + { + + TryDifferential(m_boolMostLikelyFlip, 1, -2, -2); + TryDifferential(m_boolMostLikelyFlip, 1, -2, 2); + TryDifferential(m_boolMostLikelyFlip, 1, 2, -2); + TryDifferential(m_boolMostLikelyFlip, 1, 2, 2); + + } + + // ---------------------------------------------------------------------------------------------------- + // try version 4 of the degenerate search + // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings + // each subsequent version of the degenerate search uses more basecolor movement and is less likely to + // be successfull + // + void Block4x4Encoding_RGB8A1::TryDegenerates4(void) + { + + TryDifferential(m_boolMostLikelyFlip, 1, -4, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 4, 0); + TryDifferential(m_boolMostLikelyFlip, 1, 0, 4); + TryDifferential(m_boolMostLikelyFlip, 1, 0, -4); + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_RGB8A1::SetEncodingBits(void) + { + switch (m_mode) + { + case MODE_ETC1: + SetEncodingBits_ETC1(); + break; + + case MODE_T: + SetEncodingBits_T(); + break; + + case MODE_H: + SetEncodingBits_H(); + break; + + case MODE_PLANAR: + Block4x4Encoding_RGB8::SetEncodingBits_Planar(); + break; + + default: + assert(false); + } + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state if ETC1 mode + // + void Block4x4Encoding_RGB8A1::SetEncodingBits_ETC1(void) + { + + // there is no individual mode in RGB8A1 + assert(m_boolDiff); + + int iRed1 = m_frgbaColor1.IntRed(31.0f); + int iGreen1 = m_frgbaColor1.IntGreen(31.0f); + int iBlue1 = m_frgbaColor1.IntBlue(31.0f); + + int iRed2 = m_frgbaColor2.IntRed(31.0f); + int iGreen2 = m_frgbaColor2.IntGreen(31.0f); + int iBlue2 = m_frgbaColor2.IntBlue(31.0f); + + int iDRed2 = iRed2 - iRed1; + int iDGreen2 = iGreen2 - iGreen1; + int iDBlue2 = iBlue2 - iBlue1; + + assert(iDRed2 >= -4 && iDRed2 < 4); + assert(iDGreen2 >= -4 && iDGreen2 < 4); + assert(iDBlue2 >= -4 && iDBlue2 < 4); + + m_pencodingbitsRGB8->differential.red1 = iRed1; + m_pencodingbitsRGB8->differential.green1 = iGreen1; + m_pencodingbitsRGB8->differential.blue1 = iBlue1; + + m_pencodingbitsRGB8->differential.dred2 = iDRed2; + m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2; + m_pencodingbitsRGB8->differential.dblue2 = iDBlue2; + + m_pencodingbitsRGB8->individual.cw1 = m_uiCW1; + m_pencodingbitsRGB8->individual.cw2 = m_uiCW2; + + SetEncodingBits_Selectors(); + + // in RGB8A1 encoding bits, opaque replaces differential + m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels; + + m_pencodingbitsRGB8->individual.flip = m_boolFlip; + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state if T mode + // + void Block4x4Encoding_RGB8A1::SetEncodingBits_T(void) + { + static const bool SANITY_CHECK = true; + + assert(m_mode == MODE_T); + assert(m_boolDiff == true); + + unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); + unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); + unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); + + unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); + unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); + unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); + + m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2; + m_pencodingbitsRGB8->t.red1b = uiRed1; + m_pencodingbitsRGB8->t.green1 = uiGreen1; + m_pencodingbitsRGB8->t.blue1 = uiBlue1; + + m_pencodingbitsRGB8->t.red2 = uiRed2; + m_pencodingbitsRGB8->t.green2 = uiGreen2; + m_pencodingbitsRGB8->t.blue2 = uiBlue2; + + m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1; + m_pencodingbitsRGB8->t.db = m_uiCW1; + + // in RGB8A1 encoding bits, opaque replaces differential + m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels; + + Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); + + // create an invalid R differential to trigger T mode + m_pencodingbitsRGB8->t.detect1 = 0; + m_pencodingbitsRGB8->t.detect2 = 0; + int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + if (iRed2 >= 4) + { + m_pencodingbitsRGB8->t.detect1 = 7; + m_pencodingbitsRGB8->t.detect2 = 0; + } + else + { + m_pencodingbitsRGB8->t.detect1 = 0; + m_pencodingbitsRGB8->t.detect2 = 1; + } + + if (SANITY_CHECK) + { + iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + + // make sure red overflows + assert(iRed2 < 0 || iRed2 > 31); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state if H mode + // + // colors and selectors may need to swap in order to generate lsb of distance index + // + void Block4x4Encoding_RGB8A1::SetEncodingBits_H(void) + { + static const bool SANITY_CHECK = true; + + assert(m_mode == MODE_H); + assert(m_boolDiff == true); + + unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); + unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); + unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); + + unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); + unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); + unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); + + unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1; + unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2; + + bool boolOddDistance = m_uiCW1 & 1; + bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance; + + if (boolSwapColors) + { + m_pencodingbitsRGB8->h.red1 = uiRed2; + m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1; + m_pencodingbitsRGB8->h.green1b = uiGreen2; + m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3; + m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1; + m_pencodingbitsRGB8->h.blue1c = uiBlue2; + + m_pencodingbitsRGB8->h.red2 = uiRed1; + m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1; + m_pencodingbitsRGB8->h.green2b = uiGreen1; + m_pencodingbitsRGB8->h.blue2 = uiBlue1; + + m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; + m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; + } + else + { + m_pencodingbitsRGB8->h.red1 = uiRed1; + m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1; + m_pencodingbitsRGB8->h.green1b = uiGreen1; + m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3; + m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1; + m_pencodingbitsRGB8->h.blue1c = uiBlue1; + + m_pencodingbitsRGB8->h.red2 = uiRed2; + m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1; + m_pencodingbitsRGB8->h.green2b = uiGreen2; + m_pencodingbitsRGB8->h.blue2 = uiBlue2; + + m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; + m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; + } + + // in RGB8A1 encoding bits, opaque replaces differential + m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels; + + Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); + + if (boolSwapColors) + { + m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF; + } + + // create an invalid R differential to trigger T mode + m_pencodingbitsRGB8->h.detect1 = 0; + m_pencodingbitsRGB8->h.detect2 = 0; + m_pencodingbitsRGB8->h.detect3 = 0; + int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; + if (iRed2 < 0 || iRed2 > 31) + { + m_pencodingbitsRGB8->h.detect1 = 1; + } + if (iGreen2 >= 4) + { + m_pencodingbitsRGB8->h.detect2 = 7; + m_pencodingbitsRGB8->h.detect3 = 0; + } + else + { + m_pencodingbitsRGB8->h.detect2 = 0; + m_pencodingbitsRGB8->h.detect3 = 1; + } + + if (SANITY_CHECK) + { + iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; + iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; + + // make sure red doesn't overflow and green does + assert(iRed2 >= 0 && iRed2 <= 31); + assert(iGreen2 < 0 || iGreen2 > 31); + } + + } + + // #################################################################################################### + // Block4x4Encoding_RGB8A1_Opaque + // #################################################################################################### + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_RGB8A1_Opaque::PerformIteration(float a_fEffort) + { + assert(!m_boolPunchThroughPixels); + assert(!m_boolTransparent); + assert(!m_boolDone); + + switch (m_uiEncodingIterations) + { + case 0: + PerformFirstIteration(); + break; + + case 1: + Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); + break; + + case 2: + Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); + break; + + case 3: + Block4x4Encoding_RGB8::TryPlanar(1); + break; + + case 4: + Block4x4Encoding_RGB8::TryTAndH(1); + if (a_fEffort <= 49.5f) + { + m_boolDone = true; + } + break; + + case 5: + Block4x4Encoding_ETC1::TryDegenerates1(); + if (a_fEffort <= 59.5f) + { + m_boolDone = true; + } + break; + + case 6: + Block4x4Encoding_ETC1::TryDegenerates2(); + if (a_fEffort <= 69.5f) + { + m_boolDone = true; + } + break; + + case 7: + Block4x4Encoding_ETC1::TryDegenerates3(); + if (a_fEffort <= 79.5f) + { + m_boolDone = true; + } + break; + + case 8: + Block4x4Encoding_ETC1::TryDegenerates4(); + m_boolDone = true; + break; + + default: + assert(0); + break; + } + + m_uiEncodingIterations++; + SetDoneIfPerfect(); + } + + // ---------------------------------------------------------------------------------------------------- + // find best initial encoding to ensure block has a valid encoding + // + void Block4x4Encoding_RGB8A1_Opaque::PerformFirstIteration(void) + { + + // set decoded alphas + // calculate alpha error + m_fError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afDecodedAlphas[uiPixel] = 1.0f; + + float fDeltaA = 1.0f - m_pafrgbaSource[uiPixel].fA; + m_fError += fDeltaA * fDeltaA; + } + + CalculateMostLikelyFlip(); + + m_fError = FLT_MAX; + + Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 0, 0, 0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + Block4x4Encoding_RGB8::TryPlanar(0); + SetDoneIfPerfect(); + if (m_boolDone) + { + return; + } + Block4x4Encoding_RGB8::TryTAndH(0); + SetDoneIfPerfect(); + } + + // #################################################################################################### + // Block4x4Encoding_RGB8A1_Transparent + // #################################################################################################### + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_RGB8A1_Transparent::PerformIteration(float ) + { + assert(!m_boolOpaque); + assert(m_boolTransparent); + assert(!m_boolDone); + assert(m_uiEncodingIterations == 0); + + m_mode = MODE_ETC1; + m_boolDiff = true; + m_boolFlip = false; + + m_uiCW1 = 0; + m_uiCW2 = 0; + + m_frgbaColor1 = ColorFloatRGBA(); + m_frgbaColor2 = ColorFloatRGBA(); + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiSelectors[uiPixel] = TRANSPARENT_SELECTOR; + + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel] = 0.0f; + } + + CalcBlockError(); + + m_boolDone = true; + m_uiEncodingIterations++; + + } + + // ---------------------------------------------------------------------------------------------------- + // +} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h new file mode 100644 index 0000000000..ff26e462f8 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h @@ -0,0 +1,129 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcBlock4x4Encoding_RGB8.h" +#include "EtcErrorMetric.h" +#include "EtcBlock4x4EncodingBits.h" + +namespace Etc +{ + + // ################################################################################ + // Block4x4Encoding_RGB8A1 + // RGB8A1 if not completely opaque or transparent + // ################################################################################ + + class Block4x4Encoding_RGB8A1 : public Block4x4Encoding_RGB8 + { + public: + + static const unsigned int TRANSPARENT_SELECTOR = 2; + + Block4x4Encoding_RGB8A1(void); + virtual ~Block4x4Encoding_RGB8A1(void); + + virtual void InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, + ErrorMetric a_errormetric); + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric); + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + void InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric); + + void InitFromEncodingBits_T(void); + void InitFromEncodingBits_H(void); + + void PerformFirstIteration(void); + + void Decode_ETC1(void); + void DecodePixels_T(void); + void DecodePixels_H(void); + void SetEncodingBits_ETC1(void); + void SetEncodingBits_T(void); + void SetEncodingBits_H(void); + + protected: + + bool m_boolOpaque; // all source pixels have alpha >= 0.5 + bool m_boolTransparent; // all source pixels have alpha < 0.5 + bool m_boolPunchThroughPixels; // some source pixels have alpha < 0.5 + + static float s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS]; + + private: + + void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, + int a_iGrayOffset1, int a_iGrayOffset2); + void TryDifferentialHalf(DifferentialTrys::Half *a_phalf); + + void TryT(unsigned int a_uiRadius); + void TryT_BestSelectorCombination(void); + void TryH(unsigned int a_uiRadius); + void TryH_BestSelectorCombination(void); + + void TryDegenerates1(void); + void TryDegenerates2(void); + void TryDegenerates3(void); + void TryDegenerates4(void); + + }; + + // ################################################################################ + // Block4x4Encoding_RGB8A1_Opaque + // RGB8A1 if all pixels have alpha==1 + // ################################################################################ + + class Block4x4Encoding_RGB8A1_Opaque : public Block4x4Encoding_RGB8A1 + { + public: + + virtual void PerformIteration(float a_fEffort); + + void PerformFirstIteration(void); + + private: + + }; + + // ################################################################################ + // Block4x4Encoding_RGB8A1_Transparent + // RGB8A1 if all pixels have alpha==0 + // ################################################################################ + + class Block4x4Encoding_RGB8A1_Transparent : public Block4x4Encoding_RGB8A1 + { + public: + + virtual void PerformIteration(float a_fEffort); + + private: + + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp new file mode 100644 index 0000000000..600c7ab405 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp @@ -0,0 +1,474 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcBlock4x4Encoding_RGBA8.cpp contains: + Block4x4Encoding_RGBA8 + Block4x4Encoding_RGBA8_Opaque + Block4x4Encoding_RGBA8_Transparent + +These encoders are used when targetting file format RGBA8. + +Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque +Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent +Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block + +*/ + +#include "EtcConfig.h" +#include "EtcBlock4x4Encoding_RGBA8.h" + +#include "EtcBlock4x4EncodingBits.h" +#include "EtcBlock4x4.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <float.h> +#include <limits> + +namespace Etc +{ + + // #################################################################################################### + // Block4x4Encoding_RGBA8 + // #################################################################################################### + + float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS] + { + { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f }, + { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f }, + { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f }, + { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f }, + + { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f }, + { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f }, + { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, + { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, + + { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, + { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, + { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, + { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, + + { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, + { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f }, + { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f }, + { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f } + }; + + // ---------------------------------------------------------------------------------------------------- + // + Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void) + { + + m_pencodingbitsA8 = nullptr; + + } + Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {} + // ---------------------------------------------------------------------------------------------------- + // initialization prior to encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits + // + void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) + { + Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); + + m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits; + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8)); + + } + + // ---------------------------------------------------------------------------------------------------- + // initialization from the encoding bits of a previous encoding + // a_pblockParent points to the block associated with this encoding + // a_errormetric is used to choose the best encoding + // a_pafrgbaSource points to a 4x4 block subset of the source image + // a_paucEncodingBits points to the final encoding bits of a previous encoding + // + void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric) + { + + m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits; + m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8)); + + // init RGB portion + Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent, + (unsigned char *) m_pencodingbitsRGB8, + a_pafrgbaSource, + a_errormetric); + + // init A8 portion + // has to be done after InitFromEncodingBits() + { + m_fBase = m_pencodingbitsA8->data.base / 255.0f; + m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier; + m_uiModifierTableIndex = m_pencodingbitsA8->data.table; + + unsigned long long int ulliSelectorBits = 0; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8; + ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiShift = 45 - (3 * uiPixel); + m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1); + } + + // decode the alphas + // calc alpha error + m_fError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier, + m_uiModifierTableIndex, + m_auiAlphaSelectors[uiPixel]); + + float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA; + m_fError += fDeltaAlpha * fDeltaAlpha; + } + } + + // redo error calc to include alpha + CalcBlockError(); + + } + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + // similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added + // + void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort) + { + assert(!m_boolDone); + + if (m_uiEncodingIterations == 0) + { + if (a_fEffort < 24.9f) + { + CalculateA8(0.0f); + } + else if (a_fEffort < 49.9f) + { + CalculateA8(1.0f); + } + else + { + CalculateA8(2.0f); + } + } + + Block4x4Encoding_RGB8::PerformIteration(a_fEffort); + + } + + // ---------------------------------------------------------------------------------------------------- + // find the best combination of base alpga, multiplier and selectors + // + // a_fRadius limits the range of base alpha to try + // + void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius) + { + + // find min/max alpha + float fMinAlpha = 1.0f; + float fMaxAlpha = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + float fAlpha = m_pafrgbaSource[uiPixel].fA; + + // ignore border pixels + if (isnan(fAlpha)) + { + continue; + } + + if (fAlpha < fMinAlpha) + { + fMinAlpha = fAlpha; + } + if (fAlpha > fMaxAlpha) + { + fMaxAlpha = fAlpha; + } + } + assert(fMinAlpha <= fMaxAlpha); + + float fAlphaRange = fMaxAlpha - fMinAlpha; + + // try each modifier table entry + m_fError = FLT_MAX; // artificially high value + for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++) + { + static const unsigned int MIN_VALUE_SELECTOR = 3; + static const unsigned int MAX_VALUE_SELECTOR = 7; + + float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR]; + + float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] - + s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR]; + + float fCenterRatio = fTableEntryCenter / fTableEntryRange; + + float fCenter = fMinAlpha + fCenterRatio*fAlphaRange; + fCenter = roundf(255.0f * fCenter) / 255.0f; + + float fMinBase = fCenter - (a_fRadius / 255.0f); + if (fMinBase < 0.0f) + { + fMinBase = 0.0f; + } + + float fMaxBase = fCenter + (a_fRadius / 255.0f); + if (fMaxBase > 1.0f) + { + fMaxBase = 1.0f; + } + + for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f)) + { + + float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange); + + float fMinMultiplier = fRangeMultiplier - a_fRadius; + if (fMinMultiplier < 1.0f) + { + fMinMultiplier = 1.0f; + } + else if (fMinMultiplier > 15.0f) + { + fMinMultiplier = 15.0f; + } + + float fMaxMultiplier = fRangeMultiplier + a_fRadius; + if (fMaxMultiplier < 1.0f) + { + fMaxMultiplier = 1.0f; + } + else if (fMaxMultiplier > 15.0f) + { + fMaxMultiplier = 15.0f; + } + + for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f) + { + // find best selector for each pixel + unsigned int auiBestSelectors[PIXELS]; + float afBestAlphaError[PIXELS]; + float afBestDecodedAlphas[PIXELS]; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + float fBestPixelAlphaError = FLT_MAX; + for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++) + { + float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector); + + // border pixels (NAN) should have zero error + float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ? + 0.0f : + fDecodedAlpha - m_pafrgbaSource[uiPixel].fA; + + float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha; + + if (fPixelAlphaError < fBestPixelAlphaError) + { + fBestPixelAlphaError = fPixelAlphaError; + auiBestSelectors[uiPixel] = uiSelector; + afBestAlphaError[uiPixel] = fBestPixelAlphaError; + afBestDecodedAlphas[uiPixel] = fDecodedAlpha; + } + } + } + + float fBlockError = 0.0f; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + fBlockError += afBestAlphaError[uiPixel]; + } + + if (fBlockError < m_fError) + { + m_fError = fBlockError; + + m_fBase = fBase; + m_fMultiplier = fMultiplier; + m_uiModifierTableIndex = uiTableEntry; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel]; + m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel]; + } + } + } + } + + } + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_RGBA8::SetEncodingBits(void) + { + + // set the RGB8 portion + Block4x4Encoding_RGB8::SetEncodingBits(); + + // set the A8 portion + { + m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase); + m_pencodingbitsA8->data.table = m_uiModifierTableIndex; + m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier); + + unsigned long long int ulliSelectorBits = 0; + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + unsigned int uiShift = 45 - (3 * uiPixel); + ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift; + } + + m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40; + m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32; + m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24; + m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16; + m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8; + m_pencodingbitsA8->data.selectors5 = ulliSelectorBits; + } + + } + + // #################################################################################################### + // Block4x4Encoding_RGBA8_Opaque + // #################################################################################################### + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort) + { + assert(!m_boolDone); + + if (m_uiEncodingIterations == 0) + { + m_fError = 0.0f; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afDecodedAlphas[uiPixel] = 1.0f; + } + } + + Block4x4Encoding_RGB8::PerformIteration(a_fEffort); + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void) + { + + // set the RGB8 portion + Block4x4Encoding_RGB8::SetEncodingBits(); + + // set the A8 portion + m_pencodingbitsA8->data.base = 255; + m_pencodingbitsA8->data.table = 15; + m_pencodingbitsA8->data.multiplier = 15; + m_pencodingbitsA8->data.selectors0 = 0xFF; + m_pencodingbitsA8->data.selectors1 = 0xFF; + m_pencodingbitsA8->data.selectors2 = 0xFF; + m_pencodingbitsA8->data.selectors3 = 0xFF; + m_pencodingbitsA8->data.selectors4 = 0xFF; + m_pencodingbitsA8->data.selectors5 = 0xFF; + + } + + // #################################################################################################### + // Block4x4Encoding_RGBA8_Transparent + // #################################################################################################### + + // ---------------------------------------------------------------------------------------------------- + // perform a single encoding iteration + // replace the encoding if a better encoding was found + // subsequent iterations generally take longer for each iteration + // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort + // + void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float ) + { + assert(!m_boolDone); + assert(m_uiEncodingIterations == 0); + + m_mode = MODE_ETC1; + m_boolDiff = true; + m_boolFlip = false; + + for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) + { + m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); + m_afDecodedAlphas[uiPixel] = 0.0f; + } + + m_fError = 0.0f; + + m_boolDone = true; + m_uiEncodingIterations++; + + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits based on encoding state + // + void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void) + { + + Block4x4Encoding_RGB8::SetEncodingBits(); + + // set the A8 portion + m_pencodingbitsA8->data.base = 0; + m_pencodingbitsA8->data.table = 0; + m_pencodingbitsA8->data.multiplier = 1; + m_pencodingbitsA8->data.selectors0 = 0; + m_pencodingbitsA8->data.selectors1 = 0; + m_pencodingbitsA8->data.selectors2 = 0; + m_pencodingbitsA8->data.selectors3 = 0; + m_pencodingbitsA8->data.selectors4 = 0; + m_pencodingbitsA8->data.selectors5 = 0; + + } + + // ---------------------------------------------------------------------------------------------------- + // +} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h new file mode 100644 index 0000000000..5765d36b90 --- /dev/null +++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h @@ -0,0 +1,121 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcBlock4x4Encoding_RGB8.h" + +namespace Etc +{ + class Block4x4EncodingBits_A8; + + // ################################################################################ + // Block4x4Encoding_RGBA8 + // RGBA8 if not completely opaque or transparent + // ################################################################################ + + class Block4x4Encoding_RGBA8 : public Block4x4Encoding_RGB8 + { + public: + + Block4x4Encoding_RGBA8(void); + virtual ~Block4x4Encoding_RGBA8(void); + + virtual void InitFromSource(Block4x4 *a_pblockParent, + ColorFloatRGBA *a_pafrgbaSource, + unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric); + + virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, + unsigned char *a_paucEncodingBits, + ColorFloatRGBA *a_pafrgbaSource, + ErrorMetric a_errormetric); + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + protected: + + static const unsigned int MODIFIER_TABLE_ENTRYS = 16; + static const unsigned int ALPHA_SELECTOR_BITS = 3; + static const unsigned int ALPHA_SELECTORS = 1 << ALPHA_SELECTOR_BITS; + + static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]; + + void CalculateA8(float a_fRadius); + + Block4x4EncodingBits_A8 *m_pencodingbitsA8; // A8 portion of Block4x4EncodingBits_RGBA8 + + float m_fBase; + float m_fMultiplier; + unsigned int m_uiModifierTableIndex; + unsigned int m_auiAlphaSelectors[PIXELS]; + + private: + + inline float DecodePixelAlpha(float a_fBase, float a_fMultiplier, + unsigned int a_uiTableIndex, unsigned int a_uiSelector) + { + float fPixelAlpha = a_fBase + + a_fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]; + if (fPixelAlpha < 0.0f) + { + fPixelAlpha = 0.0f; + } + else if (fPixelAlpha > 1.0f) + { + fPixelAlpha = 1.0f; + } + + return fPixelAlpha; + } + + }; + + // ################################################################################ + // Block4x4Encoding_RGBA8_Opaque + // RGBA8 if all pixels have alpha==1 + // ################################################################################ + + class Block4x4Encoding_RGBA8_Opaque : public Block4x4Encoding_RGBA8 + { + public: + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + }; + + // ################################################################################ + // Block4x4Encoding_RGBA8_Transparent + // RGBA8 if all pixels have alpha==0 + // ################################################################################ + + class Block4x4Encoding_RGBA8_Transparent : public Block4x4Encoding_RGBA8 + { + public: + + virtual void PerformIteration(float a_fEffort); + + virtual void SetEncodingBits(void); + + }; + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcColor.h b/thirdparty/etc2comp/EtcColor.h new file mode 100644 index 0000000000..7ceae05b65 --- /dev/null +++ b/thirdparty/etc2comp/EtcColor.h @@ -0,0 +1,64 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <math.h> + +namespace Etc +{ + + inline float LogToLinear(float a_fLog) + { + static const float ALPHA = 0.055f; + static const float ONE_PLUS_ALPHA = 1.0f + ALPHA; + + if (a_fLog <= 0.04045f) + { + return a_fLog / 12.92f; + } + else + { + return powf((a_fLog + ALPHA) / ONE_PLUS_ALPHA, 2.4f); + } + } + + inline float LinearToLog(float &a_fLinear) + { + static const float ALPHA = 0.055f; + static const float ONE_PLUS_ALPHA = 1.0f + ALPHA; + + if (a_fLinear <= 0.0031308f) + { + return 12.92f * a_fLinear; + } + else + { + return ONE_PLUS_ALPHA * powf(a_fLinear, (1.0f/2.4f)) - ALPHA; + } + } + + class ColorR8G8B8A8 + { + public: + + unsigned char ucR; + unsigned char ucG; + unsigned char ucB; + unsigned char ucA; + + }; +} diff --git a/thirdparty/etc2comp/EtcColorFloatRGBA.h b/thirdparty/etc2comp/EtcColorFloatRGBA.h new file mode 100644 index 0000000000..f2ca2c1f71 --- /dev/null +++ b/thirdparty/etc2comp/EtcColorFloatRGBA.h @@ -0,0 +1,321 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcConfig.h" +#include "EtcColor.h" + +#include <math.h> + +namespace Etc +{ + + class ColorFloatRGBA + { + public: + + ColorFloatRGBA(void) + { + fR = fG = fB = fA = 0.0f; + } + + ColorFloatRGBA(float a_fR, float a_fG, float a_fB, float a_fA) + { + fR = a_fR; + fG = a_fG; + fB = a_fB; + fA = a_fA; + } + + inline ColorFloatRGBA operator+(ColorFloatRGBA& a_rfrgba) + { + ColorFloatRGBA frgba; + frgba.fR = fR + a_rfrgba.fR; + frgba.fG = fG + a_rfrgba.fG; + frgba.fB = fB + a_rfrgba.fB; + frgba.fA = fA + a_rfrgba.fA; + return frgba; + } + + inline ColorFloatRGBA operator+(float a_f) + { + ColorFloatRGBA frgba; + frgba.fR = fR + a_f; + frgba.fG = fG + a_f; + frgba.fB = fB + a_f; + frgba.fA = fA; + return frgba; + } + + inline ColorFloatRGBA operator-(float a_f) + { + ColorFloatRGBA frgba; + frgba.fR = fR - a_f; + frgba.fG = fG - a_f; + frgba.fB = fB - a_f; + frgba.fA = fA; + return frgba; + } + + inline ColorFloatRGBA operator-(ColorFloatRGBA& a_rfrgba) + { + ColorFloatRGBA frgba; + frgba.fR = fR - a_rfrgba.fR; + frgba.fG = fG - a_rfrgba.fG; + frgba.fB = fB - a_rfrgba.fB; + frgba.fA = fA - a_rfrgba.fA; + return frgba; + } + + inline ColorFloatRGBA operator*(float a_f) + { + ColorFloatRGBA frgba; + frgba.fR = fR * a_f; + frgba.fG = fG * a_f; + frgba.fB = fB * a_f; + frgba.fA = fA; + + return frgba; + } + + inline ColorFloatRGBA ScaleRGB(float a_f) + { + ColorFloatRGBA frgba; + frgba.fR = a_f * fR; + frgba.fG = a_f * fG; + frgba.fB = a_f * fB; + frgba.fA = fA; + + return frgba; + } + + inline ColorFloatRGBA RoundRGB(void) + { + ColorFloatRGBA frgba; + frgba.fR = roundf(fR); + frgba.fG = roundf(fG); + frgba.fB = roundf(fB); + + return frgba; + } + + inline ColorFloatRGBA ToLinear() + { + ColorFloatRGBA frgbaLinear; + frgbaLinear.fR = LogToLinear(fR); + frgbaLinear.fG = LogToLinear(fG); + frgbaLinear.fB = LogToLinear(fB); + frgbaLinear.fA = fA; + + return frgbaLinear; + } + + inline ColorFloatRGBA ToLog(void) + { + ColorFloatRGBA frgbaLog; + frgbaLog.fR = LinearToLog(fR); + frgbaLog.fG = LinearToLog(fG); + frgbaLog.fB = LinearToLog(fB); + frgbaLog.fA = fA; + + return frgbaLog; + } + + inline static ColorFloatRGBA ConvertFromRGBA8(unsigned char a_ucR, + unsigned char a_ucG, unsigned char a_ucB, unsigned char a_ucA) + { + ColorFloatRGBA frgba; + + frgba.fR = (float)a_ucR / 255.0f; + frgba.fG = (float)a_ucG / 255.0f; + frgba.fB = (float)a_ucB / 255.0f; + frgba.fA = (float)a_ucA / 255.0f; + + return frgba; + } + + inline static ColorFloatRGBA ConvertFromRGB4(unsigned char a_ucR4, + unsigned char a_ucG4, + unsigned char a_ucB4) + { + ColorFloatRGBA frgba; + + unsigned char ucR8 = (unsigned char)((a_ucR4 << 4) + a_ucR4); + unsigned char ucG8 = (unsigned char)((a_ucG4 << 4) + a_ucG4); + unsigned char ucB8 = (unsigned char)((a_ucB4 << 4) + a_ucB4); + + frgba.fR = (float)ucR8 / 255.0f; + frgba.fG = (float)ucG8 / 255.0f; + frgba.fB = (float)ucB8 / 255.0f; + frgba.fA = 1.0f; + + return frgba; + } + + inline static ColorFloatRGBA ConvertFromRGB5(unsigned char a_ucR5, + unsigned char a_ucG5, + unsigned char a_ucB5) + { + ColorFloatRGBA frgba; + + unsigned char ucR8 = (unsigned char)((a_ucR5 << 3) + (a_ucR5 >> 2)); + unsigned char ucG8 = (unsigned char)((a_ucG5 << 3) + (a_ucG5 >> 2)); + unsigned char ucB8 = (unsigned char)((a_ucB5 << 3) + (a_ucB5 >> 2)); + + frgba.fR = (float)ucR8 / 255.0f; + frgba.fG = (float)ucG8 / 255.0f; + frgba.fB = (float)ucB8 / 255.0f; + frgba.fA = 1.0f; + + return frgba; + } + + inline static ColorFloatRGBA ConvertFromR6G7B6(unsigned char a_ucR6, + unsigned char a_ucG7, + unsigned char a_ucB6) + { + ColorFloatRGBA frgba; + + unsigned char ucR8 = (unsigned char)((a_ucR6 << 2) + (a_ucR6 >> 4)); + unsigned char ucG8 = (unsigned char)((a_ucG7 << 1) + (a_ucG7 >> 6)); + unsigned char ucB8 = (unsigned char)((a_ucB6 << 2) + (a_ucB6 >> 4)); + + frgba.fR = (float)ucR8 / 255.0f; + frgba.fG = (float)ucG8 / 255.0f; + frgba.fB = (float)ucB8 / 255.0f; + frgba.fA = 1.0f; + + return frgba; + } + + // quantize to 4 bits, expand to 8 bits + inline ColorFloatRGBA QuantizeR4G4B4(void) const + { + ColorFloatRGBA frgba = *this; + + // quantize to 4 bits + frgba = frgba.ClampRGB().ScaleRGB(15.0f).RoundRGB(); + unsigned int uiR4 = (unsigned int)frgba.fR; + unsigned int uiG4 = (unsigned int)frgba.fG; + unsigned int uiB4 = (unsigned int)frgba.fB; + + // expand to 8 bits + frgba.fR = (float) ((uiR4 << 4) + uiR4); + frgba.fG = (float) ((uiG4 << 4) + uiG4); + frgba.fB = (float) ((uiB4 << 4) + uiB4); + + frgba = frgba.ScaleRGB(1.0f/255.0f); + + return frgba; + } + + // quantize to 5 bits, expand to 8 bits + inline ColorFloatRGBA QuantizeR5G5B5(void) const + { + ColorFloatRGBA frgba = *this; + + // quantize to 5 bits + frgba = frgba.ClampRGB().ScaleRGB(31.0f).RoundRGB(); + unsigned int uiR5 = (unsigned int)frgba.fR; + unsigned int uiG5 = (unsigned int)frgba.fG; + unsigned int uiB5 = (unsigned int)frgba.fB; + + // expand to 8 bits + frgba.fR = (float)((uiR5 << 3) + (uiR5 >> 2)); + frgba.fG = (float)((uiG5 << 3) + (uiG5 >> 2)); + frgba.fB = (float)((uiB5 << 3) + (uiB5 >> 2)); + + frgba = frgba.ScaleRGB(1.0f / 255.0f); + + return frgba; + } + + // quantize to 6/7/6 bits, expand to 8 bits + inline ColorFloatRGBA QuantizeR6G7B6(void) const + { + ColorFloatRGBA frgba = *this; + + // quantize to 6/7/6 bits + ColorFloatRGBA frgba6 = frgba.ClampRGB().ScaleRGB(63.0f).RoundRGB(); + ColorFloatRGBA frgba7 = frgba.ClampRGB().ScaleRGB(127.0f).RoundRGB(); + unsigned int uiR6 = (unsigned int)frgba6.fR; + unsigned int uiG7 = (unsigned int)frgba7.fG; + unsigned int uiB6 = (unsigned int)frgba6.fB; + + // expand to 8 bits + frgba.fR = (float)((uiR6 << 2) + (uiR6 >> 4)); + frgba.fG = (float)((uiG7 << 1) + (uiG7 >> 6)); + frgba.fB = (float)((uiB6 << 2) + (uiB6 >> 4)); + + frgba = frgba.ScaleRGB(1.0f / 255.0f); + + return frgba; + } + + inline ColorFloatRGBA ClampRGB(void) + { + ColorFloatRGBA frgba = *this; + if (frgba.fR < 0.0f) { frgba.fR = 0.0f; } + if (frgba.fR > 1.0f) { frgba.fR = 1.0f; } + if (frgba.fG < 0.0f) { frgba.fG = 0.0f; } + if (frgba.fG > 1.0f) { frgba.fG = 1.0f; } + if (frgba.fB < 0.0f) { frgba.fB = 0.0f; } + if (frgba.fB > 1.0f) { frgba.fB = 1.0f; } + + return frgba; + } + + inline ColorFloatRGBA ClampRGBA(void) + { + ColorFloatRGBA frgba = *this; + if (frgba.fR < 0.0f) { frgba.fR = 0.0f; } + if (frgba.fR > 1.0f) { frgba.fR = 1.0f; } + if (frgba.fG < 0.0f) { frgba.fG = 0.0f; } + if (frgba.fG > 1.0f) { frgba.fG = 1.0f; } + if (frgba.fB < 0.0f) { frgba.fB = 0.0f; } + if (frgba.fB > 1.0f) { frgba.fB = 1.0f; } + if (frgba.fA < 0.0f) { frgba.fA = 0.0f; } + if (frgba.fA > 1.0f) { frgba.fA = 1.0f; } + + return frgba; + } + + inline int IntRed(float a_fScale) + { + return (int)roundf(fR * a_fScale); + } + + inline int IntGreen(float a_fScale) + { + return (int)roundf(fG * a_fScale); + } + + inline int IntBlue(float a_fScale) + { + return (int)roundf(fB * a_fScale); + } + + inline int IntAlpha(float a_fScale) + { + return (int)roundf(fA * a_fScale); + } + + float fR, fG, fB, fA; + }; + +} + diff --git a/thirdparty/etc2comp/EtcConfig.h b/thirdparty/etc2comp/EtcConfig.h new file mode 100644 index 0000000000..3bfe1d99a8 --- /dev/null +++ b/thirdparty/etc2comp/EtcConfig.h @@ -0,0 +1,67 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef _WIN32 +#define ETC_WINDOWS (1) +#else +#define ETC_WINDOWS (0) +#endif + +#if __APPLE__ +#define ETC_OSX (1) +#else +#define ETC_OSX (0) +#endif + +#if __unix__ +#define ETC_UNIX (1) +#else +#define ETC_UNIX (0) +#endif + + +// short names for common types +#include <stdint.h> +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef float f32; +typedef double f64; + +// Keep asserts enabled in release builds during development +#undef NDEBUG + +// 0=disable. stb_image can be used if you need to compress +//other image formats like jpg +#define USE_STB_IMAGE_LOAD 0 + +#if ETC_WINDOWS +#include <sdkddkver.h> +#define _CRT_SECURE_NO_WARNINGS (1) +#include <tchar.h> +#endif + +#include <stdio.h> + diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.cpp b/thirdparty/etc2comp/EtcDifferentialTrys.cpp new file mode 100644 index 0000000000..ef4cd103d9 --- /dev/null +++ b/thirdparty/etc2comp/EtcDifferentialTrys.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcDifferentialTrys.cpp + +Gathers the results of the various encoding trys for both halves of a 4x4 block for Differential mode + +*/ + +#include "EtcConfig.h" +#include "EtcDifferentialTrys.h" + +#include <assert.h> + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // construct a list of trys (encoding attempts) + // + // a_frgbaColor1 is the basecolor for the first half + // a_frgbaColor2 is the basecolor for the second half + // a_pauiPixelMapping1 is the pixel order for the first half + // a_pauiPixelMapping2 is the pixel order for the second half + // a_uiRadius is the amount to vary the base colors + // + DifferentialTrys::DifferentialTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2, + const unsigned int *a_pauiPixelMapping1, + const unsigned int *a_pauiPixelMapping2, + unsigned int a_uiRadius, + int a_iGrayOffset1, int a_iGrayOffset2) + { + assert(a_uiRadius <= MAX_RADIUS); + + m_boolSeverelyBentColors = false; + + ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR5G5B5(); + ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR5G5B5(); + + // quantize base colors + // ensure that trys with a_uiRadius don't overflow + int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(31.0f)+a_iGrayOffset1, a_uiRadius); + int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(31.0f) + a_iGrayOffset1, a_uiRadius); + int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(31.0f) + a_iGrayOffset1, a_uiRadius); + int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(31.0f) + a_iGrayOffset2, a_uiRadius); + int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(31.0f) + a_iGrayOffset2, a_uiRadius); + int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(31.0f) + a_iGrayOffset2, a_uiRadius); + + int iDeltaRed = iRed2 - iRed1; + int iDeltaGreen = iGreen2 - iGreen1; + int iDeltaBlue = iBlue2 - iBlue1; + + // make sure components are within range + { + if (iDeltaRed > 3) + { + if (iDeltaRed > 7) + { + m_boolSeverelyBentColors = true; + } + + iRed1 += (iDeltaRed - 3) / 2; + iRed2 = iRed1 + 3; + iDeltaRed = 3; + } + else if (iDeltaRed < -4) + { + if (iDeltaRed < -8) + { + m_boolSeverelyBentColors = true; + } + + iRed1 += (iDeltaRed + 4) / 2; + iRed2 = iRed1 - 4; + iDeltaRed = -4; + } + assert(iRed1 >= (signed)(0 + a_uiRadius) && iRed1 <= (signed)(31 - a_uiRadius)); + assert(iRed2 >= (signed)(0 + a_uiRadius) && iRed2 <= (signed)(31 - a_uiRadius)); + assert(iDeltaRed >= -4 && iDeltaRed <= 3); + + if (iDeltaGreen > 3) + { + if (iDeltaGreen > 7) + { + m_boolSeverelyBentColors = true; + } + + iGreen1 += (iDeltaGreen - 3) / 2; + iGreen2 = iGreen1 + 3; + iDeltaGreen = 3; + } + else if (iDeltaGreen < -4) + { + if (iDeltaGreen < -8) + { + m_boolSeverelyBentColors = true; + } + + iGreen1 += (iDeltaGreen + 4) / 2; + iGreen2 = iGreen1 - 4; + iDeltaGreen = -4; + } + assert(iGreen1 >= (signed)(0 + a_uiRadius) && iGreen1 <= (signed)(31 - a_uiRadius)); + assert(iGreen2 >= (signed)(0 + a_uiRadius) && iGreen2 <= (signed)(31 - a_uiRadius)); + assert(iDeltaGreen >= -4 && iDeltaGreen <= 3); + + if (iDeltaBlue > 3) + { + if (iDeltaBlue > 7) + { + m_boolSeverelyBentColors = true; + } + + iBlue1 += (iDeltaBlue - 3) / 2; + iBlue2 = iBlue1 + 3; + iDeltaBlue = 3; + } + else if (iDeltaBlue < -4) + { + if (iDeltaBlue < -8) + { + m_boolSeverelyBentColors = true; + } + + iBlue1 += (iDeltaBlue + 4) / 2; + iBlue2 = iBlue1 - 4; + iDeltaBlue = -4; + } + assert(iBlue1 >= (signed)(0+a_uiRadius) && iBlue1 <= (signed)(31 - a_uiRadius)); + assert(iBlue2 >= (signed)(0 + a_uiRadius) && iBlue2 <= (signed)(31 - a_uiRadius)); + assert(iDeltaBlue >= -4 && iDeltaBlue <= 3); + } + + m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius); + m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius); + + } + + // ---------------------------------------------------------------------------------------------------- + // + void DifferentialTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue, + const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius) + { + + m_iRed = a_iRed; + m_iGreen = a_iGreen; + m_iBlue = a_iBlue; + + m_pauiPixelMapping = a_pauiPixelMapping; + m_uiRadius = a_uiRadius; + + m_uiTrys = 0; + + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.h b/thirdparty/etc2comp/EtcDifferentialTrys.h new file mode 100644 index 0000000000..71860908ff --- /dev/null +++ b/thirdparty/etc2comp/EtcDifferentialTrys.h @@ -0,0 +1,97 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcColorFloatRGBA.h" + +namespace Etc +{ + + class DifferentialTrys + { + public: + + static const unsigned int MAX_RADIUS = 2; + + DifferentialTrys(ColorFloatRGBA a_frgbaColor1, + ColorFloatRGBA a_frgbaColor2, + const unsigned int *a_pauiPixelMapping1, + const unsigned int *a_pauiPixelMapping2, + unsigned int a_uiRadius, + int a_iGrayOffset1, int a_iGrayOffset2); + + inline static int MoveAwayFromEdge(int a_i, int a_iDistance) + { + if (a_i < (0+ a_iDistance)) + { + return (0 + a_iDistance); + } + else if (a_i > (31- a_iDistance)) + { + return (31 - a_iDistance); + } + + return a_i; + } + + class Try + { + public : + static const unsigned int SELECTORS = 8; // per half + + int m_iRed; + int m_iGreen; + int m_iBlue; + unsigned int m_uiCW; + unsigned int m_auiSelectors[SELECTORS]; + float m_fError; + }; + + class Half + { + public: + + static const unsigned int MAX_TRYS = 125; + + void Init(int a_iRed, int a_iGreen, int a_iBlue, + const unsigned int *a_pauiPixelMapping, + unsigned int a_uiRadius); + + // center of trys + int m_iRed; + int m_iGreen; + int m_iBlue; + + const unsigned int *m_pauiPixelMapping; + unsigned int m_uiRadius; + + unsigned int m_uiTrys; + Try m_atry[MAX_TRYS]; + + Try *m_ptryBest; + }; + + Half m_half1; + Half m_half2; + + bool m_boolSeverelyBentColors; + }; + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcErrorMetric.h b/thirdparty/etc2comp/EtcErrorMetric.h new file mode 100644 index 0000000000..df4dcab4fb --- /dev/null +++ b/thirdparty/etc2comp/EtcErrorMetric.h @@ -0,0 +1,54 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace Etc +{ + + enum ErrorMetric + { + RGBA, + RGBX, + REC709, + NUMERIC, + NORMALXYZ, + // + ERROR_METRICS, + // + BT709 = REC709 + }; + + inline const char *ErrorMetricToString(ErrorMetric errorMetric) + { + switch (errorMetric) + { + case RGBA: + return "RGBA"; + case RGBX: + return "RGBX"; + case REC709: + return "REC709"; + case NUMERIC: + return "NUMERIC"; + case NORMALXYZ: + return "NORMALXYZ"; + case ERROR_METRICS: + default: + return "UNKNOWN"; + } + } +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcFile.cpp b/thirdparty/etc2comp/EtcFile.cpp new file mode 100644 index 0000000000..831a3aac45 --- /dev/null +++ b/thirdparty/etc2comp/EtcFile.cpp @@ -0,0 +1,390 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS (1) +#endif + +#include "EtcConfig.h" + + +#include "EtcFile.h" + +#include "EtcFileHeader.h" +#include "EtcColor.h" +#include "Etc.h" +#include "EtcBlock4x4EncodingBits.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +using namespace Etc; + +// ---------------------------------------------------------------------------------------------------- +// +File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, + unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes, + unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, + unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight) +{ + if (a_pstrFilename == nullptr) + { + m_pstrFilename = const_cast<char *>(""); + } + else + { + m_pstrFilename = new char[strlen(a_pstrFilename) + 1]; + strcpy(m_pstrFilename, a_pstrFilename); + } + + m_fileformat = a_fileformat; + if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION) + { + // ***** TODO: add this later ***** + m_fileformat = Format::KTX; + } + + m_imageformat = a_imageformat; + + m_uiNumMipmaps = 1; + m_pMipmapImages = new RawImage[m_uiNumMipmaps]; + m_pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(a_paucEncodingBits, [](unsigned char *p) { delete[] p; } ); + m_pMipmapImages[0].uiEncodingBitsBytes = a_uiEncodingBitsBytes; + m_pMipmapImages[0].uiExtendedWidth = a_uiExtendedWidth; + m_pMipmapImages[0].uiExtendedHeight = a_uiExtendedHeight; + + m_uiSourceWidth = a_uiSourceWidth; + m_uiSourceHeight = a_uiSourceHeight; + + switch (m_fileformat) + { + case Format::PKM: + m_pheader = new FileHeader_Pkm(this); + break; + + case Format::KTX: + m_pheader = new FileHeader_Ktx(this); + break; + + default: + assert(0); + break; + } + +} + +// ---------------------------------------------------------------------------------------------------- +// +File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, + unsigned int a_uiNumMipmaps, RawImage *a_pMipmapImages, + unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight) +{ + if (a_pstrFilename == nullptr) + { + m_pstrFilename = const_cast<char *>(""); + } + else + { + m_pstrFilename = new char[strlen(a_pstrFilename) + 1]; + strcpy(m_pstrFilename, a_pstrFilename); + } + + m_fileformat = a_fileformat; + if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION) + { + // ***** TODO: add this later ***** + m_fileformat = Format::KTX; + } + + m_imageformat = a_imageformat; + + m_uiNumMipmaps = a_uiNumMipmaps; + m_pMipmapImages = new RawImage[m_uiNumMipmaps]; + + for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++) + { + m_pMipmapImages[mip] = a_pMipmapImages[mip]; + } + + m_uiSourceWidth = a_uiSourceWidth; + m_uiSourceHeight = a_uiSourceHeight; + + switch (m_fileformat) + { + case Format::PKM: + m_pheader = new FileHeader_Pkm(this); + break; + + case Format::KTX: + m_pheader = new FileHeader_Ktx(this); + break; + + default: + assert(0); + break; + } + +} + +// ---------------------------------------------------------------------------------------------------- +// +File::File(const char *a_pstrFilename, Format a_fileformat) +{ + if (a_pstrFilename == nullptr) + { + return; + } + else + { + m_pstrFilename = new char[strlen(a_pstrFilename) + 1]; + strcpy(m_pstrFilename, a_pstrFilename); + } + + m_fileformat = a_fileformat; + if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION) + { + // ***** TODO: add this later ***** + m_fileformat = Format::KTX; + } + + FILE *pfile = fopen(m_pstrFilename, "rb"); + if (pfile == nullptr) + { + printf("ERROR: Couldn't open %s", m_pstrFilename); + exit(1); + } + fseek(pfile, 0, SEEK_END); + unsigned int fileSize = ftell(pfile); + fseek(pfile, 0, SEEK_SET); + size_t szResult; + + m_pheader = new FileHeader_Ktx(this); + szResult = fread( ((FileHeader_Ktx*)m_pheader)->GetData(), 1, sizeof(FileHeader_Ktx::Data), pfile); + assert(szResult > 0); + + m_uiNumMipmaps = 1; + m_pMipmapImages = new RawImage[m_uiNumMipmaps]; + + if (((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData > 0) + fseek(pfile, ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData, SEEK_CUR); + szResult = fread(&m_pMipmapImages->uiEncodingBitsBytes, 1, sizeof(unsigned int), pfile); + assert(szResult > 0); + + m_pMipmapImages->paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[m_pMipmapImages->uiEncodingBitsBytes], [](unsigned char *p) { delete[] p; } ); + assert(ftell(pfile) + m_pMipmapImages->uiEncodingBitsBytes <= fileSize); + szResult = fread(m_pMipmapImages->paucEncodingBits.get(), 1, m_pMipmapImages->uiEncodingBitsBytes, pfile); + assert(szResult == m_pMipmapImages->uiEncodingBitsBytes); + + uint32_t uiInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlInternalFormat; + uint32_t uiBaseInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlBaseInternalFormat; + + if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC1_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC1_RGB8) + { + m_imageformat = Image::Format::ETC1; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8) + { + m_imageformat = Image::Format::RGB8; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8A1 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8A1) + { + m_imageformat = Image::Format::RGB8A1; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGBA8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGBA8) + { + m_imageformat = Image::Format::RGBA8; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11) + { + m_imageformat = Image::Format::R11; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11) + { + m_imageformat = Image::Format::SIGNED_R11; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11) + { + m_imageformat = Image::Format::RG11; + } + else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11) + { + m_imageformat = Image::Format::SIGNED_RG11; + } + else + { + m_imageformat = Image::Format::UNKNOWN; + } + + m_uiSourceWidth = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelWidth; + m_uiSourceHeight = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelHeight; + m_pMipmapImages->uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth); + m_pMipmapImages->uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight); + + unsigned int uiBlocks = m_pMipmapImages->uiExtendedWidth * m_pMipmapImages->uiExtendedHeight / 16; + Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat); + unsigned int expectedbytes = uiBlocks * Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat); + assert(expectedbytes == m_pMipmapImages->uiEncodingBitsBytes); + + fclose(pfile); +} + +File::~File() +{ + if (m_pMipmapImages != nullptr) + { + delete [] m_pMipmapImages; + } + + if(m_pstrFilename != nullptr) + { + delete[] m_pstrFilename; + m_pstrFilename = nullptr; + } + if (m_pheader != nullptr) + { + delete m_pheader; + m_pheader = nullptr; + } +} + +void File::UseSingleBlock(int a_iPixelX, int a_iPixelY) +{ + if (a_iPixelX <= -1 || a_iPixelY <= -1) + return; + if (a_iPixelX >(int) m_uiSourceWidth) + { + //if we are using a ktx thats the size of a single block or less + //then make sure we use the 4x4 image as the single block + if (m_uiSourceWidth <= 4) + { + a_iPixelX = 0; + } + else + { + printf("blockAtHV: H coordinate out of range, capped to image width\n"); + a_iPixelX = m_uiSourceWidth - 1; + } + } + if (a_iPixelY >(int) m_uiSourceHeight) + { + //if we are using a ktx thats the size of a single block or less + //then make sure we use the 4x4 image as the single block + if (m_uiSourceHeight <= 4) + { + a_iPixelY= 0; + } + else + { + printf("blockAtHV: V coordinate out of range, capped to image height\n"); + a_iPixelY = m_uiSourceHeight - 1; + } + } + + unsigned int origWidth = m_uiSourceWidth; + unsigned int origHeight = m_uiSourceHeight; + + m_uiSourceWidth = 4; + m_uiSourceHeight = 4; + + Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat); + unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat); + + int numMipmaps = 1; + RawImage* pMipmapImages = new RawImage[numMipmaps]; + pMipmapImages[0].uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth); + pMipmapImages[0].uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight); + pMipmapImages[0].uiEncodingBitsBytes = 0; + pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[uiEncodingBitsBytesPerBlock], [](unsigned char *p) { delete[] p; }); + + //block position in pixels + // remove the bottom 2 bits to get the block coordinates + unsigned int iBlockPosX = (a_iPixelX & 0xFFFFFFFC); + unsigned int iBlockPosY = (a_iPixelY & 0xFFFFFFFC); + + int numXBlocks = (origWidth / 4); + int numYBlocks = (origHeight / 4); + + + // block location + //int iBlockX = (a_iPixelX % 4) == 0 ? a_iPixelX / 4.0f : (a_iPixelX / 4) + 1; + //int iBlockY = (a_iPixelY % 4) == 0 ? a_iPixelY / 4.0f : (a_iPixelY / 4) + 1; + //m_paucEncodingBits += ((iBlockY * numXBlocks) + iBlockX) * uiEncodingBitsBytesPerBlock; + + + unsigned int num = numXBlocks*numYBlocks; + unsigned int uiH = 0, uiV = 0; + unsigned char* pEncodingBits = m_pMipmapImages[0].paucEncodingBits.get(); + for (unsigned int uiBlock = 0; uiBlock < num; uiBlock++) + { + if (uiH == iBlockPosX && uiV == iBlockPosY) + { + memcpy(pMipmapImages[0].paucEncodingBits.get(),pEncodingBits, uiEncodingBitsBytesPerBlock); + break; + } + pEncodingBits += uiEncodingBitsBytesPerBlock; + uiH += 4; + + if (uiH >= origWidth) + { + uiH = 0; + uiV += 4; + } + } + + delete [] m_pMipmapImages; + m_pMipmapImages = pMipmapImages; +} +// ---------------------------------------------------------------------------------------------------- +// +void File::Write() +{ + + FILE *pfile = fopen(m_pstrFilename, "wb"); + if (pfile == nullptr) + { + printf("Error: couldn't open Etc file (%s)\n", m_pstrFilename); + exit(1); + } + + m_pheader->Write(pfile); + + for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++) + { + if(m_fileformat == Format::KTX) + { + // Write u32 image size + uint32_t u32ImageSize = m_pMipmapImages[mip].uiEncodingBitsBytes; + uint32_t szBytesWritten = fwrite(&u32ImageSize, 1, sizeof(u32ImageSize), pfile); + assert(szBytesWritten == sizeof(u32ImageSize)); + } + + unsigned int iResult = (int)fwrite(m_pMipmapImages[mip].paucEncodingBits.get(), 1, m_pMipmapImages[mip].uiEncodingBitsBytes, pfile); + if (iResult != m_pMipmapImages[mip].uiEncodingBitsBytes) + { + printf("Error: couldn't write Etc file (%s)\n", m_pstrFilename); + exit(1); + } + } + + fclose(pfile); + +} + +// ---------------------------------------------------------------------------------------------------- +// + diff --git a/thirdparty/etc2comp/EtcFile.h b/thirdparty/etc2comp/EtcFile.h new file mode 100644 index 0000000000..69bf3b2d3a --- /dev/null +++ b/thirdparty/etc2comp/EtcFile.h @@ -0,0 +1,136 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcColorFloatRGBA.h" +#include "EtcImage.h" +#include "Etc.h" + +namespace Etc +{ + class FileHeader; + class SourceImage; + + class File + { + public: + + enum class Format + { + INFER_FROM_FILE_EXTENSION, + PKM, + KTX, + }; + + File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, + unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes, + unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, + unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight); + + File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, + unsigned int a_uiNumMipmaps, RawImage *pMipmapImages, + unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight ); + + File(const char *a_pstrFilename, Format a_fileformat); + ~File(); + const char *GetFilename(void) { return m_pstrFilename; } + + void Read(const char *a_pstrFilename); + void Write(void); + + inline unsigned int GetSourceWidth(void) + { + return m_uiSourceWidth; + } + + inline unsigned int GetSourceHeight(void) + { + return m_uiSourceHeight; + } + + inline unsigned int GetExtendedWidth(unsigned int mipmapIndex = 0) + { + if (mipmapIndex < m_uiNumMipmaps) + { + return m_pMipmapImages[mipmapIndex].uiExtendedWidth; + } + else + { + return 0; + } + } + + inline unsigned int GetExtendedHeight(unsigned int mipmapIndex = 0) + { + if (mipmapIndex < m_uiNumMipmaps) + { + return m_pMipmapImages[mipmapIndex].uiExtendedHeight; + } + else + { + return 0; + } + } + + inline Image::Format GetImageFormat() + { + return m_imageformat; + } + + inline unsigned int GetEncodingBitsBytes(unsigned int mipmapIndex = 0) + { + if (mipmapIndex < m_uiNumMipmaps) + { + return m_pMipmapImages[mipmapIndex].uiEncodingBitsBytes; + } + else + { + return 0; + } + } + + inline unsigned char* GetEncodingBits(unsigned int mipmapIndex = 0) + { + if( mipmapIndex < m_uiNumMipmaps) + { + return m_pMipmapImages[mipmapIndex].paucEncodingBits.get(); + } + else + { + return nullptr; + } + } + + inline unsigned int GetNumMipmaps() + { + return m_uiNumMipmaps; + } + + void UseSingleBlock(int a_iPixelX = -1, int a_iPixelY = -1); + private: + + char *m_pstrFilename; // includes directory path and file extension + Format m_fileformat; + Image::Format m_imageformat; + FileHeader *m_pheader; + unsigned int m_uiNumMipmaps; + RawImage* m_pMipmapImages; + unsigned int m_uiSourceWidth; + unsigned int m_uiSourceHeight; + }; + +} diff --git a/thirdparty/etc2comp/EtcFileHeader.cpp b/thirdparty/etc2comp/EtcFileHeader.cpp new file mode 100644 index 0000000000..f02fcab011 --- /dev/null +++ b/thirdparty/etc2comp/EtcFileHeader.cpp @@ -0,0 +1,185 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EtcFileHeader.h" + +#include "EtcBlock4x4EncodingBits.h" + +#include <assert.h> + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // + FileHeader_Pkm::FileHeader_Pkm(File *a_pfile) + { + m_pfile = a_pfile; + + static const char s_acMagicNumberData[4] = { 'P', 'K', 'M', ' ' }; + static const char s_acVersionData[2] = { '1', '0' }; + + for (unsigned int ui = 0; ui < sizeof(s_acMagicNumberData); ui++) + { + m_data.m_acMagicNumber[ui] = s_acMagicNumberData[ui]; + } + + for (unsigned int ui = 0; ui < sizeof(s_acVersionData); ui++) + { + m_data.m_acVersion[ui] = s_acVersionData[ui]; + } + + m_data.m_ucDataType_msb = 0; // ETC1_RGB_NO_MIPMAPS + m_data.m_ucDataType_lsb = 0; + + m_data.m_ucOriginalWidth_msb = (unsigned char)(m_pfile->GetSourceWidth() >> 8); + m_data.m_ucOriginalWidth_lsb = m_pfile->GetSourceWidth() & 0xFF; + m_data.m_ucOriginalHeight_msb = (unsigned char)(m_pfile->GetSourceHeight() >> 8); + m_data.m_ucOriginalHeight_lsb = m_pfile->GetSourceHeight() & 0xFF; + + m_data.m_ucExtendedWidth_msb = (unsigned char)(m_pfile->GetExtendedWidth() >> 8); + m_data.m_ucExtendedWidth_lsb = m_pfile->GetExtendedWidth() & 0xFF; + m_data.m_ucExtendedHeight_msb = (unsigned char)(m_pfile->GetExtendedHeight() >> 8); + m_data.m_ucExtendedHeight_lsb = m_pfile->GetExtendedHeight() & 0xFF; + + } + + // ---------------------------------------------------------------------------------------------------- + // + void FileHeader_Pkm::Write(FILE *a_pfile) + { + + fwrite(&m_data, sizeof(Data), 1, a_pfile); + + } + + // ---------------------------------------------------------------------------------------------------- + // + FileHeader_Ktx::FileHeader_Ktx(File *a_pfile) + { + m_pfile = a_pfile; + + static const uint8_t s_au8Itentfier[12] = + { + 0xAB, 0x4B, 0x54, 0x58, // first four bytes of Byte[12] identifier + 0x20, 0x31, 0x31, 0xBB, // next four bytes of Byte[12] identifier + 0x0D, 0x0A, 0x1A, 0x0A // final four bytes of Byte[12] identifier + }; + + for (unsigned int ui = 0; ui < sizeof(s_au8Itentfier); ui++) + { + m_data.m_au8Identifier[ui] = s_au8Itentfier[ui]; + } + + m_data.m_u32Endianness = 0x04030201; + m_data.m_u32GlType = 0; + m_data.m_u32GlTypeSize = 1; + m_data.m_u32GlFormat = 0; + + switch (m_pfile->GetImageFormat()) + { + case Image::Format::RGB8: + case Image::Format::SRGB8: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8; + break; + + case Image::Format::RGBA8: + case Image::Format::SRGBA8: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGBA8; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGBA8; + break; + + case Image::Format::RGB8A1: + case Image::Format::SRGB8A1: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8A1; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8A1; + break; + + case Image::Format::R11: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_R11; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11; + break; + + case Image::Format::SIGNED_R11: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_R11; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11; + break; + + case Image::Format::RG11: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RG11; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11; + break; + + case Image::Format::SIGNED_RG11: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_RG11; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11; + break; + + default: + m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC1_RGB8; + m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC1_RGB8; + break; + } + + m_data.m_u32PixelWidth = 0; + m_data.m_u32PixelHeight = 0; + m_data.m_u32PixelDepth = 0; + m_data.m_u32NumberOfArrayElements = 0; + m_data.m_u32NumberOfFaces = 0; + m_data.m_u32BytesOfKeyValueData = 0; + + m_pkeyvaluepair = nullptr; + + m_u32Images = 0; + m_u32KeyValuePairs = 0; + + m_data.m_u32PixelWidth = m_pfile->GetSourceWidth(); + m_data.m_u32PixelHeight = m_pfile->GetSourceHeight(); + m_data.m_u32PixelDepth = 0; + m_data.m_u32NumberOfArrayElements = 0; + m_data.m_u32NumberOfFaces = 1; + m_data.m_u32NumberOfMipmapLevels = m_pfile->GetNumMipmaps(); + + } + + // ---------------------------------------------------------------------------------------------------- + // + void FileHeader_Ktx::Write(FILE *a_pfile) + { + size_t szBytesWritten; + + // Write header + szBytesWritten = fwrite(&m_data, 1, sizeof(Data), a_pfile); + assert(szBytesWritten == sizeof(Data)); + + // Write KeyAndValuePairs + if (m_u32KeyValuePairs) + { + fwrite(m_pkeyvaluepair, m_pkeyvaluepair->u32KeyAndValueByteSize, 1, a_pfile); + } + } + + // ---------------------------------------------------------------------------------------------------- + // + FileHeader_Ktx::Data *FileHeader_Ktx::GetData() + { + return &m_data; + } + + // ---------------------------------------------------------------------------------------------------- + // +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcFileHeader.h b/thirdparty/etc2comp/EtcFileHeader.h new file mode 100644 index 0000000000..55a9cb5d9d --- /dev/null +++ b/thirdparty/etc2comp/EtcFileHeader.h @@ -0,0 +1,146 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcFile.h" +#include <stdio.h> +#include <inttypes.h> + +namespace Etc +{ + + class Image; + + class FileHeader + { + public: + + virtual void Write(FILE *a_pfile) = 0; + File GetFile(); + virtual ~FileHeader(void) {} + protected: + + File *m_pfile; + }; + + // ---------------------------------------------------------------------------------------------------- + // + class FileHeader_Pkm : public FileHeader + { + public: + + FileHeader_Pkm(File *a_pfile); + + virtual void Write(FILE *a_pfile); + virtual ~FileHeader_Pkm(void) {} + private: + + typedef struct + { + char m_acMagicNumber[4]; + char m_acVersion[2]; + unsigned char m_ucDataType_msb; // e.g. ETC1_RGB_NO_MIPMAPS + unsigned char m_ucDataType_lsb; + unsigned char m_ucExtendedWidth_msb; // padded to 4x4 blocks + unsigned char m_ucExtendedWidth_lsb; + unsigned char m_ucExtendedHeight_msb; // padded to 4x4 blocks + unsigned char m_ucExtendedHeight_lsb; + unsigned char m_ucOriginalWidth_msb; + unsigned char m_ucOriginalWidth_lsb; + unsigned char m_ucOriginalHeight_msb; + unsigned char m_ucOriginalHeight_lsb; + } Data; + + Data m_data; + }; + + // ---------------------------------------------------------------------------------------------------- + // + class FileHeader_Ktx : public FileHeader + { + public: + + typedef struct + { + uint32_t u32KeyAndValueByteSize; + } KeyValuePair; + + typedef struct + { + uint8_t m_au8Identifier[12]; + uint32_t m_u32Endianness; + uint32_t m_u32GlType; + uint32_t m_u32GlTypeSize; + uint32_t m_u32GlFormat; + uint32_t m_u32GlInternalFormat; + uint32_t m_u32GlBaseInternalFormat; + uint32_t m_u32PixelWidth; + uint32_t m_u32PixelHeight; + uint32_t m_u32PixelDepth; + uint32_t m_u32NumberOfArrayElements; + uint32_t m_u32NumberOfFaces; + uint32_t m_u32NumberOfMipmapLevels; + uint32_t m_u32BytesOfKeyValueData; + } Data; + + enum class InternalFormat + { + ETC1_RGB8 = 0x8D64, + ETC1_ALPHA8 = ETC1_RGB8, + // + ETC2_R11 = 0x9270, + ETC2_SIGNED_R11 = 0x9271, + ETC2_RG11 = 0x9272, + ETC2_SIGNED_RG11 = 0x9273, + ETC2_RGB8 = 0x9274, + ETC2_SRGB8 = 0x9275, + ETC2_RGB8A1 = 0x9276, + ETC2_SRGB8_PUNCHTHROUGH_ALPHA1 = 0x9277, + ETC2_RGBA8 = 0x9278 + }; + + enum class BaseInternalFormat + { + ETC2_R11 = 0x1903, + ETC2_RG11 = 0x8227, + ETC1_RGB8 = 0x1907, + ETC1_ALPHA8 = ETC1_RGB8, + // + ETC2_RGB8 = 0x1907, + ETC2_RGB8A1 = 0x1908, + ETC2_RGBA8 = 0x1908, + }; + + FileHeader_Ktx(File *a_pfile); + + virtual void Write(FILE *a_pfile); + virtual ~FileHeader_Ktx(void) {} + + void AddKeyAndValue(KeyValuePair *a_pkeyvaluepair); + + Data* GetData(); + + private: + + Data m_data; + KeyValuePair *m_pkeyvaluepair; + + uint32_t m_u32Images; + uint32_t m_u32KeyValuePairs; + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcFilter.cpp b/thirdparty/etc2comp/EtcFilter.cpp new file mode 100644 index 0000000000..bc899a533e --- /dev/null +++ b/thirdparty/etc2comp/EtcFilter.cpp @@ -0,0 +1,401 @@ +#include <stdlib.h> +#include <math.h> +#include "EtcFilter.h" + + +namespace Etc +{ + +static const double PiConst = 3.14159265358979323846; + +inline double sinc(double x) +{ + if ( x == 0.0 ) + { + return 1.0; + } + + return sin(PiConst * x) / (PiConst * x); +} + +//inline float sincf( float x ) +//{ +// x *= F_PI; +// if (x < 0.01f && x > -0.01f) +// { +// return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f); +// } +// +// return sinf(x)/x; +//} +// +//double bessel0(double x) +//{ +// const double EPSILON_RATIO = 1E-16; +// double xh, sum, pow, ds; +// int k; +// +// xh = 0.5 * x; +// sum = 1.0; +// pow = 1.0; +// k = 0; +// ds = 1.0; +// while (ds > sum * EPSILON_RATIO) +// { +// ++k; +// pow = pow * (xh / k); +// ds = pow * pow; +// sum = sum + ds; +// } +// +// return sum; +//} + +//**-------------------------------------------------------------------------- +//** Name: kaiser(double alpha, double half_width, double x) +//** Returns: +//** Description: Alpha controls shape of filter. We are using 4. +//**-------------------------------------------------------------------------- +//inline double kaiser(double alpha, double half_width, double x) +//{ +// double ratio = (x / half_width); +// return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha); +//} +// +//float Filter_Lanczos4Sinc(float x) +//{ +// if (x <= -4.0f || x >= 4.0f) // half-width of 4 +// { +// return 0.0; +// } +// +// return sinc(0.875f * x) * sinc(0.25f * x); +//} +// +//double Filter_Kaiser4( double t ) +//{ +// return kaiser( 4.0, 3.0, t); +//} +// +//double Filter_KaiserOptimal( double t ) +//{ +// return kaiser( 8.93, 3.0f, t); +//} + +double FilterLanczos3( double t ) +{ + if ( t <= -3.0 || t >= 3.0 ) + { + return 0.0; + } + + return sinc( t ) * sinc( t / 3.0 ); +} + +double FilterBox( double t ) +{ + return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0; +} + +double FilterLinear( double t ) +{ + if (t < 0.0) t = -t; + + return (t < 1.0) ? (1.0 - t) : 0.0; +} + + +//**-------------------------------------------------------------------------- +//** Name: CalcContributions( int srcSize, +//** int destSize, +//** double filterSize, +//** bool wrap, +//** double (*FilterProc)(double), +//** FilterWeights contrib[] ) +//** Returns: void +//** Description: +//**-------------------------------------------------------------------------- +void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] ) +{ + double scale; + double filterScale; + double center; + double totalWeight; + double weight; + int iRight; + int iLeft; + int iDest; + + scale = (double)destSize / srcSize; + if ( scale < 1.0 ) + { + filterSize = filterSize / scale; + filterScale = scale; + } + else + { + filterScale = 1.0; + } + + if ( filterSize > (double)MaxFilterSize ) + { + filterSize = (double)MaxFilterSize; + } + + for ( iDest = 0; iDest < destSize; ++iDest ) + { + center = (double)iDest / scale; + + iLeft = (int)ceil(center - filterSize); + iRight = (int)floor(center + filterSize); + + if ( !wrap ) + { + if ( iLeft < 0 ) + { + iLeft = 0; + } + + if ( iRight >= srcSize ) + { + iRight = srcSize - 1; + } + } + + int numWeights = iRight - iLeft + 1; + + contrib[iDest].first = iLeft; + contrib[iDest].numWeights = numWeights; + + totalWeight = 0; + double t = ((double)iLeft - center) * filterScale; + for (int i = 0; i < numWeights; i++) + { + weight = (*FilterProc)(t) * filterScale; + totalWeight += weight; + contrib[iDest].weight[i] = weight; + t += filterScale; + } + + //**-------------------------------------------------------- + //** Normalize weights by dividing by the sum of the weights + //**-------------------------------------------------------- + if ( totalWeight > 0.0 ) + { + for ( int i = 0; i < numWeights; i++) + { + contrib[iDest].weight[i] /= totalWeight; + } + } + } +} + +//**------------------------------------------------------------------------- +//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage, +//** int srcWidth, int srcHeight, +//** RGBCOLOR *pDestImage, +//** int destWidth, int destHeight, +//** double (*FilterProc)(double) ) +//** Returns: 0 on failure and 1 on success +//** Description: Filters a 2d image with a two pass filter by averaging the +//** weighted contributions of the pixels within the filter region. The +//** contributions are determined by a weighting function parameter. +//**------------------------------------------------------------------------- +int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, + RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) ) +{ + FilterWeights *contrib; + RGBCOLOR *pPixel; + RGBCOLOR *pSrcPixel; + RGBCOLOR *pTempImage; + int iRow; + int iCol; + int iSrcCol; + int iSrcRow; + int iWeight; + double dRed; + double dGreen; + double dBlue; + double dAlpha; + double filterSize = 3.0; + + int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight; + contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights)); + + //**------------------------------------------------------------------------ + //** Need to create a temporary image to stuff the horizontally scaled image + //**------------------------------------------------------------------------ + pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) ); + if ( pTempImage == NULL ) + { + return 0; + } + + //**------------------------------------------------------- + //** Horizontally filter the image into the temporary image + //**------------------------------------------------------- + bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X); + CalcContributions( srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib ); + for ( iRow = 0; iRow < srcHeight; iRow++ ) + { + for ( iCol = 0; iCol < destWidth; iCol++ ) + { + dRed = 0; + dGreen = 0; + dBlue = 0; + dAlpha = 0; + + for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ ) + { + iSrcCol = iWeight + contrib[iCol].first; + if (bWrapHorizontal) + { + iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol; + } + pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol; + dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0]; + dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1]; + dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2]; + dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3]; + } + + pPixel = pTempImage + (iRow * destWidth) + iCol; + pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed))); + pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen))); + pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue))); + pPixel->rgba[3] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dAlpha))); + } + } + + //**------------------------------------------------------- + //** Vertically filter the image into the destination image + //**------------------------------------------------------- + bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y); + CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib); + for ( iCol = 0; iCol < destWidth; iCol++ ) + { + for ( iRow = 0; iRow < destHeight; iRow++ ) + { + dRed = 0; + dGreen = 0; + dBlue = 0; + dAlpha = 0; + + for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ ) + { + iSrcRow = iWeight + contrib[iRow].first; + if (bWrapVertical) + { + iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow; + } + pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol; + dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0]; + dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1]; + dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2]; + dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3]; + } + + pPixel = pDestImage + (iRow * destWidth) + iCol; + pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed))); + pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen))); + pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue))); + pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha))); + } + } + + free( pTempImage ); + free( contrib ); + + return 1; +} + +//**------------------------------------------------------------------------- +//** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, +//** RGBCOLOR *pDstImage, int dstWidth, int dstHeight) +//** Returns: 1 +//** Description: This function runs a 2d box filter over the srouce image +//** to produce the destination image. +//**------------------------------------------------------------------------- +void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, + RGBCOLOR *pDstImage, int dstWidth, int dstHeight ) +{ + int iRow; + int iCol; + int iSampleRow; + int iSampleCol; + int iFirstSampleRow; + int iFirstSampleCol; + int iLastSampleRow; + int iLastSampleCol; + int red; + int green; + int blue; + int alpha; + int samples; + float xScale; + float yScale; + + RGBCOLOR *pSrcPixel; + RGBCOLOR *pDstPixel; + + xScale = (float)srcWidth / dstWidth; + yScale = (float)srcHeight / dstHeight; + + for ( iRow = 0; iRow < dstHeight; iRow++ ) + { + for ( iCol = 0; iCol < dstWidth; iCol++ ) + { + iFirstSampleRow = (int)(iRow * yScale); + iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1); + if ( iLastSampleRow >= srcHeight ) + { + iLastSampleRow = srcHeight - 1; + } + + iFirstSampleCol = (int)(iCol * xScale); + iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1); + if ( iLastSampleCol >= srcWidth ) + { + iLastSampleCol = srcWidth - 1; + } + + samples = 0; + red = 0; + green = 0; + blue = 0; + alpha = 0; + for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ ) + { + for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ ) + { + pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol; + red += pSrcPixel->rgba[0]; + green += pSrcPixel->rgba[1]; + blue += pSrcPixel->rgba[2]; + alpha += pSrcPixel->rgba[3]; + + samples++; + } + } + + pDstPixel = pDstImage + iRow * dstWidth + iCol; + if ( samples > 0 ) + { + pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples); + pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples); + pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples); + pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples); + } + else + { + pDstPixel->rgba[0] = static_cast<uint8_t>(red); + pDstPixel->rgba[1] = static_cast<uint8_t>(green); + pDstPixel->rgba[2] = static_cast<uint8_t>(blue); + pDstPixel->rgba[3] = static_cast<uint8_t>(alpha); + } + } + } +} + + +}
\ No newline at end of file diff --git a/thirdparty/etc2comp/EtcFilter.h b/thirdparty/etc2comp/EtcFilter.h new file mode 100644 index 0000000000..fcf125c6df --- /dev/null +++ b/thirdparty/etc2comp/EtcFilter.h @@ -0,0 +1,244 @@ +#pragma once +#include <stdint.h> +#include <algorithm> + +namespace Etc +{ + +enum FilterEnums +{ + MaxFilterSize = 32 +}; + +enum WrapFlags +{ + FILTER_WRAP_NONE = 0, + FILTER_WRAP_X = 0x1, + FILTER_WRAP_Y = 0x2 +}; + +typedef struct tagFilterWeights +{ + int first; + int numWeights; + double weight[MaxFilterSize * 2 + 1]; +} FilterWeights; + +typedef struct tagRGBCOLOR +{ + union + { + uint32_t ulColor; + uint8_t rgba[4]; + }; +} RGBCOLOR; + + +double FilterBox( double t ); +double FilterLinear( double t ); +double FilterLanczos3( double t ); + +int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, + RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) ); +void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, + RGBCOLOR *pDstImage, int dstWidth, int dstHeight ); + + +void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]); + +template <typename T> +void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight) +{ + float xScale; + float yScale; + + T *pSrcPixel; + T *pDstPixel; + + xScale = (float)srcWidth / dstWidth; + yScale = (float)srcHeight / dstHeight; + + for (int iRow = 0; iRow < dstHeight; iRow++) + { + for (int iCol = 0; iCol < dstWidth; iCol++) + { + int samples; + int iFirstSampleRow; + int iFirstSampleCol; + int iLastSampleRow; + int iLastSampleCol; + float red; + float green; + float blue; + float alpha; + + iFirstSampleRow = (int)(iRow * yScale); + iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1); + if (iLastSampleRow >= srcHeight) + { + iLastSampleRow = srcHeight - 1; + } + + iFirstSampleCol = (int)(iCol * xScale); + iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1); + if (iLastSampleCol >= srcWidth) + { + iLastSampleCol = srcWidth - 1; + } + + samples = 0; + red = 0.f; + green = 0.f; + blue = 0.f; + alpha = 0.f; + for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++) + { + for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++) + { + pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4; + red += static_cast<float>(pSrcPixel[0]); + green += static_cast<float>(pSrcPixel[1]); + blue += static_cast<float>(pSrcPixel[2]); + alpha += static_cast<float>(pSrcPixel[3]); + + samples++; + } + } + + pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4; + if (samples > 0) + { + pDstPixel[0] = static_cast<T>(red / samples); + pDstPixel[1] = static_cast<T>(green / samples); + pDstPixel[2] = static_cast<T>(blue / samples); + pDstPixel[3] = static_cast<T>(alpha / samples); + } + else + { + pDstPixel[0] = static_cast<T>(red); + pDstPixel[1] = static_cast<T>(green); + pDstPixel[2] = static_cast<T>(blue); + pDstPixel[3] = static_cast<T>(alpha); + } + } + } + +} + +//**------------------------------------------------------------------------- +//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage, +//** int srcWidth, int srcHeight, +//** RGBCOLOR *pDestImage, +//** int destWidth, int destHeight, +//** double (*FilterProc)(double) ) +//** Returns: 0 on failure and 1 on success +//** Description: Filters a 2d image with a two pass filter by averaging the +//** weighted contributions of the pixels within the filter region. The +//** contributions are determined by a weighting function parameter. +//**------------------------------------------------------------------------- +template <typename T> +int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight, + T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double)) +{ + const int numComponents = 4; + FilterWeights *contrib; + T *pPixel; + T *pTempImage; + double dRed; + double dGreen; + double dBlue; + double dAlpha; + double filterSize = 3.0; + + int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight; + contrib = new FilterWeights[maxDim]; + + //**------------------------------------------------------------------------ + //** Need to create a temporary image to stuff the horizontally scaled image + //**------------------------------------------------------------------------ + pTempImage = new T[destWidth * srcHeight * numComponents]; + if (pTempImage == NULL) + { + return 0; + } + + //**------------------------------------------------------- + //** Horizontally filter the image into the temporary image + //**------------------------------------------------------- + bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X); + CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib); + for (int iRow = 0; iRow < srcHeight; iRow++) + { + for (int iCol = 0; iCol < destWidth; iCol++) + { + dRed = 0; + dGreen = 0; + dBlue = 0; + dAlpha = 0; + + for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++) + { + int iSrcCol = iWeight + contrib[iCol].first; + if(bWrapHorizontal) + { + iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol; + } + T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents; + dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0]; + dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1]; + dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2]; + dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3]; + } + + pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents; + pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed))); + pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen))); + pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue))); + pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha))); + } + } + + //**------------------------------------------------------- + //** Vertically filter the image into the destination image + //**------------------------------------------------------- + bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y); + CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib); + for (int iCol = 0; iCol < destWidth; iCol++) + { + for (int iRow = 0; iRow < destHeight; iRow++) + { + dRed = 0; + dGreen = 0; + dBlue = 0; + dAlpha = 0; + + for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++) + { + int iSrcRow = iWeight + contrib[iRow].first; + if (bWrapVertical) + { + iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow; + } + T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents; + dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0]; + dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1]; + dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2]; + dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3]; + } + + pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents; + pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed))); + pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen))); + pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue))); + pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha))); + } + } + + delete[] pTempImage; + delete[] contrib; + + return 1; +} + + +}
\ No newline at end of file diff --git a/thirdparty/etc2comp/EtcImage.cpp b/thirdparty/etc2comp/EtcImage.cpp new file mode 100644 index 0000000000..7a1058844d --- /dev/null +++ b/thirdparty/etc2comp/EtcImage.cpp @@ -0,0 +1,685 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcImage.cpp + +Image is an array of 4x4 blocks that represent the encoding of the source image + +*/ + +#include "EtcConfig.h" + +#include <stdlib.h> + +#include "EtcImage.h" + +#include "Etc.h" +#include "EtcBlock4x4.h" +#include "EtcBlock4x4EncodingBits.h" +#include "EtcSortedBlockList.h" + +#if ETC_WINDOWS +#include <windows.h> +#endif +#include <ctime> +#include <chrono> +#include <future> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +// fix conflict with Block4x4::AlphaMix +#ifdef OPAQUE +#undef OPAQUE +#endif +#ifdef TRANSPARENT +#undef TRANSPARENT +#endif + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // + Image::Image(void) + { + m_encodingStatus = EncodingStatus::SUCCESS; + m_warningsToCapture = EncodingStatus::SUCCESS; + m_pafrgbaSource = nullptr; + + m_pablock = nullptr; + + m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; + m_uiEncodingBitsBytes = 0; + m_paucEncodingBits = nullptr; + + m_format = Format::UNKNOWN; + m_iNumOpaquePixels = 0; + m_iNumTranslucentPixels = 0; + m_iNumTransparentPixels = 0; + } + + // ---------------------------------------------------------------------------------------------------- + // constructor using source image + // used to set state before Encode() is called + // + Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth, + unsigned int a_uiSourceHeight, + ErrorMetric a_errormetric) + { + m_encodingStatus = EncodingStatus::SUCCESS; + m_warningsToCapture = EncodingStatus::SUCCESS; + m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA; + m_uiSourceWidth = a_uiSourceWidth; + m_uiSourceHeight = a_uiSourceHeight; + + m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth); + m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight); + + m_uiBlockColumns = m_uiExtendedWidth >> 2; + m_uiBlockRows = m_uiExtendedHeight >> 2; + + m_pablock = new Block4x4[GetNumberOfBlocks()]; + assert(m_pablock); + + m_format = Format::UNKNOWN; + + m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; + m_uiEncodingBitsBytes = 0; + m_paucEncodingBits = nullptr; + + m_errormetric = a_errormetric; + m_fEffort = 0.0f; + + m_iEncodeTime_ms = -1; + + m_iNumOpaquePixels = 0; + m_iNumTranslucentPixels = 0; + m_iNumTransparentPixels = 0; + m_bVerboseOutput = false; + + } + + // ---------------------------------------------------------------------------------------------------- + // constructor using encoding bits + // recreates encoding state using a previously encoded image + // + Image::Image(Format a_format, + unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, + unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes, + Image *a_pimageSource, ErrorMetric a_errormetric) + { + m_encodingStatus = EncodingStatus::SUCCESS; + m_pafrgbaSource = nullptr; + m_uiSourceWidth = a_uiSourceWidth; + m_uiSourceHeight = a_uiSourceHeight; + + m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth); + m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight); + + m_uiBlockColumns = m_uiExtendedWidth >> 2; + m_uiBlockRows = m_uiExtendedHeight >> 2; + + unsigned int uiBlocks = GetNumberOfBlocks(); + + m_pablock = new Block4x4[uiBlocks]; + assert(m_pablock); + + m_format = a_format; + + m_iNumOpaquePixels = 0; + m_iNumTranslucentPixels = 0; + m_iNumTransparentPixels = 0; + + m_encodingbitsformat = DetermineEncodingBitsFormat(m_format); + if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN) + { + AddToEncodingStatus(ERROR_UNKNOWN_FORMAT); + return; + } + m_uiEncodingBitsBytes = a_uiEncodingBitsBytes; + m_paucEncodingBits = a_paucEncidingBits; + + m_errormetric = a_errormetric; + m_fEffort = 0.0f; + m_bVerboseOutput = false; + m_iEncodeTime_ms = -1; + + unsigned char *paucEncodingBits = m_paucEncodingBits; + unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); + + unsigned int uiH = 0; + unsigned int uiV = 0; + for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++) + { + m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits, + a_pimageSource, a_errormetric); + paucEncodingBits += uiEncodingBitsBytesPerBlock; + uiH += 4; + if (uiH >= m_uiSourceWidth) + { + uiH = 0; + uiV += 4; + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // + Image::~Image(void) + { + if (m_pablock != nullptr) + { + delete[] m_pablock; + m_pablock = nullptr; + } + + /*if (m_paucEncodingBits != nullptr) + { + delete[] m_paucEncodingBits; + m_paucEncodingBits = nullptr; + }*/ + } + + // ---------------------------------------------------------------------------------------------------- + // encode an image + // create a set of encoding bits that conforms to a_format + // find best fit using a_errormetric + // explore a range of possible encodings based on a_fEffort (range = [0:100]) + // speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs) + // + Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs) + { + + auto start = std::chrono::steady_clock::now(); + + m_encodingStatus = EncodingStatus::SUCCESS; + + m_format = a_format; + m_errormetric = a_errormetric; + m_fEffort = a_fEffort; + + if (m_errormetric < 0 || m_errormetric > ERROR_METRICS) + { + AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC); + return m_encodingStatus; + } + + if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL) + { + AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE); + m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL; + } + else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL) + { + AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE); + m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL; + } + if (a_uiJobs < 1) + { + a_uiJobs = 1; + AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE); + } + else if (a_uiJobs > a_uiMaxJobs) + { + a_uiJobs = a_uiMaxJobs; + AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE); + } + + m_encodingbitsformat = DetermineEncodingBitsFormat(m_format); + + if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN) + { + AddToEncodingStatus(ERROR_UNKNOWN_FORMAT); + return m_encodingStatus; + } + + assert(m_paucEncodingBits == nullptr); + m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); + m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes]; + + InitBlocksAndBlockSorter(); + + + std::future<void> *handle = new std::future<void>[a_uiMaxJobs]; + + unsigned int uiNumThreadsNeeded = 0; + unsigned int uiUnfinishedBlocks = GetNumberOfBlocks(); + + uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs; + + for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) + { + handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded); + } + + RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded); + + for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) + { + handle[i].get(); + } + + // perform effort-based encoding + if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL) + { + unsigned int uiFinishedBlocks = 0; + unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks())); + + if (m_bVerboseOutput) + { + printf("effortblocks = %d\n", uiTotalEffortBlocks); + } + unsigned int uiPass = 0; + while (1) + { + if (m_bVerboseOutput) + { + uiPass++; + printf("pass %u\n", uiPass); + } + m_psortedblocklist->Sort(); + uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks(); + uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks; + if (m_bVerboseOutput) + { + printf(" %u unfinished blocks\n", uiUnfinishedBlocks); + // m_psortedblocklist->Print(); + } + + + + //stop enocding when we did enough to satify the effort percentage + if (uiFinishedBlocks >= uiTotalEffortBlocks) + { + if (m_bVerboseOutput) + { + printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks); + } + break; + } + + unsigned int uiIteratedBlocks = 0; + unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks); + uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs; + + if (uiNumThreadsNeeded <= 1) + { + //since we already how many blocks each thread will process + //cap the thread limit to do the proper amount of work, and not more + uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1); + } + else + { + //we have a lot of work to do, so lets multi thread it + std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1]; + + for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) + { + handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded); + } + uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded); + + for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) + { + uiIteratedBlocks += handleToBlockEncoders[i].get(); + } + + delete[] handleToBlockEncoders; + } + + if (m_bVerboseOutput) + { + printf(" %u iterated blocks\n", uiIteratedBlocks); + } + } + } + + // generate Etc2-compatible bit-format 4x4 blocks + for (int i = 0; i < (int)a_uiJobs - 1; i++) + { + handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs); + } + SetEncodingBits(a_uiJobs - 1, a_uiJobs); + + for (int i = 0; i < (int)a_uiJobs - 1; i++) + { + handle[i].get(); + } + + auto end = std::chrono::steady_clock::now(); + std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); + m_iEncodeTime_ms = (int)elapsed.count(); + + delete[] handle; + delete m_psortedblocklist; + return m_encodingStatus; + } + + // ---------------------------------------------------------------------------------------------------- + // iterate the encoding thru the blocks with the worst error + // stop when a_uiMaxBlocks blocks have been iterated + // split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride + // + unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks, + unsigned int a_uiMultithreadingOffset, + unsigned int a_uiMultithreadingStride) + { + assert(a_uiMultithreadingStride > 0); + unsigned int uiIteratedBlocks = a_uiMultithreadingOffset; + + SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock(); + for (plink = plink->Advance(a_uiMultithreadingOffset); + plink != nullptr; + plink = plink->Advance(a_uiMultithreadingStride) ) + { + if (uiIteratedBlocks >= a_uiMaxBlocks) + { + break; + } + + plink->GetBlock()->PerformEncodingIteration(m_fEffort); + + uiIteratedBlocks += a_uiMultithreadingStride; + } + + return uiIteratedBlocks; + } + + // ---------------------------------------------------------------------------------------------------- + // determine which warnings to check for during Encode() based on encoding format + // + void Image::FindEncodingWarningTypesForCurFormat() + { + TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS); + TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1); + switch (m_format) + { + case Image::Format::ETC1: + case Image::Format::RGB8: + case Image::Format::SRGB8: + TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); + TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); + break; + + case Image::Format::RGB8A1: + case Image::Format::SRGB8A1: + TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); + TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS); + break; + case Image::Format::RGBA8: + case Image::Format::SRGBA8: + TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS); + break; + + case Image::Format::R11: + case Image::Format::SIGNED_R11: + TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); + TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); + TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO); + TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); + break; + + case Image::Format::RG11: + case Image::Format::SIGNED_RG11: + TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); + TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); + TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); + break; + case Image::Format::FORMATS: + case Image::Format::UNKNOWN: + default: + assert(0); + break; + } + } + + // ---------------------------------------------------------------------------------------------------- + // examine source pixels to check for warnings + // + void Image::FindAndSetEncodingWarnings() + { + int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4); + if (m_iNumOpaquePixels == numPixels) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS); + } + if (m_iNumOpaquePixels < numPixels) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS); + } + if (m_iNumTranslucentPixels > 0) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS); + } + if (m_iNumTransparentPixels == numPixels) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS); + } + if (m_numColorValues.fB > 0.0f) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); + } + if (m_numColorValues.fG > 0.0f) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO); + } + + if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1); + } + if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f) + { + AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1); + } + } + + // ---------------------------------------------------------------------------------------------------- + // return a string name for a given image format + // + const char * Image::EncodingFormatToString(Image::Format a_format) + { + switch (a_format) + { + case Image::Format::ETC1: + return "ETC1"; + case Image::Format::RGB8: + return "RGB8"; + case Image::Format::SRGB8: + return "SRGB8"; + + case Image::Format::RGB8A1: + return "RGB8A1"; + case Image::Format::SRGB8A1: + return "SRGB8A1"; + case Image::Format::RGBA8: + return "RGBA8"; + case Image::Format::SRGBA8: + return "SRGBA8"; + + case Image::Format::R11: + return "R11"; + case Image::Format::SIGNED_R11: + return "SIGNED_R11"; + + case Image::Format::RG11: + return "RG11"; + case Image::Format::SIGNED_RG11: + return "SIGNED_RG11"; + case Image::Format::FORMATS: + case Image::Format::UNKNOWN: + default: + return "UNKNOWN"; + } + } + + // ---------------------------------------------------------------------------------------------------- + // return a string name for the image's format + // + const char * Image::EncodingFormatToString(void) + { + return EncodingFormatToString(m_format); + } + + // ---------------------------------------------------------------------------------------------------- + // init image blocks prior to encoding + // init block sorter for subsequent sortings + // check for encoding warnings + // + void Image::InitBlocksAndBlockSorter(void) + { + + FindEncodingWarningTypesForCurFormat(); + + // init each block + Block4x4 *pblock = m_pablock; + unsigned char *paucEncodingBits = m_paucEncodingBits; + for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++) + { + unsigned int uiBlockV = uiBlockRow * 4; + + for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++) + { + unsigned int uiBlockH = uiBlockColumn * 4; + + pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric); + + paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); + + pblock++; + } + } + + FindAndSetEncodingWarnings(); + + // init block sorter + { + m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100); + + for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++) + { + pblock = &m_pablock[uiBlock]; + m_psortedblocklist->AddBlock(pblock); + } + } + + } + + // ---------------------------------------------------------------------------------------------------- + // run the first pass of the encoder + // the encoder generally finds a reasonable, fast encoding + // this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding + // + void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride) + { + assert(a_uiMultithreadingStride > 0); + + for (unsigned int uiBlock = a_uiMultithreadingOffset; + uiBlock < GetNumberOfBlocks(); + uiBlock += a_uiMultithreadingStride) + { + Block4x4 *pblock = &m_pablock[uiBlock]; + pblock->PerformEncodingIteration(m_fEffort); + } + } + + // ---------------------------------------------------------------------------------------------------- + // set the encoding bits (for the output file) based on the best encoding for each block + // + void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset, + unsigned int a_uiMultithreadingStride) + { + assert(a_uiMultithreadingStride > 0); + + for (unsigned int uiBlock = a_uiMultithreadingOffset; + uiBlock < GetNumberOfBlocks(); + uiBlock += a_uiMultithreadingStride) + { + Block4x4 *pblock = &m_pablock[uiBlock]; + pblock->SetEncodingBitsFromEncoding(); + } + + } + + // ---------------------------------------------------------------------------------------------------- + // return the image error + // image error is the sum of all block errors + // + float Image::GetError(void) + { + float fError = 0.0f; + + for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++) + { + Block4x4 *pblock = &m_pablock[uiBlock]; + fError += pblock->GetError(); + } + + return fError; + } + + // ---------------------------------------------------------------------------------------------------- + // determine the encoding bits format based on the encoding format + // the encoding bits format is a family of bit encodings that are shared across various encoding formats + // + Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format) + { + Block4x4EncodingBits::Format encodingbitsformat; + + // determine encoding bits format from image format + switch (a_format) + { + case Format::ETC1: + case Format::RGB8: + case Format::SRGB8: + encodingbitsformat = Block4x4EncodingBits::Format::RGB8; + break; + + case Format::RGBA8: + case Format::SRGBA8: + encodingbitsformat = Block4x4EncodingBits::Format::RGBA8; + break; + + case Format::R11: + case Format::SIGNED_R11: + encodingbitsformat = Block4x4EncodingBits::Format::R11; + break; + + case Format::RG11: + case Format::SIGNED_RG11: + encodingbitsformat = Block4x4EncodingBits::Format::RG11; + break; + + case Format::RGB8A1: + case Format::SRGB8A1: + encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1; + break; + + default: + encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; + break; + } + + return encodingbitsformat; + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcImage.h b/thirdparty/etc2comp/EtcImage.h new file mode 100644 index 0000000000..bd807ac32e --- /dev/null +++ b/thirdparty/etc2comp/EtcImage.h @@ -0,0 +1,249 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +//#include "Etc.h" +#include "EtcColorFloatRGBA.h" +#include "EtcBlock4x4EncodingBits.h" +#include "EtcErrorMetric.h" + + +namespace Etc +{ + class Block4x4; + class EncoderSpec; + class SortedBlockList; + + class Image + { + public: + + //the differnt warning and errors that can come up during encoding + enum EncodingStatus + { + SUCCESS = 0, + // + WARNING_THRESHOLD = 1 << 0, + // + WARNING_EFFORT_OUT_OF_RANGE = 1 << 1, + WARNING_JOBS_OUT_OF_RANGE = 1 << 2, + WARNING_SOME_NON_OPAQUE_PIXELS = 1 << 3,//just for opaque formats, etc1, rgb8, r11, rg11 + WARNING_ALL_OPAQUE_PIXELS = 1 << 4, + WARNING_ALL_TRANSPARENT_PIXELS = 1 << 5, + WARNING_SOME_TRANSLUCENT_PIXELS = 1 << 6,//just for rgb8A1 + WARNING_SOME_RGBA_NOT_0_TO_1 = 1 << 7, + WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO = 1 << 8, + WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO = 1 << 9, + // + ERROR_THRESHOLD = 1 << 16, + // + ERROR_UNKNOWN_FORMAT = 1 << 17, + ERROR_UNKNOWN_ERROR_METRIC = 1 << 18, + ERROR_ZERO_WIDTH_OR_HEIGHT = 1 << 19, + // + }; + + enum class Format + { + UNKNOWN, + // + ETC1, + // + // ETC2 formats + RGB8, + SRGB8, + RGBA8, + SRGBA8, + R11, + SIGNED_R11, + RG11, + SIGNED_RG11, + RGB8A1, + SRGB8A1, + // + FORMATS, + // + DEFAULT = SRGB8 + }; + + // constructor using source image + Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth, + unsigned int a_uiSourceHeight, + ErrorMetric a_errormetric); + + // constructor using encoding bits + Image(Format a_format, + unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, + unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes, + Image *a_pimageSource, + ErrorMetric a_errormetric); + + ~Image(void); + + EncodingStatus Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, + unsigned int a_uiJobs, unsigned int a_uiMaxJobs); + + inline void AddToEncodingStatus(EncodingStatus a_encStatus) + { + m_encodingStatus = (EncodingStatus)((unsigned int)m_encodingStatus | (unsigned int)a_encStatus); + } + + inline unsigned int GetSourceWidth(void) + { + return m_uiSourceWidth; + } + + inline unsigned int GetSourceHeight(void) + { + return m_uiSourceHeight; + } + + inline unsigned int GetExtendedWidth(void) + { + return m_uiExtendedWidth; + } + + inline unsigned int GetExtendedHeight(void) + { + return m_uiExtendedHeight; + } + + inline unsigned int GetNumberOfBlocks() + { + return m_uiBlockColumns * m_uiBlockRows; + } + + inline Block4x4 * GetBlocks() + { + return m_pablock; + } + + inline unsigned char * GetEncodingBits(void) + { + return m_paucEncodingBits; + } + + inline unsigned int GetEncodingBitsBytes(void) + { + return m_uiEncodingBitsBytes; + } + + inline int GetEncodingTimeMs(void) + { + return m_iEncodeTime_ms; + } + + float GetError(void); + + inline ColorFloatRGBA * GetSourcePixel(unsigned int a_uiH, unsigned int a_uiV) + { + if (a_uiH >= m_uiSourceWidth || a_uiV >= m_uiSourceHeight) + { + return nullptr; + } + + return &m_pafrgbaSource[a_uiV*m_uiSourceWidth + a_uiH]; + } + + inline Format GetFormat(void) + { + return m_format; + } + + static Block4x4EncodingBits::Format DetermineEncodingBitsFormat(Format a_format); + + inline static unsigned short CalcExtendedDimension(unsigned short a_ushOriginalDimension) + { + return (unsigned short)((a_ushOriginalDimension + 3) & ~3); + } + + inline ErrorMetric GetErrorMetric(void) + { + return m_errormetric; + } + + static const char * EncodingFormatToString(Image::Format a_format); + const char * EncodingFormatToString(void); + //used to get basic information about the image data + int m_iNumOpaquePixels; + int m_iNumTranslucentPixels; + int m_iNumTransparentPixels; + + ColorFloatRGBA m_numColorValues; + ColorFloatRGBA m_numOutOfRangeValues; + + bool m_bVerboseOutput; + private: + //add a warning or error to check for while encoding + inline void TrackEncodingWarning(EncodingStatus a_encStatus) + { + m_warningsToCapture = (EncodingStatus)((unsigned int)m_warningsToCapture | (unsigned int)a_encStatus); + } + + //report the warning if it is something we care about for this encoding + inline void AddToEncodingStatusIfSignfigant(EncodingStatus a_encStatus) + { + if ((EncodingStatus)((unsigned int)m_warningsToCapture & (unsigned int)a_encStatus) == a_encStatus) + { + AddToEncodingStatus(a_encStatus); + } + } + + Image(void); + void FindEncodingWarningTypesForCurFormat(); + void FindAndSetEncodingWarnings(); + + void InitBlocksAndBlockSorter(void); + + void RunFirstPass(unsigned int a_uiMultithreadingOffset, + unsigned int a_uiMultithreadingStride); + + void SetEncodingBits(unsigned int a_uiMultithreadingOffset, + unsigned int a_uiMultithreadingStride); + + unsigned int IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks, + unsigned int a_uiMultithreadingOffset, + unsigned int a_uiMultithreadingStride); + + // inputs + ColorFloatRGBA *m_pafrgbaSource; + unsigned int m_uiSourceWidth; + unsigned int m_uiSourceHeight; + unsigned int m_uiExtendedWidth; + unsigned int m_uiExtendedHeight; + unsigned int m_uiBlockColumns; + unsigned int m_uiBlockRows; + // intermediate data + Block4x4 *m_pablock; + // encoding + Format m_format; + Block4x4EncodingBits::Format m_encodingbitsformat; + unsigned int m_uiEncodingBitsBytes; // for entire image + unsigned char *m_paucEncodingBits; + ErrorMetric m_errormetric; + float m_fEffort; + // stats + int m_iEncodeTime_ms; + + SortedBlockList *m_psortedblocklist; + //this will hold any warning or errors that happen during encoding + EncodingStatus m_encodingStatus; + //these will be the warnings we are tracking + EncodingStatus m_warningsToCapture; + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcIndividualTrys.cpp b/thirdparty/etc2comp/EtcIndividualTrys.cpp new file mode 100644 index 0000000000..56ff4c65ec --- /dev/null +++ b/thirdparty/etc2comp/EtcIndividualTrys.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcIndividualTrys.cpp + +Gathers the results of the various encoding trys for both halves of a 4x4 block for Individual mode + +*/ + +#include "EtcConfig.h" +#include "EtcIndividualTrys.h" + +#include <assert.h> + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // construct a list of trys (encoding attempts) + // + // a_frgbaColor1 is the basecolor for the first half + // a_frgbaColor2 is the basecolor for the second half + // a_pauiPixelMapping1 is the pixel order for the first half + // a_pauiPixelMapping2 is the pixel order for the second half + // a_uiRadius is the amount to vary the base colors + // + IndividualTrys::IndividualTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2, + const unsigned int *a_pauiPixelMapping1, + const unsigned int *a_pauiPixelMapping2, + unsigned int a_uiRadius) + { + assert(a_uiRadius <= MAX_RADIUS); + + ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR4G4B4(); + ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR4G4B4(); + + // quantize base colors + // ensure that trys with a_uiRadius don't overflow + int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(15.0f), a_uiRadius); + int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(15.0f), a_uiRadius); + int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(15.0f), a_uiRadius); + int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(15.0f), a_uiRadius); + int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(15.0f), a_uiRadius); + int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(15.0f), a_uiRadius); + + m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius); + m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius); + + } + + // ---------------------------------------------------------------------------------------------------- + // + void IndividualTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue, + const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius) + { + + m_iRed = a_iRed; + m_iGreen = a_iGreen; + m_iBlue = a_iBlue; + + m_pauiPixelMapping = a_pauiPixelMapping; + m_uiRadius = a_uiRadius; + + m_uiTrys = 0; + + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcIndividualTrys.h b/thirdparty/etc2comp/EtcIndividualTrys.h new file mode 100644 index 0000000000..5fb12fbcf4 --- /dev/null +++ b/thirdparty/etc2comp/EtcIndividualTrys.h @@ -0,0 +1,95 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "EtcColorFloatRGBA.h" + +namespace Etc +{ + + class IndividualTrys + { + public: + + static const unsigned int MAX_RADIUS = 1; + + IndividualTrys(ColorFloatRGBA a_frgbaColor1, + ColorFloatRGBA a_frgbaColor2, + const unsigned int *a_pauiPixelMapping1, + const unsigned int *a_pauiPixelMapping2, + unsigned int a_uiRadius); + + inline static int MoveAwayFromEdge(int a_i, int a_iDistance) + { + if (a_i < (0+ a_iDistance)) + { + return (0 + a_iDistance); + } + else if (a_i > (15- a_iDistance)) + { + return (15 - a_iDistance); + } + + return a_i; + } + + class Try + { + public : + static const unsigned int SELECTORS = 8; // per half + + int m_iRed; + int m_iGreen; + int m_iBlue; + unsigned int m_uiCW; + unsigned int m_auiSelectors[SELECTORS]; + float m_fError; + }; + + class Half + { + public: + + static const unsigned int MAX_TRYS = 27; + + void Init(int a_iRed, int a_iGreen, int a_iBlue, + const unsigned int *a_pauiPixelMapping, + unsigned int a_uiRadius); + + // center of trys + int m_iRed; + int m_iGreen; + int m_iBlue; + + const unsigned int *m_pauiPixelMapping; + unsigned int m_uiRadius; + + unsigned int m_uiTrys; + Try m_atry[MAX_TRYS]; + + Try *m_ptryBest; + }; + + Half m_half1; + Half m_half2; + + }; + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcMath.cpp b/thirdparty/etc2comp/EtcMath.cpp new file mode 100644 index 0000000000..096d5f7ab9 --- /dev/null +++ b/thirdparty/etc2comp/EtcMath.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EtcConfig.h" +#include "EtcMath.h" + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // calculate the line that best fits the set of XY points contained in a_afX[] and a_afY[] + // use a_fSlope and a_fOffset to define that line + // + bool Regression(float a_afX[], float a_afY[], unsigned int a_Points, + float *a_fSlope, float *a_fOffset) + { + float fPoints = (float)a_Points; + + float fSumX = 0.0f; + float fSumY = 0.0f; + float fSumXY = 0.0f; + float fSumX2 = 0.0f; + + for (unsigned int uiPoint = 0; uiPoint < a_Points; uiPoint++) + { + fSumX += a_afX[uiPoint]; + fSumY += a_afY[uiPoint]; + fSumXY += a_afX[uiPoint] * a_afY[uiPoint]; + fSumX2 += a_afX[uiPoint] * a_afX[uiPoint]; + } + + float fDivisor = fPoints*fSumX2 - fSumX*fSumX; + + // if vertical line + if (fDivisor == 0.0f) + { + *a_fSlope = 0.0f; + *a_fOffset = 0.0f; + return true; + } + + *a_fSlope = (fPoints*fSumXY - fSumX*fSumY) / fDivisor; + *a_fOffset = (fSumY - (*a_fSlope)*fSumX) / fPoints; + + return false; + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcMath.h b/thirdparty/etc2comp/EtcMath.h new file mode 100644 index 0000000000..c58c9a91bc --- /dev/null +++ b/thirdparty/etc2comp/EtcMath.h @@ -0,0 +1,40 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <math.h> + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // return true if vertical line + bool Regression(float a_afX[], float a_afY[], unsigned int a_Points, + float *a_fSlope, float *a_fOffset); + + inline float ConvertMSEToPSNR(float a_fMSE) + { + if (a_fMSE == 0.0f) + { + return INFINITY; + } + + return 10.0f * log10f(1.0f / a_fMSE); + } + + +} diff --git a/thirdparty/etc2comp/EtcSortedBlockList.cpp b/thirdparty/etc2comp/EtcSortedBlockList.cpp new file mode 100644 index 0000000000..bfa6b7b3fa --- /dev/null +++ b/thirdparty/etc2comp/EtcSortedBlockList.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +EtcSortedBlockList.cpp + +SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize +the encoding of the 4x4 blocks. + +The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has + +*/ + +#include "EtcConfig.h" +#include "EtcSortedBlockList.h" + +#include "EtcBlock4x4.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +namespace Etc +{ + + // ---------------------------------------------------------------------------------------------------- + // construct an empty list + // + // allocate enough memory to add all of the image's 4x4 blocks later + // allocate enough buckets to sort the blocks + // + SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets) + { + m_uiImageBlocks = a_uiImageBlocks; + m_iBuckets = (int)a_uiBuckets; + + m_uiAddedBlocks = 0; + m_uiSortedBlocks = 0; + m_palinkPool = new Link[m_uiImageBlocks]; + m_pabucket = new Bucket[m_iBuckets]; + m_fMaxError = 0.0f; + + InitBuckets(); + + } + + // ---------------------------------------------------------------------------------------------------- + // + SortedBlockList::~SortedBlockList(void) + { + delete[] m_palinkPool; + delete[] m_pabucket; + } + + // ---------------------------------------------------------------------------------------------------- + // add a 4x4 block to the list + // the 4x4 block will be sorted later + // + void SortedBlockList::AddBlock(Block4x4 *a_pblock) + { + assert(m_uiAddedBlocks < m_uiImageBlocks); + Link *plink = &m_palinkPool[m_uiAddedBlocks++]; + plink->Init(a_pblock); + } + + // ---------------------------------------------------------------------------------------------------- + // sort all of the 4x4 blocks that have been added to the list + // + // first, determine the maximum error, then assign an error range to each bucket + // next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error + // add the 4x4 block to the appropriate bucket + // lastly, walk thru the buckets and add each bucket to a sorted linked list + // + // the resultant sorting is an approximate sorting from most to least error + // + void SortedBlockList::Sort(void) + { + assert(m_uiAddedBlocks == m_uiImageBlocks); + InitBuckets(); + + // find max block error + m_fMaxError = -1.0f; + + for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++) + { + Link *plinkBlock = &m_palinkPool[uiLink]; + + float fBlockError = plinkBlock->GetBlock()->GetError(); + if (fBlockError > m_fMaxError) + { + m_fMaxError = fBlockError; + } + } + // prevent divide by zero or divide by negative + if (m_fMaxError <= 0.0f) + { + m_fMaxError = 1.0f; + } + //used for debugging + //int numDone = 0; + // put all of the blocks with unfinished encodings into the appropriate bucket + m_uiSortedBlocks = 0; + for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++) + { + Link *plinkBlock = &m_palinkPool[uiLink]; + + // if the encoding is done, don't add it to the list + if (plinkBlock->GetBlock()->GetEncoding()->IsDone()) + { + //numDone++; + continue; + } + + // calculate the appropriate sort bucket + float fBlockError = plinkBlock->GetBlock()->GetError(); + int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError); + // clamp to bucket index + iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket; + + // add block to bucket + { + Bucket *pbucket = &m_pabucket[iBucket]; + if (pbucket->plinkLast) + { + pbucket->plinkLast->SetNext(plinkBlock); + pbucket->plinkLast = plinkBlock; + } + else + { + pbucket->plinkFirst = pbucket->plinkLast = plinkBlock; + } + plinkBlock->SetNext(nullptr); + } + + m_uiSortedBlocks++; + + if (0) + { + printf("%u: e=%.3f\n", uiLink, fBlockError); + Print(); + printf("\n\n\n"); + } + } + //printf("num blocks already done: %d\n",numDone); + //link the blocks together across buckets + m_plinkFirst = nullptr; + m_plinkLast = nullptr; + for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--) + { + Bucket *pbucket = &m_pabucket[iBucket]; + + if (pbucket->plinkFirst) + { + if (m_plinkFirst == nullptr) + { + m_plinkFirst = pbucket->plinkFirst; + } + else + { + assert(pbucket->plinkLast->GetNext() == nullptr); + m_plinkLast->SetNext(pbucket->plinkFirst); + } + + m_plinkLast = pbucket->plinkLast; + } + } + + + } + + // ---------------------------------------------------------------------------------------------------- + // clear all of the buckets. normally done in preparation for a sort + // + void SortedBlockList::InitBuckets(void) + { + for (int iBucket = 0; iBucket < m_iBuckets; iBucket++) + { + Bucket *pbucket = &m_pabucket[iBucket]; + + pbucket->plinkFirst = 0; + pbucket->plinkLast = 0; + } + } + + // ---------------------------------------------------------------------------------------------------- + // print out the list of sorted 4x4 blocks + // normally used for debugging + // + void SortedBlockList::Print(void) + { + for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--) + { + Bucket *pbucket = &m_pabucket[iBucket]; + + unsigned int uiBlocks = 0; + for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() ) + { + uiBlocks++; + + if (plink == pbucket->plinkLast) + { + break; + } + } + + float fBucketError = m_fMaxError * iBucket / m_iBuckets; + float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) ); + printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks); + } + } + + // ---------------------------------------------------------------------------------------------------- + // + +} // namespace Etc diff --git a/thirdparty/etc2comp/EtcSortedBlockList.h b/thirdparty/etc2comp/EtcSortedBlockList.h new file mode 100644 index 0000000000..960e8adc34 --- /dev/null +++ b/thirdparty/etc2comp/EtcSortedBlockList.h @@ -0,0 +1,124 @@ +/* + * Copyright 2015 The Etc2Comp Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace Etc +{ + class Block4x4; + + class SortedBlockList + { + public: + + class Link + { + public: + + inline void Init(Block4x4 *a_pblock) + { + m_pblock = a_pblock; + m_plinkNext = nullptr; + } + + inline Block4x4 * GetBlock(void) + { + return m_pblock; + } + + inline void SetNext(Link *a_plinkNext) + { + m_plinkNext = a_plinkNext; + } + + inline Link * GetNext(void) + { + return m_plinkNext; + } + + inline Link * Advance(unsigned int a_uiSteps = 1) + { + Link *plink = this; + + for (unsigned int uiStep = 0; uiStep < a_uiSteps; uiStep++) + { + if (plink == nullptr) + { + break; + } + + plink = plink->m_plinkNext; + } + + return plink; + } + + private: + + Block4x4 *m_pblock; + Link *m_plinkNext; + }; + + SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets); + ~SortedBlockList(void); + + void AddBlock(Block4x4 *a_pblock); + + void Sort(void); + + inline Link * GetLinkToFirstBlock(void) + { + return m_plinkFirst; + } + + inline unsigned int GetNumberOfAddedBlocks(void) + { + return m_uiAddedBlocks; + } + + inline unsigned int GetNumberOfSortedBlocks(void) + { + return m_uiSortedBlocks; + } + + void Print(void); + + private: + + void InitBuckets(void); + + class Bucket + { + public: + Link *plinkFirst; + Link *plinkLast; + }; + + unsigned int m_uiImageBlocks; + int m_iBuckets; + + unsigned int m_uiAddedBlocks; + unsigned int m_uiSortedBlocks; + Link *m_palinkPool; + Bucket *m_pabucket; + float m_fMaxError; + + Link *m_plinkFirst; + Link *m_plinkLast; + + }; + +} // namespace Etc diff --git a/thirdparty/etc2comp/LICENSE b/thirdparty/etc2comp/LICENSE new file mode 100644 index 0000000000..75b52484ea --- /dev/null +++ b/thirdparty/etc2comp/LICENSE @@ -0,0 +1,202 @@ +
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/thirdparty/etc2comp/README.md b/thirdparty/etc2comp/README.md new file mode 100644 index 0000000000..1c70ae9f4e --- /dev/null +++ b/thirdparty/etc2comp/README.md @@ -0,0 +1,197 @@ +# Etc2Comp - Texture to ETC2 compressor
+
+Etc2Comp is a command line tool that converts textures (e.g. bitmaps)
+into the [ETC2](https://en.wikipedia.org/wiki/Ericsson_Texture_Compression)
+format. The tool is built with a focus on encoding performance
+to reduce the amount of time required to compile asset heavy applications as
+well as reduce overall application size.
+
+This repo provides source code that can be compiled into a binary. The
+binary can then be used to convert textures to the ETC2 format.
+
+Important: This is not an official Google product. It is an experimental
+library published as-is. Please see the CONTRIBUTORS.md file for information
+about questions or issues.
+
+## Setup
+This project uses [CMake](https://cmake.org/) to generate platform-specific
+build files:
+ - Linux: make files
+ - OS X: Xcode workspace files
+ - Microsoft Windows: Visual Studio solution files
+ - Note: CMake supports other formats, but this doc only provides steps for
+ one of each platform for brevity.
+
+Refer to each platform's setup section to setup your environment and build
+an Etc2Comp binary. Then skip to the usage section of this page for examples
+of how to use the library.
+
+### Setup for OS X
+ build tested on this config:
+ OS X 10.9.5 i7 16GB RAM
+ Xcode 5.1.1
+ cmake 3.2.3
+
+Start by downloading and installing the following components if they are not
+already installed on your development machine.
+ - *Xcode* version 5.1.1, or greater
+ - [CMake](https://cmake.org/download/) version 3.2.3, or greater
+
+To build the Etc2Comp binary:
+ 1. Open a *Terminal* window and navigate to the project directory.
+ 1. Run `mkdir build_xcode`
+ 1. Run `cd build_xcode`
+ 1. Run `cmake -G Xcode ../`
+ 1. Open *Xcode* and import the `build_xcode/EtcTest.xcodeproj` file.
+ 1. Open the Product menu and choose Build For -> Running.
+ 1. Once the build succeeds the binary located at `build_xcode/EtcTool/Debug/EtcTool`
+can be executed.
+
+Optional
+Xcode EtcTool ‘Run’ preferences
+note: if the build_xcode/EtcTest.xcodeproj is manually deleted then some Xcode preferences
+will need to be set by hand after cmake is run (these prefs are retained across
+cmake updates if the .xcodeproj is not deleted/removed)
+
+1. Set the active scheme to ‘EtcTool’
+1. Edit the scheme
+1. Select option ‘Run EtcTool’, then tab ‘Arguments’.
+Add this launch argument: ‘-argfile ../../EtcTool/args.txt’
+1. Select tab ‘Options’ and set a custom working directory to: ‘$(SRCROOT)/Build_Xcode/EtcTool’
+
+### SetUp for Windows
+
+1. Open a *Terminal* window and navigate to the project directory.
+1. Run `mkdir build_vs`
+1. Run `cd build_vs`
+1. Run CMAKE, noting what build version you need, and pointing to the parent directory as the source root;
+ For VS 2013 : `cmake -G "Visual Studio 12 2013 Win64" ../`
+ For VS 2015 : `cmake -G "Visual Studio 14 2015 Win64" ../`
+ NOTE: To see what supported Visual Studio outputs there are, run `cmake -G`
+1. open the 'EtcTest' solution
+1. make the 'EtcTool' project the start up project
+1. (optional) in the project properties, under 'Debugging ->command arguments'
+add the argfile textfile thats included in the EtcTool directory.
+example: -argfile C:\etc2\EtcTool\Args.txt
+
+### Setup For Linux
+The Linux build was tested on this config:
+ Ubuntu desktop 14.04
+ gcc/g++ 4.8
+ cmake 2.8.12.2
+
+1. Verify linux has cmake and C++-11 capable g++ installed
+1. Open shell
+1. Run `mkdir build_linux`
+1. Run `cd build_linux`
+1. Run `cmake ../`
+1. Run `make`
+1. navigate to the newly created EtcTool directory `cd EtcTool`
+1. run the executable: `./EtcTool -argfile ../../EtcTool/args.txt`
+
+Skip to the <a href="#usage">Usage</a> section for more information about using the
+tool.
+
+## Usage
+
+### Command Line Usage
+EtcTool can be run from the command line with the following usage:
+ etctool.exe source_image [options ...] -output encoded_image
+
+The encoder will use an array of RGBA floats read from the source_image to create
+an ETC1 or ETC2 encoded image in encoded_image. The RGBA floats should be in the
+range [0:1].
+
+Options:
+
+ -analyze <analysis_folder>
+ -argfile <arg_file> additional command line arguments read from a file
+ -blockAtHV <H V> encodes a single block that contains the
+ pixel specified by the H V coordinates
+ -compare <comparison_image> compares source_image to comparison_image
+ -effort <amount> number between 0 and 100 to specify the encoding quality
+ (100 is the highest quality)
+ -errormetric <error_metric> specify the error metric, the options are
+ rgba, rgbx, rec709, numeric and normalxyz
+ -format <etc_format> ETC1, RGB8, SRGB8, RGBA8, SRGB8, RGB8A1,
+ SRGB8A1 or R11
+ -help prints this message
+ -jobs or -j <thread_count> specifies the number of threads (default=1)
+ -normalizexyz normalize RGB to have a length of 1
+ -verbose or -v shows status information during the encoding
+ process
+ -mipmaps or -m <mip_count> sets the maximum number of mipaps to generate (default=1)
+ -mipwrap or -w <x|y|xy> sets the mipmap filter wrap mode (default=clamp)
+
+* -analyze will run an analysis of the encoding and place it in folder
+"analysis_folder" (e.g. ../analysis/kodim05). within the analysis_folder, a folder
+will be created with a name of the current date/time (e.g. 20151204_153306). this
+date/time folder is used to compare encodings of the same texture over time.
+within the date/time folder is a text file with several encoding stats and a 2x png
+image showing the encoding mode for each 4x4 block.
+
+* -argfile allows additional command line arguments to be placed in a text file
+
+* -blockAtHV selects the 4x4 pixel subset of the source image at position (H,V).
+This is mainly used for debugging
+
+* -compare compares the source image to the created encoded image. The encoding
+will dictate what error analysis is used in the comparison.
+
+* -effort uses an "amount" between 0 and 100 to determine how much additional effort
+to apply during the encoding.
+
+* -errormetric selects the fitting algorithm used by the encoder. "rgba" calculates
+RMS error using RGB components that are weighted by A. "rgbx" calculates RMS error
+using RGBA components, where A is treated as an additional data channel, instead of
+as alpha. "rec709" is similar to "rgba", except the RGB components are also weighted
+according to Rec709. "numeric" calculates RMS error using unweighted RGBA components.
+"normalize" calculates error based on dot product and vector length for RGB and RMS
+error for A.
+
+* -help prints out the usage message
+
+* -jobs enables multi-threading to speed up image encoding
+
+* -normalizexyz normalizes the source RGB to have a length of 1.
+
+* -verbose shows information on the current encoding process. It will then display the
+PSNR and time time it took to encode the image.
+
+* -mipmaps takes an argument that specifies how many mipmaps to generate from the
+source image. The mipmaps are generated with a lanczos3 filter using edge clamping.
+If the mipmaps option is not specified no mipmaps are created.
+
+* -mipwrap takes an argument that specifies the mipmap filter wrap mode. The options
+are "x", "y" and "xy" which specify wrapping in x only, y only or x and y respectively.
+The default options are clamping in both x and y.
+
+Note: Path names can use slashes or backslashes. The tool will convert the
+slashes to the appropriate polarity for the current platform.
+
+
+## API
+
+The library supports two different APIs - a C-like API that is not heavily
+class-based and a class-based API.
+
+main() in EtcTool.cpp contains an example of both APIs.
+
+The Encode() method now returns an EncodingStatus that contains bit flags for
+reporting various warnings and flags encountered when encoding.
+
+
+## Copyright
+Copyright 2015 Etc2Comp Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c index 70a93f8d25..2d756ec3f6 100644 --- a/thirdparty/glad/glad.c +++ b/thirdparty/glad/glad.c @@ -1,6 +1,6 @@ /* - OpenGL loader generated by glad 0.1.13a0 on Fri Jan 6 19:27:07 2017. + OpenGL loader generated by glad 0.1.14a0 on Wed Jun 14 20:12:45 2017. Language/Generator: C/C++ Specification: gl @@ -30,7 +30,7 @@ static void* get_proc(const char *namez); static HMODULE libGL; typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); -PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; +static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; static int open_gl(void) { @@ -57,7 +57,7 @@ static void* libGL; #ifndef __APPLE__ typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); -PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; +static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; #endif static @@ -152,19 +152,19 @@ static int get_exts(void) { exts = (const char *)glGetString(GL_EXTENSIONS); #ifdef _GLAD_IS_SOME_NEW_VERSION } else { - int index; + unsigned int index; num_exts_i = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); if (num_exts_i > 0) { - exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i); + exts_i = (const char **)realloc((void *)exts_i, (size_t)num_exts_i * (sizeof *exts_i)); } if (exts_i == NULL) { return 0; } - for(index = 0; index < num_exts_i; index++) { + for(index = 0; index < (unsigned)num_exts_i; index++) { exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, index); } } @@ -174,7 +174,7 @@ static int get_exts(void) { static void free_exts(void) { if (exts_i != NULL) { - free((char **)exts_i); + free((void *)exts_i); exts_i = NULL; } } diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h index e5eb22e297..cb78df071e 100644 --- a/thirdparty/glad/glad/glad.h +++ b/thirdparty/glad/glad/glad.h @@ -1,6 +1,6 @@ /* - OpenGL loader generated by glad 0.1.13a0 on Fri Jan 6 19:27:07 2017. + OpenGL loader generated by glad 0.1.14a0 on Wed Jun 14 20:12:45 2017. Language/Generator: C/C++ Specification: gl @@ -54,7 +54,7 @@ typedef void* (* GLADloadproc)(const char *name); #ifndef GLAPI # if defined(GLAD_GLAPI_EXPORT) -# if defined(WIN32) || defined(__CYGWIN__) +# if defined(_WIN32) || defined(__CYGWIN__) # if defined(GLAD_GLAPI_EXPORT_BUILD) # if defined(__GNUC__) # define GLAPI __attribute__ ((dllexport)) extern @@ -183,6 +183,7 @@ typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLen typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); typedef unsigned short GLhalfNV; typedef GLintptr GLvdpauSurfaceNV; +typedef void (APIENTRY *GLVULKANPROCNV)(void); #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 @@ -264,7 +265,6 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_BLEND_SRC 0x0BE1 #define GL_BLEND 0x0BE2 #define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_COLOR_LOGIC_OP 0x0BF2 #define GL_DRAW_BUFFER 0x0C01 #define GL_READ_BUFFER 0x0C02 #define GL_SCISSOR_BOX 0x0C10 @@ -292,21 +292,9 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_SUBPIXEL_BITS 0x0D50 #define GL_TEXTURE_1D 0x0DE0 #define GL_TEXTURE_2D 0x0DE1 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_2D 0x8069 #define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_ALPHA_SIZE 0x805F #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 @@ -317,7 +305,6 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 -#define GL_DOUBLE 0x140A #define GL_STACK_OVERFLOW 0x0503 #define GL_STACK_UNDERFLOW 0x0504 #define GL_CLEAR 0x1500 @@ -369,23 +356,7 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 #define GL_REPEAT 0x2901 -#define GL_R3_G3_B2 0x2A10 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B #define GL_CURRENT_BIT 0x00000001 #define GL_POINT_BIT 0x00000002 #define GL_LINE_BIT 0x00000004 @@ -404,9 +375,6 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_TEXTURE_BIT 0x00040000 #define GL_SCISSOR_BIT 0x00080000 #define GL_ALL_ATTRIB_BITS 0xFFFFFFFF -#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 -#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 -#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF #define GL_QUAD_STRIP 0x0008 #define GL_POLYGON 0x0009 #define GL_ACCUM 0x0100 @@ -446,14 +414,6 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_PIXEL_MAP_G_TO_G 0x0C77 #define GL_PIXEL_MAP_B_TO_B 0x0C78 #define GL_PIXEL_MAP_A_TO_A 0x0C79 -#define GL_VERTEX_ARRAY_POINTER 0x808E -#define GL_NORMAL_ARRAY_POINTER 0x808F -#define GL_COLOR_ARRAY_POINTER 0x8090 -#define GL_INDEX_ARRAY_POINTER 0x8091 -#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 -#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 -#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 -#define GL_SELECTION_BUFFER_POINTER 0x0DF3 #define GL_CURRENT_COLOR 0x0B00 #define GL_CURRENT_INDEX 0x0B01 #define GL_CURRENT_NORMAL 0x0B02 @@ -499,11 +459,9 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_PROJECTION_MATRIX 0x0BA7 #define GL_TEXTURE_MATRIX 0x0BA8 #define GL_ATTRIB_STACK_DEPTH 0x0BB0 -#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 #define GL_ALPHA_TEST 0x0BC0 #define GL_ALPHA_TEST_FUNC 0x0BC1 #define GL_ALPHA_TEST_REF 0x0BC2 -#define GL_INDEX_LOGIC_OP 0x0BF1 #define GL_LOGIC_OP 0x0BF1 #define GL_AUX_BUFFERS 0x0C00 #define GL_INDEX_CLEAR_VALUE 0x0C20 @@ -553,7 +511,6 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_MAX_NAME_STACK_DEPTH 0x0D37 #define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 #define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 -#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B #define GL_INDEX_BITS 0x0D51 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 @@ -589,35 +546,8 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_MAP1_GRID_SEGMENTS 0x0DD1 #define GL_MAP2_GRID_DOMAIN 0x0DD2 #define GL_MAP2_GRID_SEGMENTS 0x0DD3 -#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 -#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 -#define GL_SELECTION_BUFFER_SIZE 0x0DF4 -#define GL_VERTEX_ARRAY 0x8074 -#define GL_NORMAL_ARRAY 0x8075 -#define GL_COLOR_ARRAY 0x8076 -#define GL_INDEX_ARRAY 0x8077 -#define GL_TEXTURE_COORD_ARRAY 0x8078 -#define GL_EDGE_FLAG_ARRAY 0x8079 -#define GL_VERTEX_ARRAY_SIZE 0x807A -#define GL_VERTEX_ARRAY_TYPE 0x807B -#define GL_VERTEX_ARRAY_STRIDE 0x807C -#define GL_NORMAL_ARRAY_TYPE 0x807E -#define GL_NORMAL_ARRAY_STRIDE 0x807F -#define GL_COLOR_ARRAY_SIZE 0x8081 -#define GL_COLOR_ARRAY_TYPE 0x8082 -#define GL_COLOR_ARRAY_STRIDE 0x8083 -#define GL_INDEX_ARRAY_TYPE 0x8085 -#define GL_INDEX_ARRAY_STRIDE 0x8086 -#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 -#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 -#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A -#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C #define GL_TEXTURE_COMPONENTS 0x1003 #define GL_TEXTURE_BORDER 0x1005 -#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 -#define GL_TEXTURE_INTENSITY_SIZE 0x8061 -#define GL_TEXTURE_PRIORITY 0x8066 -#define GL_TEXTURE_RESIDENT 0x8067 #define GL_AMBIENT 0x1200 #define GL_DIFFUSE 0x1201 #define GL_SPECULAR 0x1202 @@ -664,6 +594,91 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_OBJECT_PLANE 0x2501 #define GL_EYE_PLANE 0x2502 #define GL_CLAMP 0x2900 +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DOUBLE 0x140A +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RESIDENT 0x8067 #define GL_ALPHA4 0x803B #define GL_ALPHA8 0x803C #define GL_ALPHA12 0x803D @@ -697,20 +712,6 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_T2F_N3F_V3F 0x2A2B #define GL_T2F_C4F_N3F_V3F 0x2A2C #define GL_T4F_C4F_N3F_V4F 0x2A2D -#define GL_CLIP_PLANE0 0x3000 -#define GL_CLIP_PLANE1 0x3001 -#define GL_CLIP_PLANE2 0x3002 -#define GL_CLIP_PLANE3 0x3003 -#define GL_CLIP_PLANE4 0x3004 -#define GL_CLIP_PLANE5 0x3005 -#define GL_LIGHT0 0x4000 -#define GL_LIGHT1 0x4001 -#define GL_LIGHT2 0x4002 -#define GL_LIGHT3 0x4003 -#define GL_LIGHT4 0x4004 -#define GL_LIGHT5 0x4005 -#define GL_LIGHT6 0x4006 -#define GL_LIGHT7 0x4007 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 diff --git a/thirdparty/rg-etc1/rg_etc1.cpp b/thirdparty/rg-etc1/rg_etc1.cpp deleted file mode 100644 index 8e28b53f9d..0000000000 --- a/thirdparty/rg-etc1/rg_etc1.cpp +++ /dev/null @@ -1,2446 +0,0 @@ -// File: rg_etc1.cpp - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com> -// Please see ZLIB license at the end of rg_etc1.h. -// -// For more information Ericsson Texture Compression (ETC/ETC1), see: -// http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt -// -// v1.04 - 5/15/14 - Fix signed vs. unsigned subtraction problem (noticed when compiled with gcc) in pack_etc1_block_init(). -// This issue would cause an assert when this func. was called in debug. (Note this module was developed/testing with MSVC, -// I still need to test it throughly when compiled with gcc.) -// -// v1.03 - 5/12/13 - Initial public release -#include "rg_etc1.h" - -#include <stdlib.h> -#include <memory.h> -#include <assert.h> -//#include <stdio.h> -#include <math.h> - -#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union - -#if defined(_DEBUG) || defined(DEBUG) -#define RG_ETC1_BUILD_DEBUG -#endif - -#define RG_ETC1_ASSERT assert - -namespace rg_etc1 -{ - typedef unsigned char uint8; - typedef unsigned short uint16; - typedef unsigned int uint; - typedef unsigned int uint32; - typedef long long int64; - typedef unsigned long long uint64; - - const uint32 cUINT32_MAX = 0xFFFFFFFFU; - const uint64 cUINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64; - - template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; } - template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); } - template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; } - template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); } - template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); } - template<typename T> inline T square(T value) { return value * value; } - template<typename T> inline void zero_object(T& obj) { memset((void*)&obj, 0, sizeof(obj)); } - template<typename T> inline void zero_this(T* pObj) { memset((void*)pObj, 0, sizeof(*pObj)); } - - template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]); - -#define RG_ETC1_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X))) - - enum eNoClamp { cNoClamp }; - - struct color_quad_u8 - { - static inline int clamp(int v) { if (v & 0xFFFFFF00U) v = (~(static_cast<int>(v) >> 31)) & 0xFF; return v; } - - struct component_traits { enum { cSigned = false, cFloat = false, cMin = 0U, cMax = 255U }; }; - - public: - typedef unsigned char component_t; - typedef int parameter_t; - - enum { cNumComps = 4 }; - - union - { - struct - { - component_t r; - component_t g; - component_t b; - component_t a; - }; - - component_t c[cNumComps]; - - uint32 m_u32; - }; - - inline color_quad_u8() - { - } - - inline color_quad_u8(const color_quad_u8& other) : m_u32(other.m_u32) - { - } - - explicit inline color_quad_u8(parameter_t y, parameter_t alpha = component_traits::cMax) - { - set(y, alpha); - } - - inline color_quad_u8(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax) - { - set(red, green, blue, alpha); - } - - explicit inline color_quad_u8(eNoClamp, parameter_t y, parameter_t alpha = component_traits::cMax) - { - set_noclamp_y_alpha(y, alpha); - } - - inline color_quad_u8(eNoClamp, parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax) - { - set_noclamp_rgba(red, green, blue, alpha); - } - - inline void clear() - { - m_u32 = 0; - } - - inline color_quad_u8& operator= (const color_quad_u8& other) - { - m_u32 = other.m_u32; - return *this; - } - - inline color_quad_u8& set_rgb(const color_quad_u8& other) - { - r = other.r; - g = other.g; - b = other.b; - return *this; - } - - inline color_quad_u8& operator= (parameter_t y) - { - set(y, component_traits::cMax); - return *this; - } - - inline color_quad_u8& set(parameter_t y, parameter_t alpha = component_traits::cMax) - { - y = clamp(y); - alpha = clamp(alpha); - r = static_cast<component_t>(y); - g = static_cast<component_t>(y); - b = static_cast<component_t>(y); - a = static_cast<component_t>(alpha); - return *this; - } - - inline color_quad_u8& set_noclamp_y_alpha(parameter_t y, parameter_t alpha = component_traits::cMax) - { - RG_ETC1_ASSERT( (y >= component_traits::cMin) && (y <= component_traits::cMax) ); - RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) ); - - r = static_cast<component_t>(y); - g = static_cast<component_t>(y); - b = static_cast<component_t>(y); - a = static_cast<component_t>(alpha); - return *this; - } - - inline color_quad_u8& set(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax) - { - r = static_cast<component_t>(clamp(red)); - g = static_cast<component_t>(clamp(green)); - b = static_cast<component_t>(clamp(blue)); - a = static_cast<component_t>(clamp(alpha)); - return *this; - } - - inline color_quad_u8& set_noclamp_rgba(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha) - { - RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) ); - RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) ); - RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) ); - RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) ); - - r = static_cast<component_t>(red); - g = static_cast<component_t>(green); - b = static_cast<component_t>(blue); - a = static_cast<component_t>(alpha); - return *this; - } - - inline color_quad_u8& set_noclamp_rgb(parameter_t red, parameter_t green, parameter_t blue) - { - RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) ); - RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) ); - RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) ); - - r = static_cast<component_t>(red); - g = static_cast<component_t>(green); - b = static_cast<component_t>(blue); - return *this; - } - - static inline parameter_t get_min_comp() { return component_traits::cMin; } - static inline parameter_t get_max_comp() { return component_traits::cMax; } - static inline bool get_comps_are_signed() { return component_traits::cSigned; } - - inline component_t operator[] (uint i) const { RG_ETC1_ASSERT(i < cNumComps); return c[i]; } - inline component_t& operator[] (uint i) { RG_ETC1_ASSERT(i < cNumComps); return c[i]; } - - inline color_quad_u8& set_component(uint i, parameter_t f) - { - RG_ETC1_ASSERT(i < cNumComps); - - c[i] = static_cast<component_t>(clamp(f)); - - return *this; - } - - inline color_quad_u8& set_grayscale(parameter_t l) - { - component_t x = static_cast<component_t>(clamp(l)); - c[0] = x; - c[1] = x; - c[2] = x; - return *this; - } - - inline color_quad_u8& clamp(const color_quad_u8& l, const color_quad_u8& h) - { - for (uint i = 0; i < cNumComps; i++) - c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l[i], h[i])); - return *this; - } - - inline color_quad_u8& clamp(parameter_t l, parameter_t h) - { - for (uint i = 0; i < cNumComps; i++) - c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l, h)); - return *this; - } - - // Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y). - inline parameter_t get_luma() const - { - return static_cast<parameter_t>((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U); - } - - // Returns REC 709 luma. - inline parameter_t get_luma_rec709() const - { - return static_cast<parameter_t>((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U); - } - - inline uint squared_distance_rgb(const color_quad_u8& c) const - { - return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b); - } - - inline uint squared_distance_rgba(const color_quad_u8& c) const - { - return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b) + rg_etc1::square(a - c.a); - } - - inline bool rgb_equals(const color_quad_u8& rhs) const - { - return (r == rhs.r) && (g == rhs.g) && (b == rhs.b); - } - - inline bool operator== (const color_quad_u8& rhs) const - { - return m_u32 == rhs.m_u32; - } - - color_quad_u8& operator+= (const color_quad_u8& other) - { - for (uint i = 0; i < 4; i++) - c[i] = static_cast<component_t>(clamp(c[i] + other.c[i])); - return *this; - } - - color_quad_u8& operator-= (const color_quad_u8& other) - { - for (uint i = 0; i < 4; i++) - c[i] = static_cast<component_t>(clamp(c[i] - other.c[i])); - return *this; - } - - friend color_quad_u8 operator+ (const color_quad_u8& lhs, const color_quad_u8& rhs) - { - color_quad_u8 result(lhs); - result += rhs; - return result; - } - - friend color_quad_u8 operator- (const color_quad_u8& lhs, const color_quad_u8& rhs) - { - color_quad_u8 result(lhs); - result -= rhs; - return result; - } - }; // class color_quad_u8 - - struct vec3F - { - float m_s[3]; - - inline vec3F() { } - inline vec3F(float s) { m_s[0] = s; m_s[1] = s; m_s[2] = s; } - inline vec3F(float x, float y, float z) { m_s[0] = x; m_s[1] = y; m_s[2] = z; } - - inline float operator[] (uint i) const { RG_ETC1_ASSERT(i < 3); return m_s[i]; } - - inline vec3F& operator += (const vec3F& other) { for (uint i = 0; i < 3; i++) m_s[i] += other.m_s[i]; return *this; } - - inline vec3F& operator *= (float s) { for (uint i = 0; i < 3; i++) m_s[i] *= s; return *this; } - }; - - enum etc_constants - { - cETC1BytesPerBlock = 8U, - - cETC1SelectorBits = 2U, - cETC1SelectorValues = 1U << cETC1SelectorBits, - cETC1SelectorMask = cETC1SelectorValues - 1U, - - cETC1BlockShift = 2U, - cETC1BlockSize = 1U << cETC1BlockShift, - - cETC1LSBSelectorIndicesBitOffset = 0, - cETC1MSBSelectorIndicesBitOffset = 16, - - cETC1FlipBitOffset = 32, - cETC1DiffBitOffset = 33, - - cETC1IntenModifierNumBits = 3, - cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits, - cETC1RightIntenModifierTableBitOffset = 34, - cETC1LeftIntenModifierTableBitOffset = 37, - - // Base+Delta encoding (5 bit bases, 3 bit delta) - cETC1BaseColorCompNumBits = 5, - cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits, - - cETC1DeltaColorCompNumBits = 3, - cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits, - cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits, - - cETC1BaseColor5RBitOffset = 59, - cETC1BaseColor5GBitOffset = 51, - cETC1BaseColor5BBitOffset = 43, - - cETC1DeltaColor3RBitOffset = 56, - cETC1DeltaColor3GBitOffset = 48, - cETC1DeltaColor3BBitOffset = 40, - - // Absolute (non-delta) encoding (two 4-bit per component bases) - cETC1AbsColorCompNumBits = 4, - cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits, - - cETC1AbsColor4R1BitOffset = 60, - cETC1AbsColor4G1BitOffset = 52, - cETC1AbsColor4B1BitOffset = 44, - - cETC1AbsColor4R2BitOffset = 56, - cETC1AbsColor4G2BitOffset = 48, - cETC1AbsColor4B2BitOffset = 40, - - cETC1ColorDeltaMin = -4, - cETC1ColorDeltaMax = 3, - - // Delta3: - // 0 1 2 3 4 5 6 7 - // 000 001 010 011 100 101 110 111 - // 0 1 2 3 -4 -3 -2 -1 - }; - - static uint8 g_quant5_tab[256+16]; - - static const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] = - { - { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 }, - { -60, -18, 18, 60 }, { -80, -24, 24, 80 }, { -106, -33, 33, 106 }, { -183, -47, 47, 183 } - }; - - static const uint8 g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 }; - static const uint8 g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 }; - - // Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte. - static uint16 g_etc1_inverse_lookup[2*8*4][256]; // [diff/inten_table/selector][desired_color] - - // g_color8_to_etc_block_config[color][table_index] = Supplies for each 8-bit color value a list of packed ETC1 diff/intensity table/selectors/packed_colors that map to that color. - // To pack: diff | (inten << 1) | (selector << 4) | (packed_c << 8) - static const uint16 g_color8_to_etc_block_config_0_255[2][33] = - { - { 0x0000, 0x0010, 0x0002, 0x0012, 0x0004, 0x0014, 0x0006, 0x0016, 0x0008, 0x0018, 0x000A, 0x001A, 0x000C, 0x001C, 0x000E, 0x001E, - 0x0001, 0x0011, 0x0003, 0x0013, 0x0005, 0x0015, 0x0007, 0x0017, 0x0009, 0x0019, 0x000B, 0x001B, 0x000D, 0x001D, 0x000F, 0x001F, 0xFFFF }, - { 0x0F20, 0x0F30, 0x0E32, 0x0F22, 0x0E34, 0x0F24, 0x0D36, 0x0F26, 0x0C38, 0x0E28, 0x0B3A, 0x0E2A, 0x093C, 0x0E2C, 0x053E, 0x0D2E, - 0x1E31, 0x1F21, 0x1D33, 0x1F23, 0x1C35, 0x1E25, 0x1A37, 0x1E27, 0x1839, 0x1D29, 0x163B, 0x1C2B, 0x133D, 0x1B2D, 0x093F, 0x1A2F, 0xFFFF }, - }; - - // Really only [254][11]. - static const uint16 g_color8_to_etc_block_config_1_to_254[254][12] = - { - { 0x021C, 0x0D0D, 0xFFFF }, { 0x0020, 0x0021, 0x0A0B, 0x061F, 0xFFFF }, { 0x0113, 0x0217, 0xFFFF }, { 0x0116, 0x031E, - 0x0B0E, 0x0405, 0xFFFF }, { 0x0022, 0x0204, 0x050A, 0x0023, 0xFFFF }, { 0x0111, 0x0319, 0x0809, 0x170F, 0xFFFF }, { - 0x0303, 0x0215, 0x0607, 0xFFFF }, { 0x0030, 0x0114, 0x0408, 0x0031, 0x0201, 0x051D, 0xFFFF }, { 0x0100, 0x0024, 0x0306, - 0x0025, 0x041B, 0x0E0D, 0xFFFF }, { 0x021A, 0x0121, 0x0B0B, 0x071F, 0xFFFF }, { 0x0213, 0x0317, 0xFFFF }, { 0x0112, - 0x0505, 0xFFFF }, { 0x0026, 0x070C, 0x0123, 0x0027, 0xFFFF }, { 0x0211, 0x0909, 0xFFFF }, { 0x0110, 0x0315, 0x0707, - 0x0419, 0x180F, 0xFFFF }, { 0x0218, 0x0131, 0x0301, 0x0403, 0x061D, 0xFFFF }, { 0x0032, 0x0202, 0x0033, 0x0125, 0x051B, - 0x0F0D, 0xFFFF }, { 0x0028, 0x031C, 0x0221, 0x0029, 0xFFFF }, { 0x0120, 0x0313, 0x0C0B, 0x081F, 0xFFFF }, { 0x0605, - 0x0417, 0xFFFF }, { 0x0216, 0x041E, 0x0C0E, 0x0223, 0x0127, 0xFFFF }, { 0x0122, 0x0304, 0x060A, 0x0311, 0x0A09, 0xFFFF - }, { 0x0519, 0x190F, 0xFFFF }, { 0x002A, 0x0231, 0x0503, 0x0415, 0x0807, 0x002B, 0x071D, 0xFFFF }, { 0x0130, 0x0214, - 0x0508, 0x0401, 0x0133, 0x0225, 0x061B, 0xFFFF }, { 0x0200, 0x0124, 0x0406, 0x0321, 0x0129, 0x100D, 0xFFFF }, { 0x031A, - 0x0D0B, 0x091F, 0xFFFF }, { 0x0413, 0x0705, 0x0517, 0xFFFF }, { 0x0212, 0x0034, 0x0323, 0x0035, 0x0227, 0xFFFF }, { - 0x0126, 0x080C, 0x0B09, 0xFFFF }, { 0x0411, 0x0619, 0x1A0F, 0xFFFF }, { 0x0210, 0x0331, 0x0603, 0x0515, 0x0907, 0x012B, - 0xFFFF }, { 0x0318, 0x002C, 0x0501, 0x0233, 0x0325, 0x071B, 0x002D, 0x081D, 0xFFFF }, { 0x0132, 0x0302, 0x0229, 0x110D, - 0xFFFF }, { 0x0128, 0x041C, 0x0421, 0x0E0B, 0x0A1F, 0xFFFF }, { 0x0220, 0x0513, 0x0617, 0xFFFF }, { 0x0135, 0x0805, - 0x0327, 0xFFFF }, { 0x0316, 0x051E, 0x0D0E, 0x0423, 0xFFFF }, { 0x0222, 0x0404, 0x070A, 0x0511, 0x0719, 0x0C09, 0x1B0F, - 0xFFFF }, { 0x0703, 0x0615, 0x0A07, 0x022B, 0xFFFF }, { 0x012A, 0x0431, 0x0601, 0x0333, 0x012D, 0x091D, 0xFFFF }, { - 0x0230, 0x0314, 0x0036, 0x0608, 0x0425, 0x0037, 0x0329, 0x081B, 0x120D, 0xFFFF }, { 0x0300, 0x0224, 0x0506, 0x0521, - 0x0F0B, 0x0B1F, 0xFFFF }, { 0x041A, 0x0613, 0x0717, 0xFFFF }, { 0x0235, 0x0905, 0xFFFF }, { 0x0312, 0x0134, 0x0523, - 0x0427, 0xFFFF }, { 0x0226, 0x090C, 0x002E, 0x0611, 0x0D09, 0x002F, 0xFFFF }, { 0x0715, 0x0B07, 0x0819, 0x032B, 0x1C0F, - 0xFFFF }, { 0x0310, 0x0531, 0x0701, 0x0803, 0x022D, 0x0A1D, 0xFFFF }, { 0x0418, 0x012C, 0x0433, 0x0525, 0x0137, 0x091B, - 0x130D, 0xFFFF }, { 0x0232, 0x0402, 0x0621, 0x0429, 0xFFFF }, { 0x0228, 0x051C, 0x0713, 0x100B, 0x0C1F, 0xFFFF }, { - 0x0320, 0x0335, 0x0A05, 0x0817, 0xFFFF }, { 0x0623, 0x0527, 0xFFFF }, { 0x0416, 0x061E, 0x0E0E, 0x0711, 0x0E09, 0x012F, - 0xFFFF }, { 0x0322, 0x0504, 0x080A, 0x0919, 0x1D0F, 0xFFFF }, { 0x0631, 0x0903, 0x0815, 0x0C07, 0x042B, 0x032D, 0x0B1D, - 0xFFFF }, { 0x022A, 0x0801, 0x0533, 0x0625, 0x0237, 0x0A1B, 0xFFFF }, { 0x0330, 0x0414, 0x0136, 0x0708, 0x0721, 0x0529, - 0x140D, 0xFFFF }, { 0x0400, 0x0324, 0x0606, 0x0038, 0x0039, 0x110B, 0x0D1F, 0xFFFF }, { 0x051A, 0x0813, 0x0B05, 0x0917, - 0xFFFF }, { 0x0723, 0x0435, 0x0627, 0xFFFF }, { 0x0412, 0x0234, 0x0F09, 0x022F, 0xFFFF }, { 0x0326, 0x0A0C, 0x012E, - 0x0811, 0x0A19, 0x1E0F, 0xFFFF }, { 0x0731, 0x0A03, 0x0915, 0x0D07, 0x052B, 0xFFFF }, { 0x0410, 0x0901, 0x0633, 0x0725, - 0x0337, 0x0B1B, 0x042D, 0x0C1D, 0xFFFF }, { 0x0518, 0x022C, 0x0629, 0x150D, 0xFFFF }, { 0x0332, 0x0502, 0x0821, 0x0139, - 0x120B, 0x0E1F, 0xFFFF }, { 0x0328, 0x061C, 0x0913, 0x0A17, 0xFFFF }, { 0x0420, 0x0535, 0x0C05, 0x0727, 0xFFFF }, { - 0x0823, 0x032F, 0xFFFF }, { 0x0516, 0x071E, 0x0F0E, 0x0911, 0x0B19, 0x1009, 0x1F0F, 0xFFFF }, { 0x0422, 0x0604, 0x090A, - 0x0B03, 0x0A15, 0x0E07, 0x062B, 0xFFFF }, { 0x0831, 0x0A01, 0x0733, 0x052D, 0x0D1D, 0xFFFF }, { 0x032A, 0x0825, 0x0437, - 0x0729, 0x0C1B, 0x160D, 0xFFFF }, { 0x0430, 0x0514, 0x0236, 0x0808, 0x0921, 0x0239, 0x130B, 0x0F1F, 0xFFFF }, { 0x0500, - 0x0424, 0x0706, 0x0138, 0x0A13, 0x0B17, 0xFFFF }, { 0x061A, 0x0635, 0x0D05, 0xFFFF }, { 0x0923, 0x0827, 0xFFFF }, { - 0x0512, 0x0334, 0x003A, 0x0A11, 0x1109, 0x003B, 0x042F, 0xFFFF }, { 0x0426, 0x0B0C, 0x022E, 0x0B15, 0x0F07, 0x0C19, - 0x072B, 0xFFFF }, { 0x0931, 0x0B01, 0x0C03, 0x062D, 0x0E1D, 0xFFFF }, { 0x0510, 0x0833, 0x0925, 0x0537, 0x0D1B, 0x170D, - 0xFFFF }, { 0x0618, 0x032C, 0x0A21, 0x0339, 0x0829, 0xFFFF }, { 0x0432, 0x0602, 0x0B13, 0x140B, 0x101F, 0xFFFF }, { - 0x0428, 0x071C, 0x0735, 0x0E05, 0x0C17, 0xFFFF }, { 0x0520, 0x0A23, 0x0927, 0xFFFF }, { 0x0B11, 0x1209, 0x013B, 0x052F, - 0xFFFF }, { 0x0616, 0x081E, 0x0D19, 0xFFFF }, { 0x0522, 0x0704, 0x0A0A, 0x0A31, 0x0D03, 0x0C15, 0x1007, 0x082B, 0x072D, - 0x0F1D, 0xFFFF }, { 0x0C01, 0x0933, 0x0A25, 0x0637, 0x0E1B, 0xFFFF }, { 0x042A, 0x0B21, 0x0929, 0x180D, 0xFFFF }, { - 0x0530, 0x0614, 0x0336, 0x0908, 0x0439, 0x150B, 0x111F, 0xFFFF }, { 0x0600, 0x0524, 0x0806, 0x0238, 0x0C13, 0x0F05, - 0x0D17, 0xFFFF }, { 0x071A, 0x0B23, 0x0835, 0x0A27, 0xFFFF }, { 0x1309, 0x023B, 0x062F, 0xFFFF }, { 0x0612, 0x0434, - 0x013A, 0x0C11, 0x0E19, 0xFFFF }, { 0x0526, 0x0C0C, 0x032E, 0x0B31, 0x0E03, 0x0D15, 0x1107, 0x092B, 0xFFFF }, { 0x0D01, - 0x0A33, 0x0B25, 0x0737, 0x0F1B, 0x082D, 0x101D, 0xFFFF }, { 0x0610, 0x0A29, 0x190D, 0xFFFF }, { 0x0718, 0x042C, 0x0C21, - 0x0539, 0x160B, 0x121F, 0xFFFF }, { 0x0532, 0x0702, 0x0D13, 0x0E17, 0xFFFF }, { 0x0528, 0x081C, 0x0935, 0x1005, 0x0B27, - 0xFFFF }, { 0x0620, 0x0C23, 0x033B, 0x072F, 0xFFFF }, { 0x0D11, 0x0F19, 0x1409, 0xFFFF }, { 0x0716, 0x003C, 0x091E, - 0x0F03, 0x0E15, 0x1207, 0x0A2B, 0x003D, 0xFFFF }, { 0x0622, 0x0804, 0x0B0A, 0x0C31, 0x0E01, 0x0B33, 0x092D, 0x111D, - 0xFFFF }, { 0x0C25, 0x0837, 0x0B29, 0x101B, 0x1A0D, 0xFFFF }, { 0x052A, 0x0D21, 0x0639, 0x170B, 0x131F, 0xFFFF }, { - 0x0630, 0x0714, 0x0436, 0x0A08, 0x0E13, 0x0F17, 0xFFFF }, { 0x0700, 0x0624, 0x0906, 0x0338, 0x0A35, 0x1105, 0xFFFF }, { - 0x081A, 0x0D23, 0x0C27, 0xFFFF }, { 0x0E11, 0x1509, 0x043B, 0x082F, 0xFFFF }, { 0x0712, 0x0534, 0x023A, 0x0F15, 0x1307, - 0x1019, 0x0B2B, 0x013D, 0xFFFF }, { 0x0626, 0x0D0C, 0x042E, 0x0D31, 0x0F01, 0x1003, 0x0A2D, 0x121D, 0xFFFF }, { 0x0C33, - 0x0D25, 0x0937, 0x111B, 0x1B0D, 0xFFFF }, { 0x0710, 0x0E21, 0x0739, 0x0C29, 0xFFFF }, { 0x0818, 0x052C, 0x0F13, 0x180B, - 0x141F, 0xFFFF }, { 0x0632, 0x0802, 0x0B35, 0x1205, 0x1017, 0xFFFF }, { 0x0628, 0x091C, 0x0E23, 0x0D27, 0xFFFF }, { - 0x0720, 0x0F11, 0x1609, 0x053B, 0x092F, 0xFFFF }, { 0x1119, 0x023D, 0xFFFF }, { 0x0816, 0x013C, 0x0A1E, 0x0E31, 0x1103, - 0x1015, 0x1407, 0x0C2B, 0x0B2D, 0x131D, 0xFFFF }, { 0x0722, 0x0904, 0x0C0A, 0x1001, 0x0D33, 0x0E25, 0x0A37, 0x121B, - 0xFFFF }, { 0x0F21, 0x0D29, 0x1C0D, 0xFFFF }, { 0x062A, 0x0839, 0x190B, 0x151F, 0xFFFF }, { 0x0730, 0x0814, 0x0536, - 0x0B08, 0x1013, 0x1305, 0x1117, 0xFFFF }, { 0x0800, 0x0724, 0x0A06, 0x0438, 0x0F23, 0x0C35, 0x0E27, 0xFFFF }, { 0x091A, - 0x1709, 0x063B, 0x0A2F, 0xFFFF }, { 0x1011, 0x1219, 0x033D, 0xFFFF }, { 0x0812, 0x0634, 0x033A, 0x0F31, 0x1203, 0x1115, - 0x1507, 0x0D2B, 0xFFFF }, { 0x0726, 0x0E0C, 0x052E, 0x1101, 0x0E33, 0x0F25, 0x0B37, 0x131B, 0x0C2D, 0x141D, 0xFFFF }, { - 0x0E29, 0x1D0D, 0xFFFF }, { 0x0810, 0x1021, 0x0939, 0x1A0B, 0x161F, 0xFFFF }, { 0x0918, 0x062C, 0x1113, 0x1217, 0xFFFF - }, { 0x0732, 0x0902, 0x0D35, 0x1405, 0x0F27, 0xFFFF }, { 0x0728, 0x0A1C, 0x1023, 0x073B, 0x0B2F, 0xFFFF }, { 0x0820, - 0x1111, 0x1319, 0x1809, 0xFFFF }, { 0x1303, 0x1215, 0x1607, 0x0E2B, 0x043D, 0xFFFF }, { 0x0916, 0x023C, 0x0B1E, 0x1031, - 0x1201, 0x0F33, 0x0D2D, 0x151D, 0xFFFF }, { 0x0822, 0x0A04, 0x0D0A, 0x1025, 0x0C37, 0x0F29, 0x141B, 0x1E0D, 0xFFFF }, { - 0x1121, 0x0A39, 0x1B0B, 0x171F, 0xFFFF }, { 0x072A, 0x1213, 0x1317, 0xFFFF }, { 0x0830, 0x0914, 0x0636, 0x0C08, 0x0E35, - 0x1505, 0xFFFF }, { 0x0900, 0x0824, 0x0B06, 0x0538, 0x1123, 0x1027, 0xFFFF }, { 0x0A1A, 0x1211, 0x1909, 0x083B, 0x0C2F, - 0xFFFF }, { 0x1315, 0x1707, 0x1419, 0x0F2B, 0x053D, 0xFFFF }, { 0x0912, 0x0734, 0x043A, 0x1131, 0x1301, 0x1403, 0x0E2D, - 0x161D, 0xFFFF }, { 0x0826, 0x0F0C, 0x062E, 0x1033, 0x1125, 0x0D37, 0x151B, 0x1F0D, 0xFFFF }, { 0x1221, 0x0B39, 0x1029, - 0xFFFF }, { 0x0910, 0x1313, 0x1C0B, 0x181F, 0xFFFF }, { 0x0A18, 0x072C, 0x0F35, 0x1605, 0x1417, 0xFFFF }, { 0x0832, - 0x0A02, 0x1223, 0x1127, 0xFFFF }, { 0x0828, 0x0B1C, 0x1311, 0x1A09, 0x093B, 0x0D2F, 0xFFFF }, { 0x0920, 0x1519, 0x063D, - 0xFFFF }, { 0x1231, 0x1503, 0x1415, 0x1807, 0x102B, 0x0F2D, 0x171D, 0xFFFF }, { 0x0A16, 0x033C, 0x0C1E, 0x1401, 0x1133, - 0x1225, 0x0E37, 0x161B, 0xFFFF }, { 0x0922, 0x0B04, 0x0E0A, 0x1321, 0x1129, 0xFFFF }, { 0x0C39, 0x1D0B, 0x191F, 0xFFFF - }, { 0x082A, 0x1413, 0x1705, 0x1517, 0xFFFF }, { 0x0930, 0x0A14, 0x0736, 0x0D08, 0x1323, 0x1035, 0x1227, 0xFFFF }, { - 0x0A00, 0x0924, 0x0C06, 0x0638, 0x1B09, 0x0A3B, 0x0E2F, 0xFFFF }, { 0x0B1A, 0x1411, 0x1619, 0x073D, 0xFFFF }, { 0x1331, - 0x1603, 0x1515, 0x1907, 0x112B, 0xFFFF }, { 0x0A12, 0x0834, 0x053A, 0x1501, 0x1233, 0x1325, 0x0F37, 0x171B, 0x102D, - 0x181D, 0xFFFF }, { 0x0926, 0x072E, 0x1229, 0xFFFF }, { 0x1421, 0x0D39, 0x1E0B, 0x1A1F, 0xFFFF }, { 0x0A10, 0x1513, - 0x1617, 0xFFFF }, { 0x0B18, 0x082C, 0x1135, 0x1805, 0x1327, 0xFFFF }, { 0x0932, 0x0B02, 0x1423, 0x0B3B, 0x0F2F, 0xFFFF - }, { 0x0928, 0x0C1C, 0x1511, 0x1719, 0x1C09, 0xFFFF }, { 0x0A20, 0x1703, 0x1615, 0x1A07, 0x122B, 0x083D, 0xFFFF }, { - 0x1431, 0x1601, 0x1333, 0x112D, 0x191D, 0xFFFF }, { 0x0B16, 0x043C, 0x0D1E, 0x1425, 0x1037, 0x1329, 0x181B, 0xFFFF }, { - 0x0A22, 0x0C04, 0x0F0A, 0x1521, 0x0E39, 0x1F0B, 0x1B1F, 0xFFFF }, { 0x1613, 0x1717, 0xFFFF }, { 0x092A, 0x1235, 0x1905, - 0xFFFF }, { 0x0A30, 0x0B14, 0x0836, 0x0E08, 0x1523, 0x1427, 0xFFFF }, { 0x0B00, 0x0A24, 0x0D06, 0x0738, 0x1611, 0x1D09, - 0x0C3B, 0x102F, 0xFFFF }, { 0x0C1A, 0x1715, 0x1B07, 0x1819, 0x132B, 0x093D, 0xFFFF }, { 0x1531, 0x1701, 0x1803, 0x122D, - 0x1A1D, 0xFFFF }, { 0x0B12, 0x0934, 0x063A, 0x1433, 0x1525, 0x1137, 0x191B, 0xFFFF }, { 0x0A26, 0x003E, 0x082E, 0x1621, - 0x0F39, 0x1429, 0x003F, 0xFFFF }, { 0x1713, 0x1C1F, 0xFFFF }, { 0x0B10, 0x1335, 0x1A05, 0x1817, 0xFFFF }, { 0x0C18, - 0x092C, 0x1623, 0x1527, 0xFFFF }, { 0x0A32, 0x0C02, 0x1711, 0x1E09, 0x0D3B, 0x112F, 0xFFFF }, { 0x0A28, 0x0D1C, 0x1919, - 0x0A3D, 0xFFFF }, { 0x0B20, 0x1631, 0x1903, 0x1815, 0x1C07, 0x142B, 0x132D, 0x1B1D, 0xFFFF }, { 0x1801, 0x1533, 0x1625, - 0x1237, 0x1A1B, 0xFFFF }, { 0x0C16, 0x053C, 0x0E1E, 0x1721, 0x1529, 0x013F, 0xFFFF }, { 0x0B22, 0x0D04, 0x1039, 0x1D1F, - 0xFFFF }, { 0x1813, 0x1B05, 0x1917, 0xFFFF }, { 0x0A2A, 0x1723, 0x1435, 0x1627, 0xFFFF }, { 0x0B30, 0x0C14, 0x0936, - 0x0F08, 0x1F09, 0x0E3B, 0x122F, 0xFFFF }, { 0x0C00, 0x0B24, 0x0E06, 0x0838, 0x1811, 0x1A19, 0x0B3D, 0xFFFF }, { 0x0D1A, - 0x1731, 0x1A03, 0x1915, 0x1D07, 0x152B, 0xFFFF }, { 0x1901, 0x1633, 0x1725, 0x1337, 0x1B1B, 0x142D, 0x1C1D, 0xFFFF }, { - 0x0C12, 0x0A34, 0x073A, 0x1629, 0x023F, 0xFFFF }, { 0x0B26, 0x013E, 0x092E, 0x1821, 0x1139, 0x1E1F, 0xFFFF }, { 0x1913, - 0x1A17, 0xFFFF }, { 0x0C10, 0x1535, 0x1C05, 0x1727, 0xFFFF }, { 0x0D18, 0x0A2C, 0x1823, 0x0F3B, 0x132F, 0xFFFF }, { - 0x0B32, 0x0D02, 0x1911, 0x1B19, 0xFFFF }, { 0x0B28, 0x0E1C, 0x1B03, 0x1A15, 0x1E07, 0x162B, 0x0C3D, 0xFFFF }, { 0x0C20, - 0x1831, 0x1A01, 0x1733, 0x152D, 0x1D1D, 0xFFFF }, { 0x1825, 0x1437, 0x1729, 0x1C1B, 0x033F, 0xFFFF }, { 0x0D16, 0x063C, - 0x0F1E, 0x1921, 0x1239, 0x1F1F, 0xFFFF }, { 0x0C22, 0x0E04, 0x1A13, 0x1B17, 0xFFFF }, { 0x1635, 0x1D05, 0xFFFF }, { - 0x0B2A, 0x1923, 0x1827, 0xFFFF }, { 0x0C30, 0x0D14, 0x0A36, 0x1A11, 0x103B, 0x142F, 0xFFFF }, { 0x0D00, 0x0C24, 0x0F06, - 0x0938, 0x1B15, 0x1F07, 0x1C19, 0x172B, 0x0D3D, 0xFFFF }, { 0x0E1A, 0x1931, 0x1B01, 0x1C03, 0x162D, 0x1E1D, 0xFFFF }, { - 0x1833, 0x1925, 0x1537, 0x1D1B, 0xFFFF }, { 0x0D12, 0x0B34, 0x083A, 0x1A21, 0x1339, 0x1829, 0x043F, 0xFFFF }, { 0x0C26, - 0x023E, 0x0A2E, 0x1B13, 0xFFFF }, { 0x1735, 0x1E05, 0x1C17, 0xFFFF }, { 0x0D10, 0x1A23, 0x1927, 0xFFFF }, { 0x0E18, - 0x0B2C, 0x1B11, 0x113B, 0x152F, 0xFFFF }, { 0x0C32, 0x0E02, 0x1D19, 0x0E3D, 0xFFFF }, { 0x0C28, 0x0F1C, 0x1A31, 0x1D03, - 0x1C15, 0x182B, 0x172D, 0x1F1D, 0xFFFF }, { 0x0D20, 0x1C01, 0x1933, 0x1A25, 0x1637, 0x1E1B, 0xFFFF }, { 0x1B21, 0x1929, - 0x053F, 0xFFFF }, { 0x0E16, 0x073C, 0x1439, 0xFFFF }, { 0x0D22, 0x0F04, 0x1C13, 0x1F05, 0x1D17, 0xFFFF }, { 0x1B23, - 0x1835, 0x1A27, 0xFFFF }, { 0x0C2A, 0x123B, 0x162F, 0xFFFF }, { 0x0D30, 0x0E14, 0x0B36, 0x1C11, 0x1E19, 0x0F3D, 0xFFFF - }, { 0x0E00, 0x0D24, 0x0A38, 0x1B31, 0x1E03, 0x1D15, 0x192B, 0xFFFF }, { 0x0F1A, 0x1D01, 0x1A33, 0x1B25, 0x1737, 0x1F1B, - 0x182D, 0xFFFF }, { 0x1A29, 0x063F, 0xFFFF }, { 0x0E12, 0x0C34, 0x093A, 0x1C21, 0x1539, 0xFFFF }, { 0x0D26, 0x033E, - 0x0B2E, 0x1D13, 0x1E17, 0xFFFF }, { 0x1935, 0x1B27, 0xFFFF }, { 0x0E10, 0x1C23, 0x133B, 0x172F, 0xFFFF }, { 0x0F18, - 0x0C2C, 0x1D11, 0x1F19, 0xFFFF }, { 0x0D32, 0x0F02, 0x1F03, 0x1E15, 0x1A2B, 0x103D, 0xFFFF }, { 0x0D28, 0x1C31, 0x1E01, - 0x1B33, 0x192D, 0xFFFF }, { 0x0E20, 0x1C25, 0x1837, 0x1B29, 0x073F, 0xFFFF }, { 0x1D21, 0x1639, 0xFFFF }, { 0x0F16, - 0x083C, 0x1E13, 0x1F17, 0xFFFF }, { 0x0E22, 0x1A35, 0xFFFF }, { 0x1D23, 0x1C27, 0xFFFF }, { 0x0D2A, 0x1E11, 0x143B, - 0x182F, 0xFFFF }, { 0x0E30, 0x0F14, 0x0C36, 0x1F15, 0x1B2B, 0x113D, 0xFFFF }, { 0x0F00, 0x0E24, 0x0B38, 0x1D31, 0x1F01, - 0x1A2D, 0xFFFF }, { 0x1C33, 0x1D25, 0x1937, 0xFFFF }, { 0x1E21, 0x1739, 0x1C29, 0x083F, 0xFFFF }, { 0x0F12, 0x0D34, - 0x0A3A, 0x1F13, 0xFFFF }, { 0x0E26, 0x043E, 0x0C2E, 0x1B35, 0xFFFF }, { 0x1E23, 0x1D27, 0xFFFF }, { 0x0F10, 0x1F11, - 0x153B, 0x192F, 0xFFFF }, { 0x0D2C, 0x123D, 0xFFFF }, - }; - - struct etc1_block - { - // big endian uint64: - // bit ofs: 56 48 40 32 24 16 8 0 - // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 - union - { - uint64 m_uint64; - uint8 m_bytes[8]; - }; - - uint8 m_low_color[2]; - uint8 m_high_color[2]; - - enum { cNumSelectorBytes = 4 }; - uint8 m_selectors[cNumSelectorBytes]; - - inline void clear() - { - zero_this(this); - } - - inline uint get_byte_bits(uint ofs, uint num) const - { - RG_ETC1_ASSERT((ofs + num) <= 64U); - RG_ETC1_ASSERT(num && (num <= 8U)); - RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3)); - const uint byte_ofs = 7 - (ofs >> 3); - const uint byte_bit_ofs = ofs & 7; - return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1); - } - - inline void set_byte_bits(uint ofs, uint num, uint bits) - { - RG_ETC1_ASSERT((ofs + num) <= 64U); - RG_ETC1_ASSERT(num && (num < 32U)); - RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3)); - RG_ETC1_ASSERT(bits < (1U << num)); - const uint byte_ofs = 7 - (ofs >> 3); - const uint byte_bit_ofs = ofs & 7; - const uint mask = (1 << num) - 1; - m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs); - m_bytes[byte_ofs] |= (bits << byte_bit_ofs); - } - - // false = left/right subblocks - // true = upper/lower subblocks - inline bool get_flip_bit() const - { - return (m_bytes[3] & 1) != 0; - } - - inline void set_flip_bit(bool flip) - { - m_bytes[3] &= ~1; - m_bytes[3] |= static_cast<uint8>(flip); - } - - inline bool get_diff_bit() const - { - return (m_bytes[3] & 2) != 0; - } - - inline void set_diff_bit(bool diff) - { - m_bytes[3] &= ~2; - m_bytes[3] |= (static_cast<uint>(diff) << 1); - } - - // Returns intensity modifier table (0-7) used by subblock subblock_id. - // subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2) - inline uint get_inten_table(uint subblock_id) const - { - RG_ETC1_ASSERT(subblock_id < 2); - const uint ofs = subblock_id ? 2 : 5; - return (m_bytes[3] >> ofs) & 7; - } - - // Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1) - inline void set_inten_table(uint subblock_id, uint t) - { - RG_ETC1_ASSERT(subblock_id < 2); - RG_ETC1_ASSERT(t < 8); - const uint ofs = subblock_id ? 2 : 5; - m_bytes[3] &= ~(7 << ofs); - m_bytes[3] |= (t << ofs); - } - - // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables. - inline uint get_selector(uint x, uint y) const - { - RG_ETC1_ASSERT((x | y) < 4); - - const uint bit_index = x * 4 + y; - const uint byte_bit_ofs = bit_index & 7; - const uint8 *p = &m_bytes[7 - (bit_index >> 3)]; - const uint lsb = (p[0] >> byte_bit_ofs) & 1; - const uint msb = (p[-2] >> byte_bit_ofs) & 1; - const uint val = lsb | (msb << 1); - - return g_etc1_to_selector_index[val]; - } - - // Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables. - inline void set_selector(uint x, uint y, uint val) - { - RG_ETC1_ASSERT((x | y | val) < 4); - const uint bit_index = x * 4 + y; - - uint8 *p = &m_bytes[7 - (bit_index >> 3)]; - - const uint byte_bit_ofs = bit_index & 7; - const uint mask = 1 << byte_bit_ofs; - - const uint etc1_val = g_selector_index_to_etc1[val]; - - const uint lsb = etc1_val & 1; - const uint msb = etc1_val >> 1; - - p[0] &= ~mask; - p[0] |= (lsb << byte_bit_ofs); - - p[-2] &= ~mask; - p[-2] |= (msb << byte_bit_ofs); - } - - inline void set_base4_color(uint idx, uint16 c) - { - if (idx) - { - set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15); - set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15); - set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15); - } - else - { - set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15); - set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15); - set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15); - } - } - - inline uint16 get_base4_color(uint idx) const - { - uint r, g, b; - if (idx) - { - r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4); - g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4); - b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4); - } - else - { - r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4); - g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4); - b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4); - } - return static_cast<uint16>(b | (g << 4U) | (r << 8U)); - } - - inline void set_base5_color(uint16 c) - { - set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31); - set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31); - set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31); - } - - inline uint16 get_base5_color() const - { - const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5); - const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5); - const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5); - return static_cast<uint16>(b | (g << 5U) | (r << 10U)); - } - - void set_delta3_color(uint16 c) - { - set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7); - set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7); - set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7); - } - - inline uint16 get_delta3_color() const - { - const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3); - const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3); - const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3); - return static_cast<uint16>(b | (g << 3U) | (r << 6U)); - } - - // Base color 5 - static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U); - static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U); - - static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U); - static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled); - - static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U); - static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U); - - // Delta color 3 - // Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax) - static uint16 pack_delta3(int r, int g, int b); - - // Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax) - static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3); - - // Abs color 4 - static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U); - static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U); - - static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U); - static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled); - - // subblock colors - static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx); - static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx); - static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx); - - static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4) - { - if (color4) - { - dst.r = src.r | (src.r << 4); - dst.g = src.g | (src.g << 4); - dst.b = src.b | (src.b << 4); - } - else - { - dst.r = (src.r >> 2) | (src.r << 3); - dst.g = (src.g >> 2) | (src.g << 3); - dst.b = (src.b >> 2) | (src.b << 3); - } - dst.a = src.a; - } - }; - - // Returns pointer to sorted array. - template<typename T, typename Q> - T* indirect_radix_sort(uint num_indices, T* pIndices0, T* pIndices1, const Q* pKeys, uint key_ofs, uint key_size, bool init_indices) - { - RG_ETC1_ASSERT((key_ofs >= 0) && (key_ofs < sizeof(T))); - RG_ETC1_ASSERT((key_size >= 1) && (key_size <= 4)); - - if (init_indices) - { - T* p = pIndices0; - T* q = pIndices0 + (num_indices >> 1) * 2; - uint i; - for (i = 0; p != q; p += 2, i += 2) - { - p[0] = static_cast<T>(i); - p[1] = static_cast<T>(i + 1); - } - - if (num_indices & 1) - *p = static_cast<T>(i); - } - - uint hist[256 * 4]; - - memset(hist, 0, sizeof(hist[0]) * 256 * key_size); - -#define RG_ETC1_GET_KEY(p) (*(const uint*)((const uint8*)(pKeys + *(p)) + key_ofs)) -#define RG_ETC1_GET_KEY_FROM_INDEX(i) (*(const uint*)((const uint8*)(pKeys + (i)) + key_ofs)) - - if (key_size == 4) - { - T* p = pIndices0; - T* q = pIndices0 + num_indices; - for ( ; p != q; p++) - { - const uint key = RG_ETC1_GET_KEY(p); - - hist[ key & 0xFF]++; - hist[256 + ((key >> 8) & 0xFF)]++; - hist[512 + ((key >> 16) & 0xFF)]++; - hist[768 + ((key >> 24) & 0xFF)]++; - } - } - else if (key_size == 3) - { - T* p = pIndices0; - T* q = pIndices0 + num_indices; - for ( ; p != q; p++) - { - const uint key = RG_ETC1_GET_KEY(p); - - hist[ key & 0xFF]++; - hist[256 + ((key >> 8) & 0xFF)]++; - hist[512 + ((key >> 16) & 0xFF)]++; - } - } - else if (key_size == 2) - { - T* p = pIndices0; - T* q = pIndices0 + (num_indices >> 1) * 2; - - for ( ; p != q; p += 2) - { - const uint key0 = RG_ETC1_GET_KEY(p); - const uint key1 = RG_ETC1_GET_KEY(p+1); - - hist[ key0 & 0xFF]++; - hist[256 + ((key0 >> 8) & 0xFF)]++; - - hist[ key1 & 0xFF]++; - hist[256 + ((key1 >> 8) & 0xFF)]++; - } - - if (num_indices & 1) - { - const uint key = RG_ETC1_GET_KEY(p); - - hist[ key & 0xFF]++; - hist[256 + ((key >> 8) & 0xFF)]++; - } - } - else - { - RG_ETC1_ASSERT(key_size == 1); - if (key_size != 1) - return NULL; - - T* p = pIndices0; - T* q = pIndices0 + (num_indices >> 1) * 2; - - for ( ; p != q; p += 2) - { - const uint key0 = RG_ETC1_GET_KEY(p); - const uint key1 = RG_ETC1_GET_KEY(p+1); - - hist[key0 & 0xFF]++; - hist[key1 & 0xFF]++; - } - - if (num_indices & 1) - { - const uint key = RG_ETC1_GET_KEY(p); - - hist[key & 0xFF]++; - } - } - - T* pCur = pIndices0; - T* pNew = pIndices1; - - for (uint pass = 0; pass < key_size; pass++) - { - const uint* pHist = &hist[pass << 8]; - - uint offsets[256]; - - uint cur_ofs = 0; - for (uint i = 0; i < 256; i += 2) - { - offsets[i] = cur_ofs; - cur_ofs += pHist[i]; - - offsets[i+1] = cur_ofs; - cur_ofs += pHist[i+1]; - } - - const uint pass_shift = pass << 3; - - T* p = pCur; - T* q = pCur + (num_indices >> 1) * 2; - - for ( ; p != q; p += 2) - { - uint index0 = p[0]; - uint index1 = p[1]; - - uint c0 = (RG_ETC1_GET_KEY_FROM_INDEX(index0) >> pass_shift) & 0xFF; - uint c1 = (RG_ETC1_GET_KEY_FROM_INDEX(index1) >> pass_shift) & 0xFF; - - if (c0 == c1) - { - uint dst_offset0 = offsets[c0]; - - offsets[c0] = dst_offset0 + 2; - - pNew[dst_offset0] = static_cast<T>(index0); - pNew[dst_offset0 + 1] = static_cast<T>(index1); - } - else - { - uint dst_offset0 = offsets[c0]++; - uint dst_offset1 = offsets[c1]++; - - pNew[dst_offset0] = static_cast<T>(index0); - pNew[dst_offset1] = static_cast<T>(index1); - } - } - - if (num_indices & 1) - { - uint index = *p; - uint c = (RG_ETC1_GET_KEY_FROM_INDEX(index) >> pass_shift) & 0xFF; - - uint dst_offset = offsets[c]; - offsets[c] = dst_offset + 1; - - pNew[dst_offset] = static_cast<T>(index); - } - - T* t = pCur; - pCur = pNew; - pNew = t; - } - - return pCur; - } - -#undef RG_ETC1_GET_KEY -#undef RG_ETC1_GET_KEY_FROM_INDEX - - uint16 etc1_block::pack_color5(const color_quad_u8& color, bool scaled, uint bias) - { - return pack_color5(color.r, color.g, color.b, scaled, bias); - } - - uint16 etc1_block::pack_color5(uint r, uint g, uint b, bool scaled, uint bias) - { - if (scaled) - { - r = (r * 31U + bias) / 255U; - g = (g * 31U + bias) / 255U; - b = (b * 31U + bias) / 255U; - } - - r = rg_etc1::minimum(r, 31U); - g = rg_etc1::minimum(g, 31U); - b = rg_etc1::minimum(b, 31U); - - return static_cast<uint16>(b | (g << 5U) | (r << 10U)); - } - - color_quad_u8 etc1_block::unpack_color5(uint16 packed_color5, bool scaled, uint alpha) - { - uint b = packed_color5 & 31U; - uint g = (packed_color5 >> 5U) & 31U; - uint r = (packed_color5 >> 10U) & 31U; - - if (scaled) - { - b = (b << 3U) | (b >> 2U); - g = (g << 3U) | (g >> 2U); - r = (r << 3U) | (r >> 2U); - } - - return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U)); - } - - void etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, bool scaled) - { - color_quad_u8 c(unpack_color5(packed_color5, scaled, 0)); - r = c.r; - g = c.g; - b = c.b; - } - - bool etc1_block::unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha) - { - int dc_r, dc_g, dc_b; - unpack_delta3(dc_r, dc_g, dc_b, packed_delta3); - - int b = (packed_color5 & 31U) + dc_b; - int g = ((packed_color5 >> 5U) & 31U) + dc_g; - int r = ((packed_color5 >> 10U) & 31U) + dc_r; - - bool success = true; - if (static_cast<uint>(r | g | b) > 31U) - { - success = false; - r = rg_etc1::clamp<int>(r, 0, 31); - g = rg_etc1::clamp<int>(g, 0, 31); - b = rg_etc1::clamp<int>(b, 0, 31); - } - - if (scaled) - { - b = (b << 3U) | (b >> 2U); - g = (g << 3U) | (g >> 2U); - r = (r << 3U) | (r >> 2U); - } - - result.set_noclamp_rgba(r, g, b, rg_etc1::minimum(alpha, 255U)); - return success; - } - - bool etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha) - { - color_quad_u8 result; - const bool success = unpack_color5(result, packed_color5, packed_delta3, scaled, alpha); - r = result.r; - g = result.g; - b = result.b; - return success; - } - - uint16 etc1_block::pack_delta3(int r, int g, int b) - { - RG_ETC1_ASSERT((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax)); - RG_ETC1_ASSERT((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax)); - RG_ETC1_ASSERT((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax)); - if (r < 0) r += 8; - if (g < 0) g += 8; - if (b < 0) b += 8; - return static_cast<uint16>(b | (g << 3) | (r << 6)); - } - - void etc1_block::unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3) - { - r = (packed_delta3 >> 6) & 7; - g = (packed_delta3 >> 3) & 7; - b = packed_delta3 & 7; - if (r >= 4) r -= 8; - if (g >= 4) g -= 8; - if (b >= 4) b -= 8; - } - - uint16 etc1_block::pack_color4(const color_quad_u8& color, bool scaled, uint bias) - { - return pack_color4(color.r, color.g, color.b, scaled, bias); - } - - uint16 etc1_block::pack_color4(uint r, uint g, uint b, bool scaled, uint bias) - { - if (scaled) - { - r = (r * 15U + bias) / 255U; - g = (g * 15U + bias) / 255U; - b = (b * 15U + bias) / 255U; - } - - r = rg_etc1::minimum(r, 15U); - g = rg_etc1::minimum(g, 15U); - b = rg_etc1::minimum(b, 15U); - - return static_cast<uint16>(b | (g << 4U) | (r << 8U)); - } - - color_quad_u8 etc1_block::unpack_color4(uint16 packed_color4, bool scaled, uint alpha) - { - uint b = packed_color4 & 15U; - uint g = (packed_color4 >> 4U) & 15U; - uint r = (packed_color4 >> 8U) & 15U; - - if (scaled) - { - b = (b << 4U) | b; - g = (g << 4U) | g; - r = (r << 4U) | r; - } - - return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U)); - } - - void etc1_block::unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled) - { - color_quad_u8 c(unpack_color4(packed_color4, scaled, 0)); - r = c.r; - g = c.g; - b = c.b; - } - - void etc1_block::get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx) - { - RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues); - const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0]; - - uint r, g, b; - unpack_color5(r, g, b, packed_color5, true); - - const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b); - - const int y0 = pInten_modifer_table[0]; - pDst[0].set(ir + y0, ig + y0, ib + y0); - - const int y1 = pInten_modifer_table[1]; - pDst[1].set(ir + y1, ig + y1, ib + y1); - - const int y2 = pInten_modifer_table[2]; - pDst[2].set(ir + y2, ig + y2, ib + y2); - - const int y3 = pInten_modifer_table[3]; - pDst[3].set(ir + y3, ig + y3, ib + y3); - } - - bool etc1_block::get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx) - { - RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues); - const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0]; - - uint r, g, b; - bool success = unpack_color5(r, g, b, packed_color5, packed_delta3, true); - - const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b); - - const int y0 = pInten_modifer_table[0]; - pDst[0].set(ir + y0, ig + y0, ib + y0); - - const int y1 = pInten_modifer_table[1]; - pDst[1].set(ir + y1, ig + y1, ib + y1); - - const int y2 = pInten_modifer_table[2]; - pDst[2].set(ir + y2, ig + y2, ib + y2); - - const int y3 = pInten_modifer_table[3]; - pDst[3].set(ir + y3, ig + y3, ib + y3); - - return success; - } - - void etc1_block::get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx) - { - RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues); - const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0]; - - uint r, g, b; - unpack_color4(r, g, b, packed_color4, true); - - const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b); - - const int y0 = pInten_modifer_table[0]; - pDst[0].set(ir + y0, ig + y0, ib + y0); - - const int y1 = pInten_modifer_table[1]; - pDst[1].set(ir + y1, ig + y1, ib + y1); - - const int y2 = pInten_modifer_table[2]; - pDst[2].set(ir + y2, ig + y2, ib + y2); - - const int y3 = pInten_modifer_table[3]; - pDst[3].set(ir + y3, ig + y3, ib + y3); - } - - bool unpack_etc1_block(const void* pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha) - { - color_quad_u8* pDst = reinterpret_cast<color_quad_u8*>(pDst_pixels_rgba); - const etc1_block& block = *static_cast<const etc1_block*>(pETC1_block); - - const bool diff_flag = block.get_diff_bit(); - const bool flip_flag = block.get_flip_bit(); - const uint table_index0 = block.get_inten_table(0); - const uint table_index1 = block.get_inten_table(1); - - color_quad_u8 subblock_colors0[4]; - color_quad_u8 subblock_colors1[4]; - bool success = true; - - if (diff_flag) - { - const uint16 base_color5 = block.get_base5_color(); - const uint16 delta_color3 = block.get_delta3_color(); - etc1_block::get_diff_subblock_colors(subblock_colors0, base_color5, table_index0); - - if (!etc1_block::get_diff_subblock_colors(subblock_colors1, base_color5, delta_color3, table_index1)) - success = false; - } - else - { - const uint16 base_color4_0 = block.get_base4_color(0); - etc1_block::get_abs_subblock_colors(subblock_colors0, base_color4_0, table_index0); - - const uint16 base_color4_1 = block.get_base4_color(1); - etc1_block::get_abs_subblock_colors(subblock_colors1, base_color4_1, table_index1); - } - - if (preserve_alpha) - { - if (flip_flag) - { - for (uint y = 0; y < 2; y++) - { - pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]); - pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]); - pDst[2].set_rgb(subblock_colors0[block.get_selector(2, y)]); - pDst[3].set_rgb(subblock_colors0[block.get_selector(3, y)]); - pDst += 4; - } - - for (uint y = 2; y < 4; y++) - { - pDst[0].set_rgb(subblock_colors1[block.get_selector(0, y)]); - pDst[1].set_rgb(subblock_colors1[block.get_selector(1, y)]); - pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]); - pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]); - pDst += 4; - } - } - else - { - for (uint y = 0; y < 4; y++) - { - pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]); - pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]); - pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]); - pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]); - pDst += 4; - } - } - } - else - { - if (flip_flag) - { - // 0000 - // 0000 - // 1111 - // 1111 - for (uint y = 0; y < 2; y++) - { - pDst[0] = subblock_colors0[block.get_selector(0, y)]; - pDst[1] = subblock_colors0[block.get_selector(1, y)]; - pDst[2] = subblock_colors0[block.get_selector(2, y)]; - pDst[3] = subblock_colors0[block.get_selector(3, y)]; - pDst += 4; - } - - for (uint y = 2; y < 4; y++) - { - pDst[0] = subblock_colors1[block.get_selector(0, y)]; - pDst[1] = subblock_colors1[block.get_selector(1, y)]; - pDst[2] = subblock_colors1[block.get_selector(2, y)]; - pDst[3] = subblock_colors1[block.get_selector(3, y)]; - pDst += 4; - } - } - else - { - // 0011 - // 0011 - // 0011 - // 0011 - for (uint y = 0; y < 4; y++) - { - pDst[0] = subblock_colors0[block.get_selector(0, y)]; - pDst[1] = subblock_colors0[block.get_selector(1, y)]; - pDst[2] = subblock_colors1[block.get_selector(2, y)]; - pDst[3] = subblock_colors1[block.get_selector(3, y)]; - pDst += 4; - } - } - } - - return success; - } - - struct etc1_solution_coordinates - { - inline etc1_solution_coordinates() : - m_unscaled_color(0, 0, 0, 0), - m_inten_table(0), - m_color4(false) - { - } - - inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4) : - m_unscaled_color(r, g, b, 255), - m_inten_table(inten_table), - m_color4(color4) - { - } - - inline etc1_solution_coordinates(const color_quad_u8& c, uint inten_table, bool color4) : - m_unscaled_color(c), - m_inten_table(inten_table), - m_color4(color4) - { - } - - inline etc1_solution_coordinates(const etc1_solution_coordinates& other) - { - *this = other; - } - - inline etc1_solution_coordinates& operator= (const etc1_solution_coordinates& rhs) - { - m_unscaled_color = rhs.m_unscaled_color; - m_inten_table = rhs.m_inten_table; - m_color4 = rhs.m_color4; - return *this; - } - - inline void clear() - { - m_unscaled_color.clear(); - m_inten_table = 0; - m_color4 = false; - } - - inline color_quad_u8 get_scaled_color() const - { - int br, bg, bb; - if (m_color4) - { - br = m_unscaled_color.r | (m_unscaled_color.r << 4); - bg = m_unscaled_color.g | (m_unscaled_color.g << 4); - bb = m_unscaled_color.b | (m_unscaled_color.b << 4); - } - else - { - br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3); - bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3); - bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3); - } - return color_quad_u8(br, bg, bb); - } - - inline void get_block_colors(color_quad_u8* pBlock_colors) - { - int br, bg, bb; - if (m_color4) - { - br = m_unscaled_color.r | (m_unscaled_color.r << 4); - bg = m_unscaled_color.g | (m_unscaled_color.g << 4); - bb = m_unscaled_color.b | (m_unscaled_color.b << 4); - } - else - { - br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3); - bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3); - bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3); - } - const int* pInten_table = g_etc1_inten_tables[m_inten_table]; - pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]); - pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]); - pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]); - pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]); - } - - color_quad_u8 m_unscaled_color; - uint m_inten_table; - bool m_color4; - }; - - class etc1_optimizer - { - etc1_optimizer(const etc1_optimizer&); - etc1_optimizer& operator= (const etc1_optimizer&); - - public: - etc1_optimizer() - { - clear(); - } - - void clear() - { - m_pParams = NULL; - m_pResult = NULL; - m_pSorted_luma = NULL; - m_pSorted_luma_indices = NULL; - } - - struct params : etc1_pack_params - { - params() - { - clear(); - } - - params(const etc1_pack_params& base_params) : - etc1_pack_params(base_params) - { - clear_optimizer_params(); - } - - void clear() - { - etc1_pack_params::clear(); - clear_optimizer_params(); - } - - void clear_optimizer_params() - { - m_num_src_pixels = 0; - m_pSrc_pixels = 0; - - m_use_color4 = false; - static const int s_default_scan_delta[] = { 0 }; - m_pScan_deltas = s_default_scan_delta; - m_scan_delta_size = 1; - - m_base_color5.clear(); - m_constrain_against_base_color5 = false; - } - - uint m_num_src_pixels; - const color_quad_u8* m_pSrc_pixels; - - bool m_use_color4; - const int* m_pScan_deltas; - uint m_scan_delta_size; - - color_quad_u8 m_base_color5; - bool m_constrain_against_base_color5; - }; - - struct results - { - uint64 m_error; - color_quad_u8 m_block_color_unscaled; - uint m_block_inten_table; - uint m_n; - uint8* m_pSelectors; - bool m_block_color4; - - inline results& operator= (const results& rhs) - { - m_block_color_unscaled = rhs.m_block_color_unscaled; - m_block_color4 = rhs.m_block_color4; - m_block_inten_table = rhs.m_block_inten_table; - m_error = rhs.m_error; - RG_ETC1_ASSERT(m_n == rhs.m_n); - memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n); - return *this; - } - }; - - void init(const params& params, results& result); - bool compute(); - - private: - struct potential_solution - { - potential_solution() : m_coords(), m_error(cUINT64_MAX), m_valid(false) - { - } - - etc1_solution_coordinates m_coords; - uint8 m_selectors[8]; - uint64 m_error; - bool m_valid; - - void clear() - { - m_coords.clear(); - m_error = cUINT64_MAX; - m_valid = false; - } - }; - - const params* m_pParams; - results* m_pResult; - - int m_limit; - - vec3F m_avg_color; - int m_br, m_bg, m_bb; - uint16 m_luma[8]; - uint32 m_sorted_luma[2][8]; - const uint32* m_pSorted_luma_indices; - uint32* m_pSorted_luma; - - uint8 m_selectors[8]; - uint8 m_best_selectors[8]; - - potential_solution m_best_solution; - potential_solution m_trial_solution; - uint8 m_temp_selectors[8]; - - bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution); - bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution); - }; - - bool etc1_optimizer::compute() - { - const uint n = m_pParams->m_num_src_pixels; - const int scan_delta_size = m_pParams->m_scan_delta_size; - - // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color. - // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index. - for (int zdi = 0; zdi < scan_delta_size; zdi++) - { - const int zd = m_pParams->m_pScan_deltas[zdi]; - const int mbb = m_bb + zd; - if (mbb < 0) continue; else if (mbb > m_limit) break; - - for (int ydi = 0; ydi < scan_delta_size; ydi++) - { - const int yd = m_pParams->m_pScan_deltas[ydi]; - const int mbg = m_bg + yd; - if (mbg < 0) continue; else if (mbg > m_limit) break; - - for (int xdi = 0; xdi < scan_delta_size; xdi++) - { - const int xd = m_pParams->m_pScan_deltas[xdi]; - const int mbr = m_br + xd; - if (mbr < 0) continue; else if (mbr > m_limit) break; - - etc1_solution_coordinates coords(mbr, mbg, mbb, 0, m_pParams->m_use_color4); - if (m_pParams->m_quality == cHighQuality) - { - if (!evaluate_solution(coords, m_trial_solution, &m_best_solution)) - continue; - } - else - { - if (!evaluate_solution_fast(coords, m_trial_solution, &m_best_solution)) - continue; - } - - // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index. - // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors: - // The goal is: - // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0 - // Rearranging this: - // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0 - // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0 - // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0 - // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0 - // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0 - // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 - // So what this means: - // optimal_block_color = avg_input - avg_inten_delta - // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta. - // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula. - // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping. - - const uint max_refinement_trials = (m_pParams->m_quality == cLowQuality) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2); - for (uint refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++) - { - const uint8* pSelectors = m_best_solution.m_selectors; - const int* pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table]; - - int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0; - const color_quad_u8 base_color(m_best_solution.m_coords.get_scaled_color()); - for (uint r = 0; r < n; r++) - { - const uint s = *pSelectors++; - const int yd = pInten_table[s]; - // Compute actual delta being applied to each pixel, taking into account clamping. - delta_sum_r += rg_etc1::clamp<int>(base_color.r + yd, 0, 255) - base_color.r; - delta_sum_g += rg_etc1::clamp<int>(base_color.g + yd, 0, 255) - base_color.g; - delta_sum_b += rg_etc1::clamp<int>(base_color.b + yd, 0, 255) - base_color.b; - } - if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b)) - break; - const float avg_delta_r_f = static_cast<float>(delta_sum_r) / n; - const float avg_delta_g_f = static_cast<float>(delta_sum_g) / n; - const float avg_delta_b_f = static_cast<float>(delta_sum_b) / n; - const int br1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit); - const int bg1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit); - const int bb1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit); - - bool skip = false; - - if ((mbr == br1) && (mbg == bg1) && (mbb == bb1)) - skip = true; - else if ((br1 == m_best_solution.m_coords.m_unscaled_color.r) && (bg1 == m_best_solution.m_coords.m_unscaled_color.g) && (bb1 == m_best_solution.m_coords.m_unscaled_color.b)) - skip = true; - else if ((m_br == br1) && (m_bg == bg1) && (m_bb == bb1)) - skip = true; - - if (skip) - break; - - etc1_solution_coordinates coords1(br1, bg1, bb1, 0, m_pParams->m_use_color4); - if (m_pParams->m_quality == cHighQuality) - { - if (!evaluate_solution(coords1, m_trial_solution, &m_best_solution)) - break; - } - else - { - if (!evaluate_solution_fast(coords1, m_trial_solution, &m_best_solution)) - break; - } - - } // refinement_trial - - } // xdi - } // ydi - } // zdi - - if (!m_best_solution.m_valid) - { - m_pResult->m_error = cUINT32_MAX; - return false; - } - - const uint8* pSelectors = m_best_solution.m_selectors; - -#ifdef RG_ETC1_BUILD_DEBUG - { - color_quad_u8 block_colors[4]; - m_best_solution.m_coords.get_block_colors(block_colors); - - const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels; - uint64 actual_error = 0; - for (uint i = 0; i < n; i++) - actual_error += pSrc_pixels[i].squared_distance_rgb(block_colors[pSelectors[i]]); - - RG_ETC1_ASSERT(actual_error == m_best_solution.m_error); - } -#endif - - m_pResult->m_error = m_best_solution.m_error; - - m_pResult->m_block_color_unscaled = m_best_solution.m_coords.m_unscaled_color; - m_pResult->m_block_color4 = m_best_solution.m_coords.m_color4; - - m_pResult->m_block_inten_table = m_best_solution.m_coords.m_inten_table; - memcpy(m_pResult->m_pSelectors, pSelectors, n); - m_pResult->m_n = n; - - return true; - } - - void etc1_optimizer::init(const params& p, results& r) - { - // This version is hardcoded for 8 pixel subblocks. - RG_ETC1_ASSERT(p.m_num_src_pixels == 8); - - m_pParams = &p; - m_pResult = &r; - - const uint n = 8; - - m_limit = m_pParams->m_use_color4 ? 15 : 31; - - vec3F avg_color(0.0f); - - for (uint i = 0; i < n; i++) - { - const color_quad_u8& c = m_pParams->m_pSrc_pixels[i]; - const vec3F fc(c.r, c.g, c.b); - - avg_color += fc; - - m_luma[i] = static_cast<uint16>(c.r + c.g + c.b); - m_sorted_luma[0][i] = i; - } - avg_color *= (1.0f / static_cast<float>(n)); - m_avg_color = avg_color; - - m_br = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[0] * m_limit / 255.0f + .5f), 0, m_limit); - m_bg = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[1] * m_limit / 255.0f + .5f), 0, m_limit); - m_bb = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[2] * m_limit / 255.0f + .5f), 0, m_limit); - - if (m_pParams->m_quality <= cMediumQuality) - { - m_pSorted_luma_indices = indirect_radix_sort(n, m_sorted_luma[0], m_sorted_luma[1], m_luma, 0, sizeof(m_luma[0]), false); - m_pSorted_luma = m_sorted_luma[0]; - if (m_pSorted_luma_indices == m_sorted_luma[0]) - m_pSorted_luma = m_sorted_luma[1]; - - for (uint i = 0; i < n; i++) - m_pSorted_luma[i] = m_luma[m_pSorted_luma_indices[i]]; - } - - m_best_solution.m_coords.clear(); - m_best_solution.m_valid = false; - m_best_solution.m_error = cUINT64_MAX; - } - - bool etc1_optimizer::evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution) - { - trial_solution.m_valid = false; - - if (m_pParams->m_constrain_against_base_color5) - { - const int dr = coords.m_unscaled_color.r - m_pParams->m_base_color5.r; - const int dg = coords.m_unscaled_color.g - m_pParams->m_base_color5.g; - const int db = coords.m_unscaled_color.b - m_pParams->m_base_color5.b; - - if ((rg_etc1::minimum(dr, dg, db) < cETC1ColorDeltaMin) || (rg_etc1::maximum(dr, dg, db) > cETC1ColorDeltaMax)) - return false; - } - - const color_quad_u8 base_color(coords.get_scaled_color()); - - const uint n = 8; - - trial_solution.m_error = cUINT64_MAX; - - for (uint inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++) - { - const int* pInten_table = g_etc1_inten_tables[inten_table]; - - color_quad_u8 block_colors[4]; - for (uint s = 0; s < 4; s++) - { - const int yd = pInten_table[s]; - block_colors[s].set(base_color.r + yd, base_color.g + yd, base_color.b + yd, 0); - } - - uint64 total_error = 0; - - const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels; - for (uint c = 0; c < n; c++) - { - const color_quad_u8& src_pixel = *pSrc_pixels++; - - uint best_selector_index = 0; - uint best_error = rg_etc1::square(src_pixel.r - block_colors[0].r) + rg_etc1::square(src_pixel.g - block_colors[0].g) + rg_etc1::square(src_pixel.b - block_colors[0].b); - - uint trial_error = rg_etc1::square(src_pixel.r - block_colors[1].r) + rg_etc1::square(src_pixel.g - block_colors[1].g) + rg_etc1::square(src_pixel.b - block_colors[1].b); - if (trial_error < best_error) - { - best_error = trial_error; - best_selector_index = 1; - } - - trial_error = rg_etc1::square(src_pixel.r - block_colors[2].r) + rg_etc1::square(src_pixel.g - block_colors[2].g) + rg_etc1::square(src_pixel.b - block_colors[2].b); - if (trial_error < best_error) - { - best_error = trial_error; - best_selector_index = 2; - } - - trial_error = rg_etc1::square(src_pixel.r - block_colors[3].r) + rg_etc1::square(src_pixel.g - block_colors[3].g) + rg_etc1::square(src_pixel.b - block_colors[3].b); - if (trial_error < best_error) - { - best_error = trial_error; - best_selector_index = 3; - } - - m_temp_selectors[c] = static_cast<uint8>(best_selector_index); - - total_error += best_error; - if (total_error >= trial_solution.m_error) - break; - } - - if (total_error < trial_solution.m_error) - { - trial_solution.m_error = total_error; - trial_solution.m_coords.m_inten_table = inten_table; - memcpy(trial_solution.m_selectors, m_temp_selectors, 8); - trial_solution.m_valid = true; - } - } - trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color; - trial_solution.m_coords.m_color4 = m_pParams->m_use_color4; - - bool success = false; - if (pBest_solution) - { - if (trial_solution.m_error < pBest_solution->m_error) - { - *pBest_solution = trial_solution; - success = true; - } - } - - return success; - } - - bool etc1_optimizer::evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution) - { - if (m_pParams->m_constrain_against_base_color5) - { - const int dr = coords.m_unscaled_color.r - m_pParams->m_base_color5.r; - const int dg = coords.m_unscaled_color.g - m_pParams->m_base_color5.g; - const int db = coords.m_unscaled_color.b - m_pParams->m_base_color5.b; - - if ((rg_etc1::minimum(dr, dg, db) < cETC1ColorDeltaMin) || (rg_etc1::maximum(dr, dg, db) > cETC1ColorDeltaMax)) - { - trial_solution.m_valid = false; - return false; - } - } - - const color_quad_u8 base_color(coords.get_scaled_color()); - - const uint n = 8; - - trial_solution.m_error = cUINT64_MAX; - - for (int inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table) - { - const int* pInten_table = g_etc1_inten_tables[inten_table]; - - uint block_inten[4]; - color_quad_u8 block_colors[4]; - for (uint s = 0; s < 4; s++) - { - const int yd = pInten_table[s]; - color_quad_u8 block_color(base_color.r + yd, base_color.g + yd, base_color.b + yd, 0); - block_colors[s] = block_color; - block_inten[s] = block_color.r + block_color.g + block_color.b; - } - - // evaluate_solution_fast() enforces/assumesd a total ordering of the input colors along the intensity (1,1,1) axis to more quickly classify the inputs to selectors. - // The inputs colors have been presorted along the projection onto this axis, and ETC1 block colors are always ordered along the intensity axis, so this classification is fast. - // 0 1 2 3 - // 01 12 23 - const uint block_inten_midpoints[3] = { block_inten[0] + block_inten[1], block_inten[1] + block_inten[2], block_inten[2] + block_inten[3] }; - - uint64 total_error = 0; - const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels; - if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0]) - { - if (block_inten[0] > m_pSorted_luma[n - 1]) - { - const uint min_error = labs(block_inten[0] - m_pSorted_luma[n - 1]); - if (min_error >= trial_solution.m_error) - continue; - } - - memset(&m_temp_selectors[0], 0, n); - - for (uint c = 0; c < n; c++) - total_error += block_colors[0].squared_distance_rgb(pSrc_pixels[c]); - } - else if ((m_pSorted_luma[0] * 2) >= block_inten_midpoints[2]) - { - if (m_pSorted_luma[0] > block_inten[3]) - { - const uint min_error = labs(m_pSorted_luma[0] - block_inten[3]); - if (min_error >= trial_solution.m_error) - continue; - } - - memset(&m_temp_selectors[0], 3, n); - - for (uint c = 0; c < n; c++) - total_error += block_colors[3].squared_distance_rgb(pSrc_pixels[c]); - } - else - { - uint cur_selector = 0, c; - for (c = 0; c < n; c++) - { - const uint y = m_pSorted_luma[c]; - while ((y * 2) >= block_inten_midpoints[cur_selector]) - if (++cur_selector > 2) - goto done; - const uint sorted_pixel_index = m_pSorted_luma_indices[c]; - m_temp_selectors[sorted_pixel_index] = static_cast<uint8>(cur_selector); - total_error += block_colors[cur_selector].squared_distance_rgb(pSrc_pixels[sorted_pixel_index]); - } -done: - while (c < n) - { - const uint sorted_pixel_index = m_pSorted_luma_indices[c]; - m_temp_selectors[sorted_pixel_index] = 3; - total_error += block_colors[3].squared_distance_rgb(pSrc_pixels[sorted_pixel_index]); - ++c; - } - } - - if (total_error < trial_solution.m_error) - { - trial_solution.m_error = total_error; - trial_solution.m_coords.m_inten_table = inten_table; - memcpy(trial_solution.m_selectors, m_temp_selectors, n); - trial_solution.m_valid = true; - if (!total_error) - break; - } - } - trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color; - trial_solution.m_coords.m_color4 = m_pParams->m_use_color4; - - bool success = false; - if (pBest_solution) - { - if (trial_solution.m_error < pBest_solution->m_error) - { - *pBest_solution = trial_solution; - success = true; - } - } - - return success; - } - - static uint etc1_decode_value(uint diff, uint inten, uint selector, uint packed_c) - { - const uint limit = diff ? 32 : 16; limit; - RG_ETC1_ASSERT((diff < 2) && (inten < 8) && (selector < 4) && (packed_c < limit)); - int c; - if (diff) - c = (packed_c >> 2) | (packed_c << 3); - else - c = packed_c | (packed_c << 4); - c += g_etc1_inten_tables[inten][selector]; - c = rg_etc1::clamp<int>(c, 0, 255); - return c; - } - - static inline int mul_8bit(int a, int b) { int t = a*b + 128; return (t + (t >> 8)) >> 8; } - - void pack_etc1_block_init() - { - for (uint diff = 0; diff < 2; diff++) - { - const uint limit = diff ? 32 : 16; - - for (uint inten = 0; inten < 8; inten++) - { - for (uint selector = 0; selector < 4; selector++) - { - const uint inverse_table_index = diff + (inten << 1) + (selector << 4); - for (uint color = 0; color < 256; color++) - { - uint best_error = cUINT32_MAX, best_packed_c = 0; - for (uint packed_c = 0; packed_c < limit; packed_c++) - { - int v = etc1_decode_value(diff, inten, selector, packed_c); - uint err = labs(v - static_cast<int>(color)); - if (err < best_error) - { - best_error = err; - best_packed_c = packed_c; - if (!best_error) - break; - } - } - RG_ETC1_ASSERT(best_error <= 255); - g_etc1_inverse_lookup[inverse_table_index][color] = static_cast<uint16>(best_packed_c | (best_error << 8)); - } - } - } - } - - uint expand5[32]; - for(int i = 0; i < 32; i++) - expand5[i] = (i << 3) | (i >> 2); - - for(int i = 0; i < 256 + 16; i++) - { - int v = clamp<int>(i - 8, 0, 255); - g_quant5_tab[i] = static_cast<uint8>(expand5[mul_8bit(v,31)]); - } - } - - // Packs solid color blocks efficiently using a set of small precomputed tables. - // For random 888 inputs, MSE results are better than Erricson's ETC1 packer in "slow" mode ~9.5% of the time, is slightly worse only ~.01% of the time, and is equal the rest of the time. - static uint64 pack_etc1_block_solid_color(etc1_block& block, const uint8* pColor, etc1_pack_params& pack_params) - { - pack_params; - RG_ETC1_ASSERT(g_etc1_inverse_lookup[0][255]); - - static uint s_next_comp[4] = { 1, 2, 0, 1 }; - - uint best_error = cUINT32_MAX, best_i = 0; - int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0; - - // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error. - for (uint i = 0; i < 3; i++) - { - const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]]; - - const int delta_range = 1; - for (int delta = -delta_range; delta <= delta_range; delta++) - { - const int c_plus_delta = rg_etc1::clamp<int>(pColor[i] + delta, 0, 255); - - const uint16* pTable; - if (!c_plus_delta) - pTable = g_color8_to_etc_block_config_0_255[0]; - else if (c_plus_delta == 255) - pTable = g_color8_to_etc_block_config_0_255[1]; - else - pTable = g_color8_to_etc_block_config_1_to_254[c_plus_delta - 1]; - - do - { - const uint x = *pTable++; - -#ifdef RG_ETC1_BUILD_DEBUG - const uint diff = x & 1; - const uint inten = (x >> 1) & 7; - const uint selector = (x >> 4) & 3; - const uint p0 = (x >> 8) & 255; - RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta); -#endif - - const uint16* pInverse_table = g_etc1_inverse_lookup[x & 0xFF]; - uint16 p1 = pInverse_table[c1]; - uint16 p2 = pInverse_table[c2]; - const uint trial_error = rg_etc1::square(c_plus_delta - pColor[i]) + rg_etc1::square(p1 >> 8) + rg_etc1::square(p2 >> 8); - if (trial_error < best_error) - { - best_error = trial_error; - best_x = x; - best_packed_c1 = p1 & 0xFF; - best_packed_c2 = p2 & 0xFF; - best_i = i; - if (!best_error) - goto found_perfect_match; - } - } while (*pTable != 0xFFFF); - } - } -found_perfect_match: - - const uint diff = best_x & 1; - const uint inten = (best_x >> 1) & 7; - - block.m_bytes[3] = static_cast<uint8>(((inten | (inten << 3)) << 2) | (diff << 1)); - - const uint etc1_selector = g_selector_index_to_etc1[(best_x >> 4) & 3]; - *reinterpret_cast<uint16*>(&block.m_bytes[4]) = (etc1_selector & 2) ? 0xFFFF : 0; - *reinterpret_cast<uint16*>(&block.m_bytes[6]) = (etc1_selector & 1) ? 0xFFFF : 0; - - const uint best_packed_c0 = (best_x >> 8) & 255; - if (diff) - { - block.m_bytes[best_i] = static_cast<uint8>(best_packed_c0 << 3); - block.m_bytes[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1 << 3); - block.m_bytes[s_next_comp[best_i+1]] = static_cast<uint8>(best_packed_c2 << 3); - } - else - { - block.m_bytes[best_i] = static_cast<uint8>(best_packed_c0 | (best_packed_c0 << 4)); - block.m_bytes[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1 | (best_packed_c1 << 4)); - block.m_bytes[s_next_comp[best_i+1]] = static_cast<uint8>(best_packed_c2 | (best_packed_c2 << 4)); - } - - return best_error; - } - - static uint pack_etc1_block_solid_color_constrained( - etc1_optimizer::results& results, - uint num_colors, const uint8* pColor, - etc1_pack_params& pack_params, - bool use_diff, - const color_quad_u8* pBase_color5_unscaled) - { - RG_ETC1_ASSERT(g_etc1_inverse_lookup[0][255]); - - pack_params; - static uint s_next_comp[4] = { 1, 2, 0, 1 }; - - uint best_error = cUINT32_MAX, best_i = 0; - int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0; - - // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error. - for (uint i = 0; i < 3; i++) - { - const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]]; - - const int delta_range = 1; - for (int delta = -delta_range; delta <= delta_range; delta++) - { - const int c_plus_delta = rg_etc1::clamp<int>(pColor[i] + delta, 0, 255); - - const uint16* pTable; - if (!c_plus_delta) - pTable = g_color8_to_etc_block_config_0_255[0]; - else if (c_plus_delta == 255) - pTable = g_color8_to_etc_block_config_0_255[1]; - else - pTable = g_color8_to_etc_block_config_1_to_254[c_plus_delta - 1]; - - do - { - const uint x = *pTable++; - const uint diff = x & 1; - if (static_cast<uint>(use_diff) != diff) - { - if (*pTable == 0xFFFF) - break; - continue; - } - - if ((diff) && (pBase_color5_unscaled)) - { - const int p0 = (x >> 8) & 255; - int delta = p0 - static_cast<int>(pBase_color5_unscaled->c[i]); - if ((delta < cETC1ColorDeltaMin) || (delta > cETC1ColorDeltaMax)) - { - if (*pTable == 0xFFFF) - break; - continue; - } - } - -#ifdef RG_ETC1_BUILD_DEBUG - { - const uint inten = (x >> 1) & 7; - const uint selector = (x >> 4) & 3; - const uint p0 = (x >> 8) & 255; - RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta); - } -#endif - - const uint16* pInverse_table = g_etc1_inverse_lookup[x & 0xFF]; - uint16 p1 = pInverse_table[c1]; - uint16 p2 = pInverse_table[c2]; - - if ((diff) && (pBase_color5_unscaled)) - { - int delta1 = (p1 & 0xFF) - static_cast<int>(pBase_color5_unscaled->c[s_next_comp[i]]); - int delta2 = (p2 & 0xFF) - static_cast<int>(pBase_color5_unscaled->c[s_next_comp[i + 1]]); - if ((delta1 < cETC1ColorDeltaMin) || (delta1 > cETC1ColorDeltaMax) || (delta2 < cETC1ColorDeltaMin) || (delta2 > cETC1ColorDeltaMax)) - { - if (*pTable == 0xFFFF) - break; - continue; - } - } - - const uint trial_error = rg_etc1::square(c_plus_delta - pColor[i]) + rg_etc1::square(p1 >> 8) + rg_etc1::square(p2 >> 8); - if (trial_error < best_error) - { - best_error = trial_error; - best_x = x; - best_packed_c1 = p1 & 0xFF; - best_packed_c2 = p2 & 0xFF; - best_i = i; - if (!best_error) - goto found_perfect_match; - } - } while (*pTable != 0xFFFF); - } - } -found_perfect_match: - - if (best_error == cUINT32_MAX) - return best_error; - - best_error *= num_colors; - - results.m_n = num_colors; - results.m_block_color4 = !(best_x & 1); - results.m_block_inten_table = (best_x >> 1) & 7; - memset(results.m_pSelectors, (best_x >> 4) & 3, num_colors); - - const uint best_packed_c0 = (best_x >> 8) & 255; - results.m_block_color_unscaled[best_i] = static_cast<uint8>(best_packed_c0); - results.m_block_color_unscaled[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1); - results.m_block_color_unscaled[s_next_comp[best_i + 1]] = static_cast<uint8>(best_packed_c2); - results.m_error = best_error; - - return best_error; - } - - // Function originally from RYG's public domain real-time DXT1 compressor, modified for 555. - static void dither_block_555(color_quad_u8* dest, const color_quad_u8* block) - { - int err[8],*ep1 = err,*ep2 = err+4; - uint8 *quant = g_quant5_tab+8; - - memset(dest, 0xFF, sizeof(color_quad_u8)*16); - - // process channels seperately - for(int ch=0;ch<3;ch++) - { - uint8* bp = (uint8*)block; - uint8* dp = (uint8*)dest; - - bp += ch; dp += ch; - - memset(err,0, sizeof(err)); - for(int y = 0; y < 4; y++) - { - // pixel 0 - dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)]; - ep1[0] = bp[ 0] - dp[ 0]; - - // pixel 1 - dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)]; - ep1[1] = bp[ 4] - dp[ 4]; - - // pixel 2 - dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)]; - ep1[2] = bp[ 8] - dp[ 8]; - - // pixel 3 - dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)]; - ep1[3] = bp[12] - dp[12]; - - // advance to next line - int* tmp = ep1; ep1 = ep2; ep2 = tmp; - bp += 16; - dp += 16; - } - } - } - - unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params) - { - const color_quad_u8* pSrc_pixels = reinterpret_cast<const color_quad_u8*>(pSrc_pixels_rgba); - etc1_block& dst_block = *static_cast<etc1_block*>(pETC1_block); - -#ifdef RG_ETC1_BUILD_DEBUG - // Ensure all alpha values are 0xFF. - for (uint i = 0; i < 16; i++) - { - RG_ETC1_ASSERT(pSrc_pixels[i].a == 255); - } -#endif - - color_quad_u8 src_pixel0(pSrc_pixels[0]); - - // Check for solid block. - const uint32 first_pixel_u32 = pSrc_pixels->m_u32; - int r; - for (r = 15; r >= 1; --r) - if (pSrc_pixels[r].m_u32 != first_pixel_u32) - break; - if (!r) - return static_cast<unsigned int>(16 * pack_etc1_block_solid_color(dst_block, &pSrc_pixels[0].r, pack_params)); - - color_quad_u8 dithered_pixels[16]; - if (pack_params.m_dithering) - { - dither_block_555(dithered_pixels, pSrc_pixels); - pSrc_pixels = dithered_pixels; - } - - etc1_optimizer optimizer; - - uint64 best_error = cUINT64_MAX; - uint best_flip = false, best_use_color4 = false; - - uint8 best_selectors[2][8]; - etc1_optimizer::results best_results[2]; - for (uint i = 0; i < 2; i++) - { - best_results[i].m_n = 8; - best_results[i].m_pSelectors = best_selectors[i]; - } - - uint8 selectors[3][8]; - etc1_optimizer::results results[3]; - - for (uint i = 0; i < 3; i++) - { - results[i].m_n = 8; - results[i].m_pSelectors = selectors[i]; - } - - color_quad_u8 subblock_pixels[8]; - - etc1_optimizer::params params(pack_params); - params.m_num_src_pixels = 8; - params.m_pSrc_pixels = subblock_pixels; - - for (uint flip = 0; flip < 2; flip++) - { - for (uint use_color4 = 0; use_color4 < 2; use_color4++) - { - uint64 trial_error = 0; - - uint subblock; - for (subblock = 0; subblock < 2; subblock++) - { - if (flip) - memcpy(subblock_pixels, pSrc_pixels + subblock * 8, sizeof(color_quad_u8) * 8); - else - { - const color_quad_u8* pSrc_col = pSrc_pixels + subblock * 2; - subblock_pixels[0] = pSrc_col[0]; subblock_pixels[1] = pSrc_col[4]; subblock_pixels[2] = pSrc_col[8]; subblock_pixels[3] = pSrc_col[12]; - subblock_pixels[4] = pSrc_col[1]; subblock_pixels[5] = pSrc_col[5]; subblock_pixels[6] = pSrc_col[9]; subblock_pixels[7] = pSrc_col[13]; - } - - results[2].m_error = cUINT64_MAX; - if ((params.m_quality >= cMediumQuality) && ((subblock) || (use_color4))) - { - const uint32 subblock_pixel0_u32 = subblock_pixels[0].m_u32; - for (r = 7; r >= 1; --r) - if (subblock_pixels[r].m_u32 != subblock_pixel0_u32) - break; - if (!r) - { - pack_etc1_block_solid_color_constrained(results[2], 8, &subblock_pixels[0].r, pack_params, !use_color4, (subblock && !use_color4) ? &results[0].m_block_color_unscaled : NULL); - } - } - - params.m_use_color4 = (use_color4 != 0); - params.m_constrain_against_base_color5 = false; - - if ((!use_color4) && (subblock)) - { - params.m_constrain_against_base_color5 = true; - params.m_base_color5 = results[0].m_block_color_unscaled; - } - - if (params.m_quality == cHighQuality) - { - static const int s_scan_delta_0_to_4[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 }; - params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_4); - params.m_pScan_deltas = s_scan_delta_0_to_4; - } - else if (params.m_quality == cMediumQuality) - { - static const int s_scan_delta_0_to_1[] = { -1, 0, 1 }; - params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_1); - params.m_pScan_deltas = s_scan_delta_0_to_1; - } - else - { - static const int s_scan_delta_0[] = { 0 }; - params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0); - params.m_pScan_deltas = s_scan_delta_0; - } - - optimizer.init(params, results[subblock]); - if (!optimizer.compute()) - break; - - if (params.m_quality >= cMediumQuality) - { - // TODO: Fix fairly arbitrary/unrefined thresholds that control how far away to scan for potentially better solutions. - const uint refinement_error_thresh0 = 3000; - const uint refinement_error_thresh1 = 6000; - if (results[subblock].m_error > refinement_error_thresh0) - { - if (params.m_quality == cMediumQuality) - { - static const int s_scan_delta_2_to_3[] = { -3, -2, 2, 3 }; - params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_2_to_3); - params.m_pScan_deltas = s_scan_delta_2_to_3; - } - else - { - static const int s_scan_delta_5_to_5[] = { -5, 5 }; - static const int s_scan_delta_5_to_8[] = { -8, -7, -6, -5, 5, 6, 7, 8 }; - if (results[subblock].m_error > refinement_error_thresh1) - { - params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_8); - params.m_pScan_deltas = s_scan_delta_5_to_8; - } - else - { - params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_5); - params.m_pScan_deltas = s_scan_delta_5_to_5; - } - } - - if (!optimizer.compute()) - break; - } - - if (results[2].m_error < results[subblock].m_error) - results[subblock] = results[2]; - } - - trial_error += results[subblock].m_error; - if (trial_error >= best_error) - break; - } - - if (subblock < 2) - continue; - - best_error = trial_error; - best_results[0] = results[0]; - best_results[1] = results[1]; - best_flip = flip; - best_use_color4 = use_color4; - - } // use_color4 - - } // flip - - int dr = best_results[1].m_block_color_unscaled.r - best_results[0].m_block_color_unscaled.r; - int dg = best_results[1].m_block_color_unscaled.g - best_results[0].m_block_color_unscaled.g; - int db = best_results[1].m_block_color_unscaled.b - best_results[0].m_block_color_unscaled.b; - RG_ETC1_ASSERT(best_use_color4 || (rg_etc1::minimum(dr, dg, db) >= cETC1ColorDeltaMin) && (rg_etc1::maximum(dr, dg, db) <= cETC1ColorDeltaMax)); - - if (best_use_color4) - { - dst_block.m_bytes[0] = static_cast<uint8>(best_results[1].m_block_color_unscaled.r | (best_results[0].m_block_color_unscaled.r << 4)); - dst_block.m_bytes[1] = static_cast<uint8>(best_results[1].m_block_color_unscaled.g | (best_results[0].m_block_color_unscaled.g << 4)); - dst_block.m_bytes[2] = static_cast<uint8>(best_results[1].m_block_color_unscaled.b | (best_results[0].m_block_color_unscaled.b << 4)); - } - else - { - if (dr < 0) dr += 8; dst_block.m_bytes[0] = static_cast<uint8>((best_results[0].m_block_color_unscaled.r << 3) | dr); - if (dg < 0) dg += 8; dst_block.m_bytes[1] = static_cast<uint8>((best_results[0].m_block_color_unscaled.g << 3) | dg); - if (db < 0) db += 8; dst_block.m_bytes[2] = static_cast<uint8>((best_results[0].m_block_color_unscaled.b << 3) | db); - } - - dst_block.m_bytes[3] = static_cast<uint8>( (best_results[1].m_block_inten_table << 2) | (best_results[0].m_block_inten_table << 5) | ((~best_use_color4 & 1) << 1) | best_flip ); - - uint selector0 = 0, selector1 = 0; - if (best_flip) - { - // flipped: - // { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 }, - // { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 } - // - // { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 }, - // { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 } - const uint8* pSelectors0 = best_results[0].m_pSelectors; - const uint8* pSelectors1 = best_results[1].m_pSelectors; - for (int x = 3; x >= 0; --x) - { - uint b; - b = g_selector_index_to_etc1[pSelectors1[4 + x]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - - b = g_selector_index_to_etc1[pSelectors1[x]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - - b = g_selector_index_to_etc1[pSelectors0[4 + x]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - - b = g_selector_index_to_etc1[pSelectors0[x]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - } - } - else - { - // non-flipped: - // { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 }, - // { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 } - // - // { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, - // { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 } - for (int subblock = 1; subblock >= 0; --subblock) - { - const uint8* pSelectors = best_results[subblock].m_pSelectors + 4; - for (uint i = 0; i < 2; i++) - { - uint b; - b = g_selector_index_to_etc1[pSelectors[3]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - - b = g_selector_index_to_etc1[pSelectors[2]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - - b = g_selector_index_to_etc1[pSelectors[1]]; - selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1); - - b = g_selector_index_to_etc1[pSelectors[0]]; - selector0 = (selector0 << 1) | (b & 1);selector1 = (selector1 << 1) | (b >> 1); - - pSelectors -= 4; - } - } - } - - dst_block.m_bytes[4] = static_cast<uint8>(selector1 >> 8); dst_block.m_bytes[5] = static_cast<uint8>(selector1 & 0xFF); - dst_block.m_bytes[6] = static_cast<uint8>(selector0 >> 8); dst_block.m_bytes[7] = static_cast<uint8>(selector0 & 0xFF); - - return static_cast<unsigned int>(best_error); - } - -} // namespace rg_etc1 diff --git a/thirdparty/rg-etc1/rg_etc1.h b/thirdparty/rg-etc1/rg_etc1.h deleted file mode 100644 index 9ce89a6cc6..0000000000 --- a/thirdparty/rg-etc1/rg_etc1.h +++ /dev/null @@ -1,76 +0,0 @@ -// File: rg_etc1.h - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com> -// Please see ZLIB license at the end of this file. -#pragma once - -namespace rg_etc1 -{ - // Unpacks an 8-byte ETC1 compressed block to a block of 4x4 32bpp RGBA pixels. - // Returns false if the block is invalid. Invalid blocks will still be unpacked with clamping. - // This function is thread safe, and does not dynamically allocate any memory. - // If preserve_alpha is true, the alpha channel of the destination pixels will not be overwritten. Otherwise, alpha will be set to 255. - bool unpack_etc1_block(const void *pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha = false); - - // Quality setting = the higher the quality, the slower. - // To pack large textures, it is highly recommended to call pack_etc1_block() in parallel, on different blocks, from multiple threads (particularly when using cHighQuality). - enum etc1_quality - { - cLowQuality, - cMediumQuality, - cHighQuality, - }; - - struct etc1_pack_params - { - etc1_quality m_quality; - bool m_dithering; - - inline etc1_pack_params() - { - clear(); - } - - void clear() - { - m_quality = cHighQuality; - m_dithering = false; - } - }; - - // Important: pack_etc1_block_init() must be called before calling pack_etc1_block(). - void pack_etc1_block_init(); - - // Packs a 4x4 block of 32bpp RGBA pixels to an 8-byte ETC1 block. - // 32-bit RGBA pixels must always be arranged as (R,G,B,A) (R first, A last) in memory, independent of platform endianness. A should always be 255. - // Returns squared error of result. - // This function is thread safe, and does not dynamically allocate any memory. - // pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE. - unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params); - -} // namespace rg_etc1 - -//------------------------------------------------------------------------------ -// -// rg_etc1 uses the ZLIB license: -// http://opensource.org/licenses/Zlib -// -// Copyright (c) 2012 Rich Geldreich -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//------------------------------------------------------------------------------ |