diff options
83 files changed, 2761 insertions, 5568 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7cca1b6f2a..748d787b86 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -169,10 +169,12 @@ /modules/gridmap/icons/ @godotengine/3d-nodes @godotengine/usability /modules/noise/ @godotengine/core /modules/noise/doc_classes/ @godotengine/core @godotengine/documentation +/modules/noise/icons/ @godotengine/core @godotengine/usability /modules/noise/tests/ @godotengine/core @godotengine/tests /modules/regex/ @godotengine/core /modules/regex/doc_classes/ @godotengine/core @godotengine/documentation -/modules/regex/test/ @godotengine/core @godotengine/tests +/modules/regex/icons/ @godotengine/core @godotengine/usability +/modules/regex/tests/ @godotengine/core @godotengine/tests /modules/zip/ @godotengine/core /modules/zip/doc_classes/ @godotengine/core @godotengine/documentation @@ -207,6 +209,7 @@ /scene/resources/text_paragraph.* @godotengine/gui-nodes /scene/resources/visual_shader*.* @godotengine/shaders /scene/theme/ @godotengine/gui-nodes +/scene/theme/icons/ @godotengine/gui-nodes @godotengine/usability # Servers diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml index d2d0e3571f..fd5e74b914 100644 --- a/.github/workflows/runner.yml +++ b/.github/workflows/runner.yml @@ -1,5 +1,5 @@ name: 🔗 GHA -on: [push, pull_request] +on: [push, pull_request, merge_group] concurrency: group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner diff --git a/SConstruct b/SConstruct index 5566770148..63cff4fe16 100644 --- a/SConstruct +++ b/SConstruct @@ -299,7 +299,6 @@ opts.Add(BoolVariable("builtin_pcre2_with_jit", "Use JIT compiler for the built- opts.Add(BoolVariable("builtin_recastnavigation", "Use the built-in Recast navigation library", True)) opts.Add(BoolVariable("builtin_rvo2_2d", "Use the built-in RVO2 2D library", True)) opts.Add(BoolVariable("builtin_rvo2_3d", "Use the built-in RVO2 3D library", True)) -opts.Add(BoolVariable("builtin_squish", "Use the built-in squish library", True)) opts.Add(BoolVariable("builtin_xatlas", "Use the built-in xatlas library", True)) opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib library", True)) opts.Add(BoolVariable("builtin_zstd", "Use the built-in Zstd library", True)) @@ -640,25 +639,18 @@ if env.dev_build: print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).") # Enforce our minimal compiler version requirements -cc_version = methods.get_compiler_version(env) or { - "major": None, - "minor": None, - "patch": None, - "metadata1": None, - "metadata2": None, - "date": None, -} -cc_version_major = int(cc_version["major"] or -1) -cc_version_minor = int(cc_version["minor"] or -1) -cc_version_metadata1 = cc_version["metadata1"] or "" - -if methods.using_gcc(env): - if cc_version_major == -1: - print_warning( - "Couldn't detect compiler version, skipping version checks. " - "Build may fail if the compiler doesn't support C++17 fully." - ) - elif cc_version_major < 9: +cc_version = methods.get_compiler_version(env) +cc_version_major = cc_version["major"] +cc_version_minor = cc_version["minor"] +cc_version_metadata1 = cc_version["metadata1"] + +if cc_version_major == -1: + print_warning( + "Couldn't detect compiler version, skipping version checks. " + "Build may fail if the compiler doesn't support C++17 fully." + ) +elif methods.using_gcc(env): + if cc_version_major < 9: print_error( "Detected GCC version older than 9, which does not fully support " "C++17, or has bugs when compiling Godot. Supported versions are 9 " @@ -678,17 +670,12 @@ if methods.using_gcc(env): print_warning("GCC < 8 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.") env["debug_paths_relative"] = False elif methods.using_clang(env): - if cc_version_major == -1: - print_warning( - "Couldn't detect compiler version, skipping version checks. " - "Build may fail if the compiler doesn't support C++17 fully." - ) # Apple LLVM versions differ from upstream LLVM version \o/, compare # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - elif env["platform"] == "macos" or env["platform"] == "ios": + if env["platform"] == "macos" or env["platform"] == "ios": vanilla = methods.is_vanilla_clang(env) if vanilla and cc_version_major < 6: - print_warning( + print_error( "Detected Clang version older than 6, which does not fully support " "C++17. Supported versions are Clang 6 and later." ) @@ -713,6 +700,28 @@ elif methods.using_clang(env): if env["debug_paths_relative"] and cc_version_major < 10: print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.") env["debug_paths_relative"] = False +elif env.msvc: + # Ensure latest minor builds of Visual Studio 2017/2019. + # https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574 + if cc_version_major == 16 and cc_version_minor < 11: + print_error( + "Detected Visual Studio 2019 version older than 16.11, which has bugs " + "when compiling Godot. Use a newer VS2019 version, or VS2022." + ) + Exit(255) + if cc_version_major == 15 and cc_version_minor < 9: + print_error( + "Detected Visual Studio 2017 version older than 15.9, which has bugs " + "when compiling Godot. Use a newer VS2017 version, or VS2019/VS2022." + ) + Exit(255) + if cc_version_major < 15: + print_error( + "Detected Visual Studio 2015 or earlier, which is unsupported in Godot. " + "Supported versions are Visual Studio 2017 and later." + ) + Exit(255) + # Set optimize and debug_symbols flags. # "custom" means do nothing and let users set their own optimization flags. @@ -790,13 +799,17 @@ if env["lto"] != "none": # This needs to come after `configure`, otherwise we don't have env.msvc. if not env.msvc: # Specifying GNU extensions support explicitly, which are supported by - # both GCC and Clang. Both currently default to gnu11 and gnu++14. + # both GCC and Clang. Both currently default to gnu11 and gnu++17. env.Prepend(CFLAGS=["-std=gnu11"]) env.Prepend(CXXFLAGS=["-std=gnu++17"]) else: - # MSVC doesn't have clear C standard support, /std only covers C++. - # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features. - env.Prepend(CCFLAGS=["/std:c++17"]) + # MSVC started offering C standard support with Visual Studio 2019 16.8, which covers all + # of our supported VS2019 & VS2022 versions; VS2017 will only pass the C++ standard. + env.Prepend(CXXFLAGS=["/std:c++17"]) + if cc_version_major < 16: + print_warning("Visual Studio 2017 cannot specify a C-Standard.") + else: + env.Prepend(CFLAGS=["/std:c11"]) # MSVC is non-conforming with the C++ standard by default, so we enable more conformance. # Note that this is still not complete conformance, as certain Windows-related headers # don't compile under complete conformance. diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 68af5abf66..25da49fa5c 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -677,6 +677,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE); diff --git a/core/object/object.h b/core/object/object.h index efe22ecc1a..110d2790c5 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -87,6 +87,7 @@ enum PropertyHint { PROPERTY_HINT_PASSWORD, PROPERTY_HINT_LAYERS_AVOIDANCE, PROPERTY_HINT_DICTIONARY_TYPE, + PROPERTY_HINT_TOOL_BUTTON, PROPERTY_HINT_MAX, }; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index a86f41cd9c..63d20242d6 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2933,7 +2933,15 @@ <constant name="PROPERTY_HINT_PASSWORD" value="36" enum="PropertyHint"> Hints that a string property is a password, and every character is replaced with the secret character. </constant> - <constant name="PROPERTY_HINT_MAX" value="39" enum="PropertyHint"> + <constant name="PROPERTY_HINT_TOOL_BUTTON" value="39" enum="PropertyHint"> + Hints that a [Callable] property should be displayed as a clickable button. When the button is pressed, the callable is called. The hint string specifies the button text and optionally an icon from the [code]"EditorIcons"[/code] theme type. + [codeblock lang=text] + "Click me!" - A button with the text "Click me!" and the default "Callable" icon. + "Click me!,ColorRect" - A button with the text "Click me!" and the "ColorRect" icon. + [/codeblock] + [b]Note:[/b] A [Callable] cannot be properly serialized and stored in a file, so it is recommended to use [constant PROPERTY_USAGE_EDITOR] instead of [constant PROPERTY_USAGE_DEFAULT]. + </constant> + <constant name="PROPERTY_HINT_MAX" value="40" enum="PropertyHint"> Represents the size of the [enum PropertyHint] enum. </constant> <constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags" is_bitfield="true"> diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml index 8033c0880b..2b6db13906 100644 --- a/doc/classes/CameraFeed.xml +++ b/doc/classes/CameraFeed.xml @@ -45,6 +45,34 @@ [code]copy[/code] will result in FEED_YCBCR </description> </method> + <method name="set_name"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <description> + Sets the camera's name. + </description> + </method> + <method name="set_position"> + <return type="void" /> + <param index="0" name="position" type="int" enum="CameraFeed.FeedPosition" /> + <description> + Sets the position of this camera. + </description> + </method> + <method name="set_rgb_image"> + <return type="void" /> + <param index="0" name="rgb_image" type="Image" /> + <description> + Sets RGB image for this feed. + </description> + </method> + <method name="set_ycbcr_image"> + <return type="void" /> + <param index="0" name="ycbcr_image" type="Image" /> + <description> + Sets YCbCr image for this feed. + </description> + </method> </methods> <members> <member name="feed_is_active" type="bool" setter="set_active" getter="is_active" default="false"> diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 670df10a89..3451e427f3 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -399,6 +399,11 @@ Emitted when this [GraphEdit] captures a [code]ui_copy[/code] action ([kbd]Ctrl + C[/kbd] by default). In general, this signal indicates that the selected [GraphElement]s should be copied. </description> </signal> + <signal name="cut_nodes_request"> + <description> + Emitted when this [GraphEdit] captures a [code]ui_cut[/code] action ([kbd]Ctrl + X[/kbd] by default). In general, this signal indicates that the selected [GraphElement]s should be cut. + </description> + </signal> <signal name="delete_nodes_request"> <param index="0" name="nodes" type="StringName[]" /> <description> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 7b6d8d0cd3..af5ec41b60 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2863,11 +2863,6 @@ </member> <member name="rendering/shading/overrides/force_vertex_shading" type="bool" setter="" getter="" default="false"> If [code]true[/code], forces vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can be used to optimize performance on low-end mobile devices. - [b]Note:[/b] This setting currently has no effect, as vertex shading is not implemented yet. - </member> - <member name="rendering/shading/overrides/force_vertex_shading.mobile" type="bool" setter="" getter="" default="true"> - Lower-end override for [member rendering/shading/overrides/force_vertex_shading] on mobile devices, due to performance concerns or driver support. - [b]Note:[/b] This setting currently has no effect, as vertex shading is not implemented yet. </member> <member name="rendering/textures/canvas_textures/default_texture_filter" type="int" setter="" getter="" default="1"> The default texture filtering mode to use on [CanvasItem]s. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 65749323fd..c2d1784958 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -4125,6 +4125,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() { global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; global_defines += "\n#define MAX_FORWARD_LIGHTS " + itos(config->max_lights_per_object) + "u\n"; global_defines += "\n#define MAX_ROUGHNESS_LOD " + itos(sky_globals.roughness_layers - 1) + ".0\n"; + if (config->force_vertex_shading) { + global_defines += "\n#define USE_VERTEX_LIGHTING\n"; + } material_storage->shaders.scene_shader.initialize(global_defines); scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create(); material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 393ba014c6..9ce10a4488 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -248,6 +248,175 @@ uniform lowp uint directional_shadow_index; #endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)) #endif // USE_ADDITIVE_LIGHTING +#ifdef USE_VERTEX_LIGHTING + +out vec3 diffuse_light_interp; +out vec3 specular_light_interp; + +#ifdef USE_ADDITIVE_LIGHTING +out vec3 additive_diffuse_light_interp; +out vec3 additive_specular_light_interp; +#endif // USE_ADDITIVE_LIGHTING + +// Directional light data. +#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING)) + +struct DirectionalLightData { + mediump vec3 direction; + mediump float energy; + mediump vec3 color; + mediump float size; + lowp uint unused; + lowp uint bake_mode; + mediump float shadow_opacity; + mediump float specular; +}; + +layout(std140) uniform DirectionalLights { // ubo:7 + DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +}; +#endif // !DISABLE_LIGHT_DIRECTIONAL + +// Omni and spot light data. +#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING)) + +struct LightData { // This structure needs to be as packed as possible. + highp vec3 position; + highp float inv_radius; + + mediump vec3 direction; + highp float size; + + mediump vec3 color; + mediump float attenuation; + + mediump float cone_attenuation; + mediump float cone_angle; + mediump float specular_amount; + mediump float shadow_opacity; + + lowp vec3 pad; + lowp uint bake_mode; +}; + +#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI) +layout(std140) uniform OmniLightData { // ubo:5 + LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; +}; +#ifdef BASE_PASS +uniform uint omni_light_indices[MAX_FORWARD_LIGHTS]; +uniform uint omni_light_count; +#endif // BASE_PASS +#endif // DISABLE_LIGHT_OMNI + +#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT) +layout(std140) uniform SpotLightData { // ubo:6 + LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; +}; +#ifdef BASE_PASS +uniform uint spot_light_indices[MAX_FORWARD_LIGHTS]; +uniform uint spot_light_count; +#endif // BASE_PASS +#endif // DISABLE_LIGHT_SPOT +#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING)) + +#ifdef USE_ADDITIVE_LIGHTING +#ifdef ADDITIVE_OMNI +uniform lowp uint omni_light_index; +#endif +#ifdef ADDITIVE_SPOT +uniform lowp uint spot_light_index; +#endif +#endif // USE_ADDITIVE_LIGHTING + +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) + +// Eyeballed approximation of `exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25`. +// Uses slightly more FMA instructions (2x rate) to avoid special instructions (0.25x rate). +// Range is reduced to [0.64,4977] from [068,2,221,528] which makes mediump feasible for the rest of the shader. +mediump float roughness_to_shininess(mediump float roughness) { + mediump float r = 1.2 - roughness; + mediump float r2 = r * r; + return r * r2 * r2 * 2000.0; +} + +void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, bool is_directional, float roughness, + inout vec3 diffuse_light, inout vec3 specular_light) { + float NdotL = min(dot(N, L), 1.0); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + +#if defined(DIFFUSE_LAMBERT_WRAP) + // Energy conserving lambert wrap shader. + // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/ + float diffuse_brdf_NL = max(0.0, (cNdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI); +#else + // lambert + float diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + diffuse_light += light_color * diffuse_brdf_NL; + +#if !defined(SPECULAR_DISABLED) + float specular_brdf_NL = 0.0; + // Normalized blinn always unless disabled. + vec3 H = normalize(V + L); + float cNdotH = clamp(dot(N, H), 0.0, 1.0); + float shininess = roughness_to_shininess(roughness); + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)) * cNdotL; + specular_brdf_NL = blinn; + specular_light += specular_brdf_NL * light_color; +#endif +} + +float get_omni_spot_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + +#if !defined(DISABLE_LIGHT_OMNI) || (defined(ADDITIVE_OMNI) && defined(USE_ADDITIVE_LIGHTING)) +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, + inout vec3 diffuse_light, inout vec3 specular_light) { + vec3 light_rel_vec = omni_lights[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_spot_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation); + vec3 color = omni_lights[idx].color * omni_attenuation; // No light shaders here, so combine. + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, false, roughness, + diffuse_light, + specular_light); +} +#endif // !defined(DISABLE_LIGHT_OMNI) || (defined(ADDITIVE_OMNI) && defined(USE_ADDITIVE_LIGHTING)) + +#if !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING)) +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, + inout vec3 diffuse_light, + inout vec3 specular_light) { + vec3 light_rel_vec = spot_lights[idx].position - vertex; + float light_length = length(light_rel_vec); + float spot_attenuation = get_omni_spot_attenuation(light_length, spot_lights[idx].inv_radius, spot_lights[idx].attenuation); + vec3 spot_dir = spot_lights[idx].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle)); + + mediump float cone_attenuation = spot_lights[idx].cone_attenuation; + spot_attenuation *= 1.0 - pow(spot_rim, cone_attenuation); + + vec3 color = spot_lights[idx].color * spot_attenuation; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, false, roughness, + diffuse_light, specular_light); +} +#endif // !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING)) + +#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) + +#endif // USE_VERTEX_LIGHTING + #ifdef USE_MULTIVIEW layout(std140) uniform MultiviewData { // ubo:8 highp mat4 projection_matrix_view[MAX_VIEWS]; @@ -540,8 +709,65 @@ void main() { gl_Position.z = 0.00001; gl_Position.w = 1.0; #endif -} +#ifdef USE_VERTEX_LIGHTING +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#ifdef USE_MULTIVIEW + vec3 view = -normalize(vertex_interp - eye_offset); +#else + vec3 view = -normalize(vertex_interp); +#endif + diffuse_light_interp = vec3(0.0); + specular_light_interp = vec3(0.0); +#ifdef BASE_PASS +#ifndef DISABLE_LIGHT_DIRECTIONAL + for (uint i = uint(0); i < scene_data.directional_light_count; i++) { + light_compute(normal_interp, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].color * directional_lights[i].energy, true, roughness, + diffuse_light_interp.rgb, + specular_light_interp.rgb); + } +#endif // !DISABLE_LIGHT_DIRECTIONAL + +#ifndef DISABLE_LIGHT_OMNI + for (uint i = 0u; i < omni_light_count; i++) { + light_process_omni(omni_light_indices[i], vertex_interp, view, normal_interp, roughness, + diffuse_light_interp.rgb, specular_light_interp.rgb); + } +#endif // !DISABLE_LIGHT_OMNI + +#ifndef DISABLE_LIGHT_SPOT + for (uint i = 0u; i < spot_light_count; i++) { + light_process_spot(spot_light_indices[i], vertex_interp, view, normal_interp, roughness, + diffuse_light_interp.rgb, specular_light_interp.rgb); + } +#endif // !DISABLE_LIGHT_SPOT +#endif // BASE_PASS + +/* ADDITIVE LIGHTING PASS */ +#ifdef USE_ADDITIVE_LIGHTING + additive_diffuse_light_interp = vec3(0.0); + additive_specular_light_interp = vec3(0.0); +#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT) + + light_compute(normal_interp, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, roughness, + additive_diffuse_light_interp.rgb, + additive_specular_light_interp.rgb); +#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT) + +#ifdef ADDITIVE_OMNI + light_process_omni(omni_light_index, vertex_interp, view, normal_interp, roughness, + additive_diffuse_light_interp.rgb, additive_specular_light_interp.rgb); +#endif // ADDITIVE_OMNI + +#ifdef ADDITIVE_SPOT + light_process_spot(spot_light_index, vertex_interp, view, normal_interp, roughness, + additive_diffuse_light_interp.rgb, additive_specular_light_interp.rgb); +#endif // ADDITIVE_SPOT + +#endif // USE_ADDITIVE_LIGHTING +#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#endif // USE_VERTEX_LIGHTING +} /* clang-format off */ #[fragment] @@ -758,6 +984,16 @@ multiview_data; #define LIGHT_BAKE_DYNAMIC 2u #ifndef MODE_RENDER_DEPTH +#ifdef USE_VERTEX_LIGHTING +in vec3 diffuse_light_interp; +in vec3 specular_light_interp; + +#ifdef USE_ADDITIVE_LIGHTING +in vec3 additive_diffuse_light_interp; +in vec3 additive_specular_light_interp; +#endif // USE_ADDITIVE_LIGHTING +#endif // USE_VERTEX_LIGHTING + // Directional light data. #if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)) @@ -809,22 +1045,22 @@ struct LightData { // This structure needs to be as packed as possible. layout(std140) uniform OmniLightData { // ubo:5 LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; }; -#ifdef BASE_PASS +#if defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING) uniform uint omni_light_indices[MAX_FORWARD_LIGHTS]; uniform uint omni_light_count; -#endif // BASE_PASS -#endif // DISABLE_LIGHT_OMNI +#endif // defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING) +#endif // !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI) #if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT) layout(std140) uniform SpotLightData { // ubo:6 LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; }; -#ifdef BASE_PASS +#if defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING) uniform uint spot_light_indices[MAX_FORWARD_LIGHTS]; uniform uint spot_light_count; -#endif // BASE_PASS -#endif // DISABLE_LIGHT_SPOT -#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) +#endif // defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING) +#endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT) +#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT) #ifdef USE_ADDITIVE_LIGHTING #ifdef ADDITIVE_OMNI @@ -985,6 +1221,8 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } #ifndef MODE_RENDER_DEPTH + +#ifndef USE_VERTEX_LIGHTING #if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(USE_ADDITIVE_LIGHTING) float D_GGX(float cos_theta_m, float alpha) { @@ -1284,6 +1522,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f #endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT) #endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) +#endif // !USE_VERTEX_LIGHTING vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; @@ -1859,9 +2098,13 @@ void main() { specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0); #endif } - #endif // !AMBIENT_LIGHT_DISABLED +#ifdef USE_VERTEX_LIGHTING + specular_light += specular_light_interp * f0; + diffuse_light += diffuse_light_interp; +#else + #ifndef DISABLE_LIGHT_DIRECTIONAL for (uint i = uint(0); i < scene_data.directional_light_count; i++) { #if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP) @@ -1944,6 +2187,7 @@ void main() { diffuse_light, specular_light); } #endif // !DISABLE_LIGHT_SPOT +#endif // !USE_VERTEX_LIGHTING #endif // BASE_PASS #endif // !MODE_UNSHADED @@ -1993,7 +2237,6 @@ void main() { #else diffuse_light *= albedo; - diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; @@ -2024,6 +2267,11 @@ void main() { diffuse_light = vec3(0.0); specular_light = vec3(0.0); +#ifdef USE_VERTEX_LIGHTING + diffuse_light = additive_diffuse_light_interp; + specular_light = additive_specular_light_interp * f0; +#endif // USE_VERTEX_LIGHTING + #if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT) #ifndef SHADOWS_DISABLED @@ -2137,6 +2385,8 @@ void main() { #else float directional_shadow = 1.0f; #endif // SHADOWS_DISABLED + +#ifndef USE_VERTEX_LIGHTING light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, @@ -2153,6 +2403,11 @@ void main() { #endif diffuse_light, specular_light); +#else + // Just apply shadows to vertex lighting. + diffuse_light *= directional_shadow; + specular_light *= directional_shadow; +#endif // !USE_VERTEX_LIGHTING #endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT) #ifdef ADDITIVE_OMNI @@ -2162,6 +2417,8 @@ void main() { omni_shadow = texture(omni_shadow_texture, vec4(light_ray, 1.0 - length(light_ray) * omni_lights[omni_light_index].inv_radius)); omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity); #endif // SHADOWS_DISABLED + +#ifndef USE_VERTEX_LIGHTING light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, @@ -2177,6 +2434,11 @@ void main() { binormal, tangent, anisotropy, #endif diffuse_light, specular_light); +#else + // Just apply shadows to vertex lighting. + diffuse_light *= omni_shadow; + specular_light *= omni_shadow; +#endif // !USE_VERTEX_LIGHTING #endif // ADDITIVE_OMNI #ifdef ADDITIVE_SPOT @@ -2185,6 +2447,8 @@ void main() { spot_shadow = sample_shadow(spot_shadow_texture, positional_shadows[positional_shadow_index].shadow_atlas_pixel_size, shadow_coord); spot_shadow = mix(1.0, spot_shadow, spot_lights[spot_light_index].shadow_opacity); #endif // SHADOWS_DISABLED + +#ifndef USE_VERTEX_LIGHTING light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, @@ -2201,6 +2465,11 @@ void main() { binormal, anisotropy, #endif diffuse_light, specular_light); +#else + // Just apply shadows to vertex lighting. + diffuse_light *= spot_shadow; + specular_light *= spot_shadow; +#endif // !USE_VERTEX_LIGHTING #endif // ADDITIVE_SPOT diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 0100719151..209b7dd7d2 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -178,7 +178,7 @@ Config::Config() { } #endif - force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); + force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading"); use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter"); use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")); diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index c29c741c2a..5dca149d99 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1368,6 +1368,10 @@ MaterialStorage::MaterialStorage() { actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + if (!GLES3::Config::get_singleton()->force_vertex_shading) { + // If forcing vertex shading, this will be defined already. + actions.render_mode_defines["vertex_lighting"] = "#define USE_VERTEX_LIGHTING\n"; + } actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n"; actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; diff --git a/editor/plugins/tool_button_editor_plugin.cpp b/editor/plugins/tool_button_editor_plugin.cpp new file mode 100644 index 0000000000..d9852c8694 --- /dev/null +++ b/editor/plugins/tool_button_editor_plugin.cpp @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* tool_button_editor_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "tool_button_editor_plugin.h" + +#include "scene/gui/button.h" + +void EditorInspectorToolButtonPlugin::_update_action_icon(Button *p_action_button, const String &p_action_icon) { + p_action_button->set_icon(p_action_button->get_editor_theme_icon(p_action_icon)); +} + +void EditorInspectorToolButtonPlugin::_call_action(const Variant &p_object, const StringName &p_property) { + Object *object = p_object.get_validated_object(); + ERR_FAIL_NULL_MSG(object, vformat(R"(Failed to get property "%s" on a previously freed instance.)", p_property)); + + const Variant value = object->get(p_property); + ERR_FAIL_COND_MSG(value.get_type() != Variant::CALLABLE, vformat(R"(The value of property "%s" is %s, but Callable was expected.)", p_property, Variant::get_type_name(value.get_type()))); + + const Callable callable = value; + ERR_FAIL_COND_MSG(!callable.is_valid(), vformat(R"(Tool button action "%s" is an invalid callable.)", callable)); + + Variant ret; + Callable::CallError ce; + callable.callp(nullptr, 0, ret, ce); + ERR_FAIL_COND_MSG(ce.error != Callable::CallError::CALL_OK, vformat(R"(Error calling tool button action "%s": %s)", callable, Variant::get_call_error_text(callable.get_method(), nullptr, 0, ce))); +} + +bool EditorInspectorToolButtonPlugin::can_handle(Object *p_object) { + return true; +} + +bool EditorInspectorToolButtonPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) { + if (p_type != Variant::CALLABLE || p_hint != PROPERTY_HINT_TOOL_BUTTON || !p_usage.has_flag(PROPERTY_USAGE_EDITOR)) { + return false; + } + + const PackedStringArray splits = p_hint_text.rsplit(",", true, 1); + const String &hint_text = splits[0]; // Safe since `splits` cannot be empty. + const String &hint_icon = splits.size() > 1 ? splits[1] : "Callable"; + + Button *action_button = EditorInspector::create_inspector_action_button(hint_text); + action_button->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); + action_button->set_disabled(p_usage & PROPERTY_USAGE_READ_ONLY); + action_button->connect(SceneStringName(theme_changed), callable_mp(this, &EditorInspectorToolButtonPlugin::_update_action_icon).bind(action_button, hint_icon)); + action_button->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorToolButtonPlugin::_call_action).bind(p_object, p_path)); + + add_custom_control(action_button); + return true; +} + +ToolButtonEditorPlugin::ToolButtonEditorPlugin() { + Ref<EditorInspectorToolButtonPlugin> plugin; + plugin.instantiate(); + add_inspector_plugin(plugin); +} diff --git a/modules/squish/image_decompress_squish.cpp b/editor/plugins/tool_button_editor_plugin.h index 3841ba8db1..2d185c3a8f 100644 --- a/modules/squish/image_decompress_squish.cpp +++ b/editor/plugins/tool_button_editor_plugin.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* image_decompress_squish.cpp */ +/* tool_button_editor_plugin.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,69 +28,30 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "image_decompress_squish.h" +#ifndef TOOL_BUTTON_EDITOR_PLUGIN_H +#define TOOL_BUTTON_EDITOR_PLUGIN_H -#include <squish.h> +#include "editor/editor_inspector.h" +#include "editor/plugins/editor_plugin.h" -void image_decompress_squish(Image *p_image) { - int w = p_image->get_width(); - int h = p_image->get_height(); +class EditorInspectorToolButtonPlugin : public EditorInspectorPlugin { + GDCLASS(EditorInspectorToolButtonPlugin, EditorInspectorPlugin); - Image::Format source_format = p_image->get_format(); - Image::Format target_format = Image::FORMAT_RGBA8; + void _update_action_icon(Button *p_action_button, const String &p_action_icon); + void _call_action(const Variant &p_object, const StringName &p_property); - Vector<uint8_t> data; - int64_t target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); - int mm_count = p_image->get_mipmap_count(); - data.resize(target_size); +public: + virtual bool can_handle(Object *p_object) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override; +}; - const uint8_t *rb = p_image->get_data().ptr(); - uint8_t *wb = data.ptrw(); +class ToolButtonEditorPlugin : public EditorPlugin { + GDCLASS(ToolButtonEditorPlugin, EditorPlugin); - int squish_flags = 0; +public: + virtual String get_name() const override { return "ToolButtonEditorPlugin"; } - switch (source_format) { - case Image::FORMAT_DXT1: - squish_flags = squish::kDxt1; - break; + ToolButtonEditorPlugin(); +}; - case Image::FORMAT_DXT3: - squish_flags = squish::kDxt3; - break; - - case Image::FORMAT_DXT5: - case Image::FORMAT_DXT5_RA_AS_RG: - squish_flags = squish::kDxt5; - break; - - case Image::FORMAT_RGTC_R: - squish_flags = squish::kBc4; - break; - - case Image::FORMAT_RGTC_RG: - squish_flags = squish::kBc5; - break; - - default: - ERR_FAIL_MSG("Squish: Can't decompress unknown format: " + itos(p_image->get_format()) + "."); - break; - } - - for (int i = 0; i <= mm_count; i++) { - int64_t src_ofs = 0, mipmap_size = 0; - int mipmap_w = 0, mipmap_h = 0; - p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h); - - int64_t dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i); - squish::DecompressImage(&wb[dst_ofs], w, h, &rb[src_ofs], squish_flags); - - w >>= 1; - h >>= 1; - } - - p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); - - if (source_format == Image::FORMAT_DXT5_RA_AS_RG) { - p_image->convert_ra_rgba8_to_rg(); - } -} +#endif // TOOL_BUTTON_EDITOR_PLUGIN_H diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index f98a30ebb3..ede8351e41 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -6300,6 +6300,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed)); graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes)); graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(false)); + graph->connect("cut_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(true)); graph->connect("paste_nodes_request", callable_mp(this, &VisualShaderEditor::_paste_nodes).bind(false, Point2())); graph->connect("delete_nodes_request", callable_mp(this, &VisualShaderEditor::_delete_nodes_request)); graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input)); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index 00377a0dd2..19aeeb0612 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -127,6 +127,7 @@ #include "editor/plugins/texture_region_editor_plugin.h" #include "editor/plugins/theme_editor_plugin.h" #include "editor/plugins/tiles/tiles_editor_plugin.h" +#include "editor/plugins/tool_button_editor_plugin.h" #include "editor/plugins/version_control_editor_plugin.h" #include "editor/plugins/visual_shader_editor_plugin.h" #include "editor/plugins/voxel_gi_editor_plugin.h" @@ -247,6 +248,7 @@ void register_editor_types() { EditorPlugins::add_by_type<TextureLayeredEditorPlugin>(); EditorPlugins::add_by_type<TextureRegionEditorPlugin>(); EditorPlugins::add_by_type<ThemeEditorPlugin>(); + EditorPlugins::add_by_type<ToolButtonEditorPlugin>(); EditorPlugins::add_by_type<VoxelGIEditorPlugin>(); // 2D diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp index ae7c86a5e5..ca5d3cbf2a 100644 --- a/editor/renames_map_3_to_4.cpp +++ b/editor/renames_map_3_to_4.cpp @@ -1354,7 +1354,6 @@ const char *RenamesMap3To4::project_settings_renames[][2] = { { "rendering/quality/shading/force_lambert_over_burley", "rendering/shading/overrides/force_lambert_over_burley" }, { "rendering/quality/shading/force_lambert_over_burley.mobile", "rendering/shading/overrides/force_lambert_over_burley.mobile" }, { "rendering/quality/shading/force_vertex_shading", "rendering/shading/overrides/force_vertex_shading" }, - { "rendering/quality/shading/force_vertex_shading.mobile", "rendering/shading/overrides/force_vertex_shading.mobile" }, { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_0_subdiv" }, { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_1_subdiv" }, { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_2_subdiv" }, @@ -1400,7 +1399,6 @@ const char *RenamesMap3To4::project_godot_renames[][2] = { { "quality/shading/force_lambert_over_burley", "shading/overrides/force_lambert_over_burley" }, { "quality/shading/force_lambert_over_burley.mobile", "shading/overrides/force_lambert_over_burley.mobile" }, { "quality/shading/force_vertex_shading", "shading/overrides/force_vertex_shading" }, - { "quality/shading/force_vertex_shading.mobile", "shading/overrides/force_vertex_shading.mobile" }, { "quality/shadow_atlas/quadrant_0_subdiv", "lights_and_shadows/shadow_atlas/quadrant_0_subdiv" }, { "quality/shadow_atlas/quadrant_1_subdiv", "lights_and_shadows/shadow_atlas/quadrant_1_subdiv" }, { "quality/shadow_atlas/quadrant_2_subdiv", "lights_and_shadows/shadow_atlas/quadrant_2_subdiv" }, diff --git a/methods.py b/methods.py index 3f11d39bd0..411ce59d9e 100644 --- a/methods.py +++ b/methods.py @@ -795,9 +795,9 @@ def get_compiler_version(env): "major": -1, "minor": -1, "patch": -1, - "metadata1": None, - "metadata2": None, - "date": None, + "metadata1": "", + "metadata2": "", + "date": "", "apple_major": -1, "apple_minor": -1, "apple_patch1": -1, @@ -806,7 +806,20 @@ def get_compiler_version(env): } if env.msvc and not using_clang(env): - # TODO: Implement for MSVC + try: + args = [env["VSWHERE"], "-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"] + version = subprocess.check_output(args, encoding="utf-8").strip() + for line in version.splitlines(): + split = line.split(":", 1) + if split[0] == "catalog_productDisplayVersion": + sem_ver = split[1].split(".") + ret["major"] = int(sem_ver[0]) + ret["minor"] = int(sem_ver[1]) + ret["patch"] = int(sem_ver[2]) + if split[0] == "catalog_buildVersion": + ret["metadata1"] = split[1] + except (subprocess.CalledProcessError, OSError): + print_warning("Couldn't find vswhere to determine compiler version.") return ret # Not using -dumpversion as some GCC distros only return major, and diff --git a/modules/bcdec/SCsub b/modules/bcdec/SCsub new file mode 100644 index 0000000000..32198eff96 --- /dev/null +++ b/modules/bcdec/SCsub @@ -0,0 +1,10 @@ +#!/usr/bin/env python +from misc.utility.scons_hints import * + +Import("env") +Import("env_modules") + +env_bcdec = env_modules.Clone() + +# Godot source files +env_bcdec.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/squish/config.py b/modules/bcdec/config.py index d22f9454ed..d22f9454ed 100644 --- a/modules/squish/config.py +++ b/modules/bcdec/config.py diff --git a/modules/bcdec/image_decompress_bcdec.cpp b/modules/bcdec/image_decompress_bcdec.cpp new file mode 100644 index 0000000000..30ca1fccb3 --- /dev/null +++ b/modules/bcdec/image_decompress_bcdec.cpp @@ -0,0 +1,181 @@ +/**************************************************************************/ +/* image_decompress_bcdec.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_decompress_bcdec.h" + +#include "core/os/os.h" +#include "core/string/print_string.h" + +#define BCDEC_IMPLEMENTATION +#include "thirdparty/misc/bcdec.h" + +inline void bcdec_bc6h_half_s(const void *compressedBlock, void *decompressedBlock, int destinationPitch) { + bcdec_bc6h_half(compressedBlock, decompressedBlock, destinationPitch, true); +} + +inline void bcdec_bc6h_half_u(const void *compressedBlock, void *decompressedBlock, int destinationPitch) { + bcdec_bc6h_half(compressedBlock, decompressedBlock, destinationPitch, false); +} + +static void decompress_image(BCdecFormat format, const void *src, void *dst, const uint64_t width, const uint64_t height) { + const uint8_t *src_blocks = reinterpret_cast<const uint8_t *>(src); + uint8_t *dec_blocks = reinterpret_cast<uint8_t *>(dst); + uint64_t src_pos = 0, dst_pos = 0; + +#define DECOMPRESS_LOOP(func, block_size, color_bytesize, color_components) \ + for (uint64_t y = 0; y < height; y += 4) { \ + for (uint64_t x = 0; x < width; x += 4) { \ + func(&src_blocks[src_pos], &dec_blocks[dst_pos], width *color_components); \ + src_pos += block_size; \ + dst_pos += 4 * color_bytesize; \ + } \ + dst_pos += 3 * width * color_bytesize; \ + } + + switch (format) { + case BCdec_BC1: { + DECOMPRESS_LOOP(bcdec_bc1, BCDEC_BC1_BLOCK_SIZE, 4, 4) + } break; + case BCdec_BC2: { + DECOMPRESS_LOOP(bcdec_bc2, BCDEC_BC2_BLOCK_SIZE, 4, 4) + } break; + case BCdec_BC3: { + DECOMPRESS_LOOP(bcdec_bc3, BCDEC_BC3_BLOCK_SIZE, 4, 4) + } break; + case BCdec_BC4: { + DECOMPRESS_LOOP(bcdec_bc4, BCDEC_BC4_BLOCK_SIZE, 1, 1) + } break; + case BCdec_BC5: { + DECOMPRESS_LOOP(bcdec_bc5, BCDEC_BC5_BLOCK_SIZE, 2, 2) + } break; + case BCdec_BC6U: { + DECOMPRESS_LOOP(bcdec_bc6h_half_u, BCDEC_BC6H_BLOCK_SIZE, 6, 3) + } break; + case BCdec_BC6S: { + DECOMPRESS_LOOP(bcdec_bc6h_half_s, BCDEC_BC6H_BLOCK_SIZE, 6, 3) + } break; + case BCdec_BC7: { + DECOMPRESS_LOOP(bcdec_bc7, BCDEC_BC7_BLOCK_SIZE, 4, 4) + } break; + } + +#undef DECOMPRESS_LOOP +} + +void image_decompress_bcdec(Image *p_image) { + uint64_t start_time = OS::get_singleton()->get_ticks_msec(); + + int w = p_image->get_width(); + int h = p_image->get_height(); + + Image::Format source_format = p_image->get_format(); + Image::Format target_format = Image::FORMAT_MAX; + + BCdecFormat bcdec_format = BCdec_BC1; + + switch (source_format) { + case Image::FORMAT_DXT1: + bcdec_format = BCdec_BC1; + target_format = Image::FORMAT_RGBA8; + break; + + case Image::FORMAT_DXT3: + bcdec_format = BCdec_BC2; + target_format = Image::FORMAT_RGBA8; + break; + + case Image::FORMAT_DXT5: + case Image::FORMAT_DXT5_RA_AS_RG: + bcdec_format = BCdec_BC3; + target_format = Image::FORMAT_RGBA8; + break; + + case Image::FORMAT_RGTC_R: + bcdec_format = BCdec_BC4; + target_format = Image::FORMAT_R8; + break; + + case Image::FORMAT_RGTC_RG: + bcdec_format = BCdec_BC5; + target_format = Image::FORMAT_RG8; + break; + + case Image::FORMAT_BPTC_RGBFU: + bcdec_format = BCdec_BC6U; + target_format = Image::FORMAT_RGBH; + break; + + case Image::FORMAT_BPTC_RGBF: + bcdec_format = BCdec_BC6S; + target_format = Image::FORMAT_RGBH; + break; + + case Image::FORMAT_BPTC_RGBA: + bcdec_format = BCdec_BC7; + target_format = Image::FORMAT_RGBA8; + break; + + default: + ERR_FAIL_MSG("bcdec: Can't decompress unknown format: " + Image::get_format_name(source_format) + "."); + break; + } + + int mm_count = p_image->get_mipmap_count(); + int64_t target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); + + Vector<uint8_t> data; + data.resize(target_size); + + const uint8_t *rb = p_image->get_data().ptr(); + uint8_t *wb = data.ptrw(); + + // Decompress mipmaps. + for (int i = 0; i <= mm_count; i++) { + int64_t src_ofs = 0, mipmap_size = 0; + int mipmap_w = 0, mipmap_h = 0; + p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h); + + int64_t dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i); + decompress_image(bcdec_format, rb + src_ofs, wb + dst_ofs, mipmap_w, mipmap_h); + + w >>= 1; + h >>= 1; + } + + p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); + + // Swap channels if necessary. + if (source_format == Image::FORMAT_DXT5_RA_AS_RG) { + p_image->convert_ra_rgba8_to_rg(); + } + + print_verbose(vformat("bcdec: Decompression of a %dx%d %s image with %d mipmaps took %d ms.", + p_image->get_width(), p_image->get_height(), Image::get_format_name(source_format), p_image->get_mipmap_count(), OS::get_singleton()->get_ticks_msec() - start_time)); +} diff --git a/modules/squish/image_decompress_squish.h b/modules/bcdec/image_decompress_bcdec.h index 53c5d344a5..b82ceed9a4 100644 --- a/modules/squish/image_decompress_squish.h +++ b/modules/bcdec/image_decompress_bcdec.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* image_decompress_squish.h */ +/* image_decompress_bcdec.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef IMAGE_DECOMPRESS_SQUISH_H -#define IMAGE_DECOMPRESS_SQUISH_H +#ifndef IMAGE_DECOMPRESS_BCDEC_H +#define IMAGE_DECOMPRESS_BCDEC_H #include "core/io/image.h" -void image_decompress_squish(Image *p_image); +enum BCdecFormat { + BCdec_BC1, + BCdec_BC2, + BCdec_BC3, + BCdec_BC4, + BCdec_BC5, + BCdec_BC6S, + BCdec_BC6U, + BCdec_BC7, +}; -#endif // IMAGE_DECOMPRESS_SQUISH_H +void image_decompress_bcdec(Image *p_image); + +#endif // IMAGE_DECOMPRESS_BCDEC_H diff --git a/modules/squish/register_types.cpp b/modules/bcdec/register_types.cpp index af7cf8f4f1..cbf9c0d383 100644 --- a/modules/squish/register_types.cpp +++ b/modules/bcdec/register_types.cpp @@ -30,17 +30,18 @@ #include "register_types.h" -#include "image_decompress_squish.h" +#include "image_decompress_bcdec.h" -void initialize_squish_module(ModuleInitializationLevel p_level) { +void initialize_bcdec_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - Image::_image_decompress_bc = image_decompress_squish; + Image::_image_decompress_bc = image_decompress_bcdec; + Image::_image_decompress_bptc = image_decompress_bcdec; } -void uninitialize_squish_module(ModuleInitializationLevel p_level) { +void uninitialize_bcdec_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } diff --git a/modules/squish/register_types.h b/modules/bcdec/register_types.h index 1786b28ed3..eb721e3f2a 100644 --- a/modules/squish/register_types.h +++ b/modules/bcdec/register_types.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef SQUISH_REGISTER_TYPES_H -#define SQUISH_REGISTER_TYPES_H +#ifndef BCDEC_REGISTER_TYPES_H +#define BCDEC_REGISTER_TYPES_H #include "modules/register_module_types.h" -void initialize_squish_module(ModuleInitializationLevel p_level); -void uninitialize_squish_module(ModuleInitializationLevel p_level); +void initialize_bcdec_module(ModuleInitializationLevel p_level); +void uninitialize_bcdec_module(ModuleInitializationLevel p_level); -#endif // SQUISH_REGISTER_TYPES_H +#endif // BCDEC_REGISTER_TYPES_H diff --git a/modules/camera/buffer_decoder.cpp b/modules/camera/buffer_decoder.cpp index 024a68f080..85cfea242c 100644 --- a/modules/camera/buffer_decoder.cpp +++ b/modules/camera/buffer_decoder.cpp @@ -105,7 +105,7 @@ void SeparateYuyvBufferDecoder::decode(StreamingBuffer p_buffer) { cbcr_image.instantiate(width, height, false, Image::FORMAT_RGB8, cbcr_image_data); } - camera_feed->set_YCbCr_imgs(y_image, cbcr_image); + camera_feed->set_ycbcr_images(y_image, cbcr_image); } YuyvToGrayscaleBufferDecoder::YuyvToGrayscaleBufferDecoder(CameraFeed *p_camera_feed) : @@ -133,7 +133,7 @@ void YuyvToGrayscaleBufferDecoder::decode(StreamingBuffer p_buffer) { image.instantiate(width, height, false, Image::FORMAT_RGB8, image_data); } - camera_feed->set_RGB_img(image); + camera_feed->set_rgb_image(image); } YuyvToRgbBufferDecoder::YuyvToRgbBufferDecoder(CameraFeed *p_camera_feed) : @@ -176,7 +176,7 @@ void YuyvToRgbBufferDecoder::decode(StreamingBuffer p_buffer) { image.instantiate(width, height, false, Image::FORMAT_RGB8, image_data); } - camera_feed->set_RGB_img(image); + camera_feed->set_rgb_image(image); } CopyBufferDecoder::CopyBufferDecoder(CameraFeed *p_camera_feed, bool p_rgba) : @@ -195,7 +195,7 @@ void CopyBufferDecoder::decode(StreamingBuffer p_buffer) { image.instantiate(width, height, false, rgba ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8, image_data); } - camera_feed->set_RGB_img(image); + camera_feed->set_rgb_image(image); } JpegBufferDecoder::JpegBufferDecoder(CameraFeed *p_camera_feed) : @@ -207,6 +207,6 @@ void JpegBufferDecoder::decode(StreamingBuffer p_buffer) { uint8_t *dst = (uint8_t *)image_data.ptrw(); memcpy(dst, p_buffer.start, p_buffer.length); if (image->load_jpg_from_buffer(image_data) == OK) { - camera_feed->set_RGB_img(image); + camera_feed->set_rgb_image(image); } } diff --git a/modules/camera/camera_macos.mm b/modules/camera/camera_macos.mm index 578a1d6325..de4f814846 100644 --- a/modules/camera/camera_macos.mm +++ b/modules/camera/camera_macos.mm @@ -182,7 +182,7 @@ } // set our texture... - feed->set_YCbCr_imgs(img[0], img[1]); + feed->set_ycbcr_images(img[0], img[1]); } // and unlock diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp index 211d419349..80e3062d04 100644 --- a/modules/cvtt/register_types.cpp +++ b/modules/cvtt/register_types.cpp @@ -40,7 +40,6 @@ void initialize_cvtt_module(ModuleInitializationLevel p_level) { } Image::set_compress_bptc_func(image_compress_cvtt); - Image::_image_decompress_bptc = image_decompress_cvtt; } void uninitialize_cvtt_module(ModuleInitializationLevel p_level) { diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index f539f27848..5fe47d69df 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -669,6 +669,41 @@ [b]Note:[/b] Subgroups cannot be nested, they only provide one extra level of depth. Just like the next group ends the previous group, so do the subsequent subgroups. </description> </annotation> + <annotation name="@export_tool_button"> + <return type="void" /> + <param index="0" name="text" type="String" /> + <param index="1" name="icon" type="String" default="""" /> + <description> + Export a [Callable] property as a clickable button with the label [param text]. When the button is pressed, the callable is called. + If [param icon] is specified, it is used to fetch an icon for the button via [method Control.get_theme_icon], from the [code]"EditorIcons"[/code] theme type. If [param icon] is omitted, the default [code]"Callable"[/code] icon is used instead. + Consider using the [EditorUndoRedoManager] to allow the action to be reverted safely. + See also [constant PROPERTY_HINT_TOOL_BUTTON]. + [codeblock] + @tool + extends Sprite2D + + @export_tool_button("Hello") var hello_action = hello + @export_tool_button("Randomize the color!", "ColorRect") + var randomize_color_action = randomize_color + + func hello(): + print("Hello world!") + + func randomize_color(): + var undo_redo = EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Randomized Sprite2D Color") + undo_redo.add_do_property(self, &"self_modulate", Color(randf(), randf(), randf())) + undo_redo.add_undo_property(self, &"self_modulate", self_modulate) + undo_redo.commit_action() + [/codeblock] + [b]Note:[/b] The property is exported without the [constant PROPERTY_USAGE_STORAGE] flag because a [Callable] cannot be properly serialized and stored in a file. + [b]Note:[/b] In an exported project neither [EditorInterface] nor [EditorUndoRedoManager] exist, which may cause some scripts to break. To prevent this, you can use [method Engine.get_singleton] and omit the static type from the variable declaration: + [codeblock] + var undo_redo = Engine.get_singleton(&"EditorInterface").get_editor_undo_redo() + [/codeblock] + [b]Note:[/b] Avoid storing lambda callables in member variables of [RefCounted]-based classes (e.g. resources), as this can lead to memory leaks. Use only method callables and optionally [method Callable.bind] or [method Callable.unbind]. + </description> + </annotation> <annotation name="@icon"> <return type="void" /> <param index="0" name="icon_path" type="String" /> diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 65aa150be3..e169566705 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -122,6 +122,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>); register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_storage_annotation); register_annotation(MethodInfo("@export_custom", PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "PropertyHint"), PropertyInfo(Variant::STRING, "hint_string"), PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_BITFIELD, "PropertyUsageFlags")), AnnotationInfo::VARIABLE, &GDScriptParser::export_custom_annotation, varray(PROPERTY_USAGE_DEFAULT)); + register_annotation(MethodInfo("@export_tool_button", PropertyInfo(Variant::STRING, "text"), PropertyInfo(Variant::STRING, "icon")), AnnotationInfo::VARIABLE, &GDScriptParser::export_tool_button_annotation, varray("")); // Export grouping annotations. register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray("")); @@ -4618,10 +4619,10 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta // For `@export_storage` and `@export_custom`, there is no need to check the variable type, argument values, // or handle array exports in a special way, so they are implemented as separate methods. -bool GDScriptParser::export_storage_annotation(AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { - ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); +bool GDScriptParser::export_storage_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { + ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); - VariableNode *variable = static_cast<VariableNode *>(p_node); + VariableNode *variable = static_cast<VariableNode *>(p_target); if (variable->is_static) { push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); return false; @@ -4640,11 +4641,11 @@ bool GDScriptParser::export_storage_annotation(AnnotationNode *p_annotation, Nod return true; } -bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { - ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); +bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { + ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); ERR_FAIL_COND_V_MSG(p_annotation->resolved_arguments.size() < 2, false, R"(Annotation "@export_custom" requires 2 arguments.)"); - VariableNode *variable = static_cast<VariableNode *>(p_node); + VariableNode *variable = static_cast<VariableNode *>(p_target); if (variable->is_static) { push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); return false; @@ -4668,12 +4669,56 @@ bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node return true; } -template <PropertyUsageFlags t_usage> -bool GDScriptParser::export_group_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { - if (p_annotation->resolved_arguments.is_empty()) { +bool GDScriptParser::export_tool_button_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { +#ifdef TOOLS_ENABLED + ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); + ERR_FAIL_COND_V(p_annotation->resolved_arguments.is_empty(), false); + + if (!is_tool()) { + push_error(R"(Tool buttons can only be used in tool scripts (add "@tool" to the top of the script).)", p_annotation); + return false; + } + + VariableNode *variable = static_cast<VariableNode *>(p_target); + + if (variable->is_static) { + push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); + return false; + } + if (variable->exported) { + push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); return false; } + const DataType variable_type = variable->get_datatype(); + if (!variable_type.is_variant() && variable_type.is_hard_type()) { + if (variable_type.kind != DataType::BUILTIN || variable_type.builtin_type != Variant::CALLABLE) { + push_error(vformat(R"("@export_tool_button" annotation requires a variable of type "Callable", but type "%s" was given instead.)", variable_type.to_string()), p_annotation); + return false; + } + } + + variable->exported = true; + + // Build the hint string (format: `<text>[,<icon>]`). + String hint_string = p_annotation->resolved_arguments[0].operator String(); // Button text. + if (p_annotation->resolved_arguments.size() > 1) { + hint_string += "," + p_annotation->resolved_arguments[1].operator String(); // Button icon. + } + + variable->export_info.type = Variant::CALLABLE; + variable->export_info.hint = PROPERTY_HINT_TOOL_BUTTON; + variable->export_info.hint_string = hint_string; + variable->export_info.usage = PROPERTY_USAGE_EDITOR; +#endif // TOOLS_ENABLED + + return true; // Only available in editor. +} + +template <PropertyUsageFlags t_usage> +bool GDScriptParser::export_group_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { + ERR_FAIL_COND_V(p_annotation->resolved_arguments.is_empty(), false); + p_annotation->export_info.name = p_annotation->resolved_arguments[0]; switch (t_usage) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 7840474a89..7f64ae902b 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1507,6 +1507,7 @@ private: bool export_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); bool export_storage_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); bool export_custom_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); + bool export_tool_button_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyUsageFlags t_usage> bool export_group_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); bool warning_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); diff --git a/modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.gd b/modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.gd new file mode 100644 index 0000000000..48be5b2541 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.gd @@ -0,0 +1 @@ +@export_tool_button("Click me!") var action diff --git a/modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.out b/modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.out new file mode 100644 index 0000000000..fb148308e4 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Tool buttons can only be used in tool scripts (add "@tool" to the top of the script). diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd index 1e134d0e0e..8aa449f602 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd @@ -1,3 +1,4 @@ +@tool class_name ExportVariableTest extends Node @@ -47,6 +48,10 @@ const PreloadedUnnamedClass = preload("./export_variable_unnamed.notest.gd") @export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_weak_int = 5 @export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_hard_int: int = 6 +# `@export_tool_button`. +@export_tool_button("Click me!") var test_tool_button_1: Callable +@export_tool_button("Click me!", "ColorRect") var test_tool_button_2: Callable + func test(): for property in get_property_list(): if str(property.name).begins_with("test_"): diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out index d10462bb8d..0d915e00e6 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.out +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -55,3 +55,7 @@ var test_export_custom_weak_int: int = 5 hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_export_custom_hard_int: int = 6 hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_tool_button_1: Callable = Callable() + hint=TOOL_BUTTON hint_string="Click me!" usage=EDITOR|SCRIPT_VARIABLE class_name=&"" +var test_tool_button_2: Callable = Callable() + hint=TOOL_BUTTON hint_string="Click me!,ColorRect" usage=EDITOR|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index 1e2788f765..fa289e442f 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -205,6 +205,9 @@ static func get_property_hint_name(hint: PropertyHint) -> String: return "PROPERTY_HINT_HIDE_QUATERNION_EDIT" PROPERTY_HINT_PASSWORD: return "PROPERTY_HINT_PASSWORD" + PROPERTY_HINT_TOOL_BUTTON: + return "PROPERTY_HINT_TOOL_BUTTON" + printerr("Argument `hint` is invalid. Use `PROPERTY_HINT_*` constants.") return "<invalid hint>" diff --git a/modules/squish/SCsub b/modules/squish/SCsub deleted file mode 100644 index d8e7fbc142..0000000000 --- a/modules/squish/SCsub +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -from misc.utility.scons_hints import * - -Import("env") -Import("env_modules") - -env_squish = env_modules.Clone() - -# Thirdparty source files - -thirdparty_obj = [] - -if env["builtin_squish"]: - thirdparty_dir = "#thirdparty/squish/" - thirdparty_sources = [ - "alpha.cpp", - "clusterfit.cpp", - "colourblock.cpp", - "colourfit.cpp", - "colourset.cpp", - "maths.cpp", - "rangefit.cpp", - "singlecolourfit.cpp", - "squish.cpp", - ] - - thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - - env_squish.Prepend(CPPPATH=[thirdparty_dir]) - - env_thirdparty = env_squish.Clone() - env_thirdparty.disable_warnings() - env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) - env.modules_sources += thirdparty_obj - - -# Godot source files - -module_obj = [] - -env_squish.add_source_files(module_obj, "*.cpp") -env.modules_sources += module_obj - -# Needed to force rebuilding the module files when the thirdparty library is updated. -env.Depends(module_obj, thirdparty_obj) diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index d1de760f34..a67434527c 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -256,10 +256,6 @@ def configure(env: "SConsEnvironment"): if not env["builtin_enet"]: env.ParseConfig("pkg-config libenet --cflags --libs") - if not env["builtin_squish"]: - # libsquish doesn't reliably install its .pc file, so some distros lack it. - env.Append(LIBS=["libsquish"]) - if not env["builtin_zstd"]: env.ParseConfig("pkg-config libzstd --cflags --libs") diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 11a6411e65..cf8815679f 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1999,6 +1999,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { } else if (p_ev->is_action("ui_copy", true)) { emit_signal(SNAME("copy_nodes_request")); accept_event(); + } else if (p_ev->is_action("ui_cut", true)) { + emit_signal(SNAME("cut_nodes_request")); + accept_event(); } else if (p_ev->is_action("ui_paste", true)) { emit_signal(SNAME("paste_nodes_request")); accept_event(); @@ -2735,6 +2738,7 @@ void GraphEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("connection_drag_ended")); ADD_SIGNAL(MethodInfo("copy_nodes_request")); + ADD_SIGNAL(MethodInfo("cut_nodes_request")); ADD_SIGNAL(MethodInfo("paste_nodes_request")); ADD_SIGNAL(MethodInfo("duplicate_nodes_request")); ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName"))); diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp index 8f6a40481d..4021d9564b 100644 --- a/servers/camera/camera_feed.cpp +++ b/servers/camera/camera_feed.cpp @@ -33,26 +33,23 @@ #include "servers/rendering_server.h" void CameraFeed::_bind_methods() { - // The setters prefixed with _ are only exposed so we can have feeds through GDExtension! - // They should not be called by the end user. - ClassDB::bind_method(D_METHOD("get_id"), &CameraFeed::get_id); ClassDB::bind_method(D_METHOD("is_active"), &CameraFeed::is_active); ClassDB::bind_method(D_METHOD("set_active", "active"), &CameraFeed::set_active); ClassDB::bind_method(D_METHOD("get_name"), &CameraFeed::get_name); - ClassDB::bind_method(D_METHOD("_set_name", "name"), &CameraFeed::set_name); + ClassDB::bind_method(D_METHOD("set_name", "name"), &CameraFeed::set_name); ClassDB::bind_method(D_METHOD("get_position"), &CameraFeed::get_position); - ClassDB::bind_method(D_METHOD("_set_position", "position"), &CameraFeed::set_position); + ClassDB::bind_method(D_METHOD("set_position", "position"), &CameraFeed::set_position); // Note, for transform some feeds may override what the user sets (such as ARKit) ClassDB::bind_method(D_METHOD("get_transform"), &CameraFeed::get_transform); ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CameraFeed::set_transform); - ClassDB::bind_method(D_METHOD("_set_RGB_img", "rgb_img"), &CameraFeed::set_RGB_img); - ClassDB::bind_method(D_METHOD("_set_YCbCr_img", "ycbcr_img"), &CameraFeed::set_YCbCr_img); + ClassDB::bind_method(D_METHOD("set_rgb_image", "rgb_image"), &CameraFeed::set_rgb_image); + ClassDB::bind_method(D_METHOD("set_ycbcr_image", "ycbcr_image"), &CameraFeed::set_ycbcr_image); ClassDB::bind_method(D_METHOD("get_datatype"), &CameraFeed::get_datatype); @@ -175,7 +172,7 @@ CameraFeed::~CameraFeed() { RenderingServer::get_singleton()->free(texture[CameraServer::FEED_CBCR_IMAGE]); } -void CameraFeed::set_RGB_img(const Ref<Image> &p_rgb_img) { +void CameraFeed::set_rgb_image(const Ref<Image> &p_rgb_img) { ERR_FAIL_COND(p_rgb_img.is_null()); if (active) { int new_width = p_rgb_img->get_width(); @@ -198,7 +195,7 @@ void CameraFeed::set_RGB_img(const Ref<Image> &p_rgb_img) { } } -void CameraFeed::set_YCbCr_img(const Ref<Image> &p_ycbcr_img) { +void CameraFeed::set_ycbcr_image(const Ref<Image> &p_ycbcr_img) { ERR_FAIL_COND(p_ycbcr_img.is_null()); if (active) { int new_width = p_ycbcr_img->get_width(); @@ -221,7 +218,7 @@ void CameraFeed::set_YCbCr_img(const Ref<Image> &p_ycbcr_img) { } } -void CameraFeed::set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img) { +void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img) { ERR_FAIL_COND(p_y_img.is_null()); ERR_FAIL_COND(p_cbcr_img.is_null()); if (active) { diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h index 5d1f54be07..492a909239 100644 --- a/servers/camera/camera_feed.h +++ b/servers/camera/camera_feed.h @@ -110,9 +110,9 @@ public: virtual ~CameraFeed(); FeedDataType get_datatype() const; - void set_RGB_img(const Ref<Image> &p_rgb_img); - void set_YCbCr_img(const Ref<Image> &p_ycbcr_img); - void set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img); + void set_rgb_image(const Ref<Image> &p_rgb_img); + void set_ycbcr_image(const Ref<Image> &p_ycbcr_img); + void set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img); virtual bool set_format(int p_index, const Dictionary &p_parameters); virtual Array get_formats() const; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index aca85ce497..307898232d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -4261,6 +4261,11 @@ RenderForwardClustered::RenderForwardClustered() { defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; + bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading"); + if (force_vertex_shading) { + defines += "\n#define USE_VERTEX_LIGHTING\n"; + } + { //lightmaps scene_state.max_lightmaps = MAX_LIGHTMAPS; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 6846c3f693..ee5b5ef1d8 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -730,13 +730,20 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + + bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading"); + if (!force_vertex_shading) { + // If forcing vertex shading, this will be defined already. + actions.render_mode_defines["vertex_lighting"] = "#define USE_VERTEX_LIGHTING\n"; + } + actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n"; actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n"; actions.base_texture_binding_index = 1; actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET; actions.base_uniform_string = "material."; - actions.base_varying_index = 12; + actions.base_varying_index = 14; actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 8a02ec0eb5..fa8796fae6 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2800,6 +2800,11 @@ RenderForwardMobile::RenderForwardMobile() { // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; + bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading"); + if (force_vertex_shading) { + defines += "\n#define USE_VERTEX_LIGHTING\n"; + } + { //lightmaps scene_state.max_lightmaps = 2; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 08982096c5..5dec4d8f21 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -633,6 +633,13 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + + bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading"); + if (!force_vertex_shading) { + // If forcing vertex shading, this will be defined already. + actions.render_mode_defines["vertex_lighting"] = "#define USE_VERTEX_LIGHTING\n"; + } + actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n"; actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n"; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 57497eb207..5441e28be0 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1974,6 +1974,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { default_canvas_texture = texture_storage->canvas_texture_allocate(); texture_storage->canvas_texture_initialize(default_canvas_texture); + RendererRD::TextureStorage::CanvasTextureInfo info = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(default_canvas_texture, default_filter, default_repeat, false, false); + default_texture_info.diffuse = info.diffuse; + default_texture_info.normal = info.normal; + default_texture_info.specular = info.specular; + default_texture_info.sampler = info.sampler; + state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size"); //create functions for shader and material @@ -2219,7 +2225,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET); Item *current_clip = nullptr; - state.current_tex_uniform_set = RID(); + state.current_batch_uniform_set = RID(); for (uint32_t i = 0; i <= state.current_batch_index; i++) { Batch *current_batch = &state.canvas_instance_batches[i]; @@ -2337,11 +2343,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar instance_data->world[i] = world[i]; } - instance_data->flags = base_flags | r_current_batch->tex_flags; // Reset on each command for safety, keep canvas texture binding config. + instance_data->flags = base_flags | r_current_batch->tex_info.flags; // Reset on each command for safety, keep canvas texture binding config. - instance_data->color_texture_pixel_size[0] = r_current_batch->tex_texpixel_size.width; - instance_data->color_texture_pixel_size[1] = r_current_batch->tex_texpixel_size.height; - instance_data->specular_shininess = r_current_batch->tex_specular_shininess; + instance_data->color_texture_pixel_size[0] = r_current_batch->tex_info.texpixel_size.width; + instance_data->color_texture_pixel_size[1] = r_current_batch->tex_info.texpixel_size.height; + instance_data->specular_shininess = r_current_batch->tex_info.specular_shininess; return instance_data; }; @@ -2373,10 +2379,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF); TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors); - if (tex_state != r_current_batch->tex_state) { + if (tex_state != r_current_batch->tex_info.state) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, rect->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, rect->texture); } Color modulated = rect->modulate * base_color; @@ -2399,7 +2405,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar Rect2 dst_rect; if (rect->texture.is_valid()) { - src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_texpixel_size, rect->source.size * r_current_batch->tex_texpixel_size) : Rect2(0, 0, 1, 1); + src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_info.texpixel_size, rect->source.size * r_current_batch->tex_info.texpixel_size) : Rect2(0, 0, 1, 1); dst_rect = Rect2(rect->rect.position, rect->rect.size); if (dst_rect.size.width < 0) { @@ -2484,10 +2490,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar } TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_state) { + if (tex_state != r_current_batch->tex_info.state) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, np->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, np->texture); } InstanceData *instance_data = new_instance_data(); @@ -2499,7 +2505,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar src_rect = Rect2(0, 0, 1, 1); } else { if (np->source != Rect2()) { - src_rect = Rect2(np->source.position.x * r_current_batch->tex_texpixel_size.width, np->source.position.y * r_current_batch->tex_texpixel_size.height, np->source.size.x * r_current_batch->tex_texpixel_size.width, np->source.size.y * r_current_batch->tex_texpixel_size.height); + src_rect = Rect2(np->source.position.x * r_current_batch->tex_info.texpixel_size.width, np->source.position.y * r_current_batch->tex_info.texpixel_size.height, np->source.size.x * r_current_batch->tex_info.texpixel_size.width, np->source.size.y * r_current_batch->tex_info.texpixel_size.height); instance_data->color_texture_pixel_size[0] = 1.0 / np->source.size.width; instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height; } else { @@ -2553,10 +2559,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->command = c; TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_state) { + if (tex_state != r_current_batch->tex_info.state) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, polygon->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, polygon->texture); } // pipeline variant @@ -2596,10 +2602,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch->pipeline_variant = variant[primitive->point_count - 1]; TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors); - if (tex_state != r_current_batch->tex_state) { + if (tex_state != r_current_batch->tex_info.state) { r_current_batch = _new_batch(r_batch_broken); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, primitive->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, primitive->texture); } } @@ -2657,8 +2663,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar if (c->type == Item::Command::TYPE_MESH) { const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c); TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, m->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, m->texture); instance_data = new_instance_data(); r_current_batch->mesh_instance_count = 1; @@ -2680,8 +2686,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar } TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, mm->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, mm->texture); instance_data = new_instance_data(); instance_data->flags |= 1; // multimesh, trails disabled @@ -2698,8 +2704,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c); TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors); - r_current_batch->set_tex_state(tex_state); - _prepare_batch_texture(r_current_batch, pt->texture); + r_current_batch->tex_info.state = tex_state; + _prepare_batch_texture_info(r_current_batch, pt->texture); instance_data = new_instance_data(); @@ -2795,7 +2801,20 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV ERR_FAIL_NULL(p_batch->command); - _bind_canvas_texture(p_draw_list, p_batch->tex_uniform_set); + { + RD::Uniform u_diffuse(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info.diffuse); + RD::Uniform u_normal(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info.normal); + RD::Uniform u_specular(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info.specular); + RD::Uniform u_sampler(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info.sampler); + RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); + + RID uniform_set = uniform_set_cache->get_cache(shader.default_version_rd_shader, BATCH_UNIFORM_SET, u_diffuse, u_normal, u_specular, u_sampler, u_instance_data); + + if (state.current_batch_uniform_set != uniform_set) { + state.current_batch_uniform_set = uniform_set; + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, BATCH_UNIFORM_SET); + } + } switch (p_batch->command_type) { case Item::Command::TYPE_RECT: @@ -2810,13 +2829,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV PushConstant push_constant; push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); - - RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); - RD::get_singleton()->draw_list_bind_uniform_set( - p_draw_list, - uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data), - INSTANCE_DATA_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); RD::get_singleton()->draw_list_draw(p_draw_list, true, p_batch->instance_count); @@ -2839,13 +2851,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV PushConstant push_constant; push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); - - RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); - RD::get_singleton()->draw_list_bind_uniform_set( - p_draw_list, - uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data), - INSTANCE_DATA_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array); if (pb->indices.is_valid()) { RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices); @@ -2868,13 +2873,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV PushConstant push_constant; push_constant.base_instance_index = p_batch->start; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); - - RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); - RD::get_singleton()->draw_list_bind_uniform_set( - p_draw_list, - uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data), - INSTANCE_DATA_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]); uint32_t instance_count = p_batch->instance_count; RD::get_singleton()->draw_list_draw(p_draw_list, true, instance_count); @@ -2934,12 +2932,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV break; } - RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]); - RD::get_singleton()->draw_list_bind_uniform_set( - p_draw_list, - uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data), - INSTANCE_DATA_UNIFORM_SET); - uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh); static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP }; @@ -3046,60 +3038,46 @@ void RendererCanvasRenderRD::_allocate_instance_buffer() { state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(buf); } -void RendererCanvasRenderRD::_prepare_batch_texture(Batch *p_current_batch, RID p_texture) const { +void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const { if (p_texture.is_null()) { p_texture = default_canvas_texture; } - Color specular_shininess; - bool use_normal; - bool use_specular; - Size2i size; - bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set( - p_texture, - p_current_batch->tex_state.texture_filter(), - p_current_batch->tex_state.texture_repeat(), - shader.default_version_rd_shader, - CANVAS_TEXTURE_UNIFORM_SET, - p_current_batch->tex_state.linear_colors(), - p_current_batch->tex_uniform_set, - size, - specular_shininess, - use_normal, - use_specular, - p_current_batch->tex_state.texture_is_data()); + RendererRD::TextureStorage::CanvasTextureInfo info = + RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info( + p_texture, + p_current_batch->tex_info.state.texture_filter(), + p_current_batch->tex_info.state.texture_repeat(), + p_current_batch->tex_info.state.linear_colors(), + p_current_batch->tex_info.state.texture_is_data()); + // something odd happened - if (!success) { - _prepare_batch_texture(p_current_batch, default_canvas_texture); + if (info.is_null()) { + _prepare_batch_texture_info(p_current_batch, default_canvas_texture); return; } - // cache values to be copied to instance data - if (specular_shininess.a < 0.999) { - p_current_batch->tex_flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; - } + p_current_batch->tex_info.diffuse = info.diffuse; + p_current_batch->tex_info.normal = info.normal; + p_current_batch->tex_info.specular = info.specular; + p_current_batch->tex_info.sampler = info.sampler; - if (use_normal) { - p_current_batch->tex_flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; + // cache values to be copied to instance data + if (info.specular_color.a < 0.999) { + p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; } - uint8_t a = uint8_t(CLAMP(specular_shininess.a * 255.0, 0.0, 255.0)); - uint8_t b = uint8_t(CLAMP(specular_shininess.b * 255.0, 0.0, 255.0)); - uint8_t g = uint8_t(CLAMP(specular_shininess.g * 255.0, 0.0, 255.0)); - uint8_t r = uint8_t(CLAMP(specular_shininess.r * 255.0, 0.0, 255.0)); - p_current_batch->tex_specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r); - - p_current_batch->tex_texpixel_size = Vector2(1.0 / float(size.width), 1.0 / float(size.height)); -} - -void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set) { - if (state.current_tex_uniform_set == p_uniform_set) { - return; + if (info.use_normal) { + p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; } - state.current_tex_uniform_set = p_uniform_set; + uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0)); + uint8_t b = uint8_t(CLAMP(info.specular_color.b * 255.0, 0.0, 255.0)); + uint8_t g = uint8_t(CLAMP(info.specular_color.g * 255.0, 0.0, 255.0)); + uint8_t r = uint8_t(CLAMP(info.specular_color.r * 255.0, 0.0, 255.0)); + p_current_batch->tex_info.specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r); - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, p_uniform_set, CANVAS_TEXTURE_UNIFORM_SET); + p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height)); } RendererCanvasRenderRD::~RendererCanvasRenderRD() { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 8d90cd23ce..b0f4a4595a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -45,8 +45,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { BASE_UNIFORM_SET = 0, MATERIAL_UNIFORM_SET = 1, TRANSFORMS_UNIFORM_SET = 2, - CANVAS_TEXTURE_UNIFORM_SET = 3, - INSTANCE_DATA_UNIFORM_SET = 4, + BATCH_UNIFORM_SET = 3, }; const int SAMPLERS_BINDING_FIRST_INDEX = 10; @@ -423,24 +422,25 @@ class RendererCanvasRenderRD : public RendererCanvasRender { } }; + struct TextureInfo { + TextureState state; + uint32_t specular_shininess = 0; + uint32_t flags = 0; + Vector2 texpixel_size; + + RID diffuse; + RID normal; + RID specular; + RID sampler; + }; + struct Batch { // Position in the UBO measured in bytes uint32_t start = 0; uint32_t instance_count = 0; uint32_t instance_buffer_index = 0; - TextureState tex_state; - RID tex_uniform_set; - - // The following tex_ prefixed fields are used to cache the texture data for the current batch. - // These values are applied to new InstanceData for the batch - - // The cached specular shininess derived from the current texture. - uint32_t tex_specular_shininess = 0; - // The cached texture flags, such as FLAGS_DEFAULT_SPECULAR_MAP_USED and FLAGS_DEFAULT_NORMAL_MAP_USED - uint32_t tex_flags = 0; - // The cached texture pixel size. - Vector2 tex_texpixel_size; + TextureInfo tex_info; Color modulate = Color(1.0, 1.0, 1.0, 1.0); @@ -462,14 +462,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender { uint32_t mesh_instance_count; }; bool has_blend = false; - - void set_tex_state(TextureState &p_tex_state) { - tex_state = p_tex_state; - tex_uniform_set = RID(); - tex_texpixel_size = Size2(); - tex_specular_shininess = 0; - tex_flags = 0; - } }; struct DataBuffer { @@ -509,7 +501,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { uint32_t max_instances_per_buffer = 16384; uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData); - RID current_tex_uniform_set; + RID current_batch_uniform_set; LightUniform *light_uniforms = nullptr; @@ -532,6 +524,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { Item *items[MAX_RENDER_ITEMS]; + TextureInfo default_texture_info; + bool using_directional_lights = false; RID default_canvas_texture; @@ -561,8 +555,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr); void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch); void _render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr); - void _prepare_batch_texture(Batch *p_current_batch, RID p_texture) const; - void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set); + void _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const; [[nodiscard]] Batch *_new_batch(bool &r_batch_broken); void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch); void _allocate_instance_buffer(); diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 7cf5b4576e..fc9b727581 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -54,11 +54,6 @@ struct InstanceData { uint lights[4]; }; -layout(set = 4, binding = 0, std430) restrict readonly buffer DrawData { - InstanceData data[]; -} -instances; - layout(push_constant, std430) uniform Params { uint base_instance_index; // base index to instance data uint pad1; @@ -163,3 +158,8 @@ layout(set = 3, binding = 0) uniform texture2D color_texture; layout(set = 3, binding = 1) uniform texture2D normal_texture; layout(set = 3, binding = 2) uniform texture2D specular_texture; layout(set = 3, binding = 3) uniform sampler texture_sampler; + +layout(set = 3, binding = 4, std430) restrict readonly buffer DrawData { + InstanceData data[]; +} +instances; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 400451ec36..3cbe1427b6 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -156,8 +156,30 @@ vec2 multiview_uv(vec2 uv) { ivec2 multiview_uv(ivec2 uv) { return uv; } + #endif //USE_MULTIVIEW +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) +layout(location = 12) highp out vec4 diffuse_light_interp; +layout(location = 13) highp out vec4 specular_light_interp; + +#include "../scene_forward_vertex_lights_inc.glsl" + +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFFu; + item_max = item_min_max >> 16; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} +#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) invariant gl_Position; #GLOBALS @@ -488,6 +510,145 @@ void vertex_shader(vec3 vertex_input, screen_pos = gl_Position; #endif +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) + diffuse_light_interp = vec4(0.0); + specular_light_interp = vec4(0.0); + +#ifdef USE_MULTIVIEW + vec3 view = -normalize(vertex_interp - eye_offset); + vec2 clip_pos = clamp((combined_projected.xy / combined_projected.w) * 0.5 + 0.5, 0.0, 1.0); +#else + vec3 view = -normalize(vertex_interp); + vec2 clip_pos = clamp((gl_Position.xy / gl_Position.w) * 0.5 + 0.5, 0.0, 1.0); +#endif + + uvec2 cluster_pos = uvec2(clip_pos / scene_data.screen_pixel_size) >> implementation_data.cluster_shift; + uint cluster_offset = (implementation_data.cluster_width * cluster_pos.y + cluster_pos.x) * (implementation_data.max_cluster_element_count_div_32 + 32); + uint cluster_z = uint(clamp((-vertex_interp.z / scene_data.z_far) * 32.0, 0.0, 31.0)); + + { //omni lights + + uint cluster_omni_offset = cluster_offset; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_omni_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); + uint merged_mask = mask; + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1u << bit); + uint light_index = 32 * i + bit; + + if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } + + light_process_omni_vertex(light_index, vertex, view, normal, roughness, + diffuse_light_interp.rgb, specular_light_interp.rgb); + } + } + } + + { //spot lights + uint cluster_spot_offset = cluster_offset + implementation_data.cluster_type_size; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); + uint merged_mask = mask; + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1u << bit); + + uint light_index = 32 * i + bit; + + if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } + + light_process_spot_vertex(light_index, vertex, view, normal, roughness, + diffuse_light_interp.rgb, specular_light_interp.rgb); + } + } + } + + { // Directional light. + + // We process the first directional light separately as it may have shadows. + vec3 directional_diffuse = vec3(0.0); + vec3 directional_specular = vec3(0.0); + + for (uint i = 0; i < scene_data.directional_light_count; i++) { + if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { + continue; // Not masked, skip. + } + + if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip. + } + if (i == 0) { + light_compute_vertex(normal, directional_lights.data[0].direction, view, + directional_lights.data[0].color * directional_lights.data[0].energy, + true, roughness, + directional_diffuse, + directional_specular); + } else { + light_compute_vertex(normal, directional_lights.data[i].direction, view, + directional_lights.data[i].color * directional_lights.data[i].energy, + true, roughness, + diffuse_light_interp.rgb, + specular_light_interp.rgb); + } + } + + // Calculate the contribution from the shadowed light so we can scale the shadows accordingly. + float diff_avg = dot(diffuse_light_interp.rgb, vec3(0.33333)); + float diff_dir_avg = dot(directional_diffuse, vec3(0.33333)); + if (diff_avg > 0.0) { + diffuse_light_interp.a = diff_dir_avg / (diff_avg + diff_dir_avg); + } else { + diffuse_light_interp.a = 1.0; + } + + diffuse_light_interp.rgb += directional_diffuse; + + float spec_avg = dot(specular_light_interp.rgb, vec3(0.33333)); + float spec_dir_avg = dot(directional_specular, vec3(0.33333)); + if (spec_avg > 0.0) { + specular_light_interp.a = spec_dir_avg / (spec_avg + spec_dir_avg); + } else { + specular_light_interp.a = 1.0; + } + + specular_light_interp.rgb += directional_specular; + } + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) + #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { if (gl_Position.z >= 0.9999) { @@ -791,7 +952,10 @@ ivec2 multiview_uv(ivec2 uv) { return uv; } #endif //USE_MULTIVIEW - +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) +layout(location = 12) highp in vec4 diffuse_light_interp; +layout(location = 13) highp in vec4 specular_light_interp; +#endif //defines to keep compatibility with vertex #ifdef USE_MULTIVIEW @@ -1375,7 +1539,6 @@ void fragment_shader(in SceneData scene_data) { vec3 specular_light = vec3(0.0, 0.0, 0.0); vec3 diffuse_light = vec3(0.0, 0.0, 0.0); vec3 ambient_light = vec3(0.0, 0.0, 0.0); - #ifndef MODE_UNSHADED // Used in regular draw pass and when drawing SDFs for SDFGI and materials for VoxelGI. emission *= scene_data.emissive_exposure_normalization; @@ -1836,6 +1999,11 @@ void fragment_shader(in SceneData scene_data) { // LIGHTING #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#ifdef USE_VERTEX_LIGHTING + diffuse_light += diffuse_light_interp.rgb; + specular_light += specular_light_interp.rgb * f0; +#endif + { // Directional light. // Do shadow and lighting in two passes to reduce register pressure. @@ -1843,10 +2011,15 @@ void fragment_shader(in SceneData scene_data) { uint shadow0 = 0; uint shadow1 = 0; +#ifdef USE_VERTEX_LIGHTING + // Only process the first light's shadow for vertex lighting. + for (uint i = 0; i < 1; i++) { +#else for (uint i = 0; i < 8; i++) { if (i >= scene_data.directional_light_count) { break; } +#endif if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { continue; //not masked @@ -2044,6 +2217,11 @@ void fragment_shader(in SceneData scene_data) { shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance +#ifdef USE_VERTEX_LIGHTING + diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a); + specular_light *= mix(1.0, shadow, specular_light_interp.a); +#endif + #undef BIAS_FUNC } // shadows @@ -2055,6 +2233,8 @@ void fragment_shader(in SceneData scene_data) { } #endif // SHADOWS_DISABLED +#ifndef USE_VERTEX_LIGHTING + for (uint i = 0; i < 8; i++) { if (i >= scene_data.directional_light_count) { break; @@ -2175,8 +2355,10 @@ void fragment_shader(in SceneData scene_data) { diffuse_light, specular_light); } +#endif // USE_VERTEX_LIGHTING } +#ifndef USE_VERTEX_LIGHTING { //omni lights uint cluster_omni_offset = cluster_offset; @@ -2320,6 +2502,8 @@ void fragment_shader(in SceneData scene_data) { } } } +#endif // !USE_VERTEX_LIGHTING +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifdef USE_SHADOW_TO_OPACITY #ifndef MODE_RENDER_DEPTH @@ -2334,8 +2518,6 @@ void fragment_shader(in SceneData scene_data) { #endif // !MODE_RENDER_DEPTH #endif // USE_SHADOW_TO_OPACITY -#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - #ifdef MODE_RENDER_DEPTH #ifdef MODE_RENDER_SDF diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 17c7b756c3..e7ce44bce2 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -105,7 +105,16 @@ layout(location = 4) mediump out vec2 uv2_interp; layout(location = 5) mediump out vec3 tangent_interp; layout(location = 6) mediump out vec3 binormal_interp; #endif +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) +layout(location = 7) highp out vec4 diffuse_light_interp; +layout(location = 8) highp out vec4 specular_light_interp; +layout(constant_id = 9) const bool sc_disable_omni_lights = false; +layout(constant_id = 10) const bool sc_disable_spot_lights = false; +layout(constant_id = 12) const bool sc_disable_directional_lights = false; + +#include "../scene_forward_vertex_lights_inc.glsl" +#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) #ifdef MATERIAL_UNIFORMS_USED /* clang-format off */ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms { @@ -185,6 +194,7 @@ void main() { mat4 model_matrix = instances.data[draw_call.instance_index].transform; mat4 inv_view_matrix = scene_data.inv_view_matrix; + #ifdef USE_DOUBLE_PRECISION vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]); model_matrix[0][3] = 0.0; @@ -448,6 +458,107 @@ void main() { binormal_interp = binormal; #endif +// VERTEX LIGHTING +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) +#ifdef USE_MULTIVIEW + vec3 view = -normalize(vertex_interp - eye_offset); +#else + vec3 view = -normalize(vertex_interp); +#endif + + diffuse_light_interp = vec4(0.0); + specular_light_interp = vec4(0.0); + + if (!sc_disable_omni_lights) { + uint light_indices = instances.data[draw_call.instance_index].omni_lights.x; + for (uint i = 0; i < 8; i++) { + uint light_index = light_indices & 0xFF; + if (i == 3) { + light_indices = instances.data[draw_call.instance_index].omni_lights.y; + } else { + light_indices = light_indices >> 8; + } + + if (light_index == 0xFF) { + break; + } + + light_process_omni_vertex(light_index, vertex, view, normal, roughness, + diffuse_light_interp.rgb, specular_light_interp.rgb); + } + } + + if (!sc_disable_spot_lights) { + uint light_indices = instances.data[draw_call.instance_index].spot_lights.x; + for (uint i = 0; i < 8; i++) { + uint light_index = light_indices & 0xFF; + if (i == 3) { + light_indices = instances.data[draw_call.instance_index].spot_lights.y; + } else { + light_indices = light_indices >> 8; + } + + if (light_index == 0xFF) { + break; + } + + light_process_spot_vertex(light_index, vertex, view, normal, roughness, + diffuse_light_interp.rgb, specular_light_interp.rgb); + } + } + + if (!sc_disable_directional_lights) { + // We process the first directional light separately as it may have shadows. + vec3 directional_diffuse = vec3(0.0); + vec3 directional_specular = vec3(0.0); + + for (uint i = 0; i < scene_data.directional_light_count; i++) { + if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { + continue; // Not masked, skip. + } + + if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip. + } + if (i == 0) { + light_compute_vertex(normal, directional_lights.data[0].direction, view, + directional_lights.data[0].color * directional_lights.data[0].energy, + true, roughness, + directional_diffuse, + directional_specular); + } else { + light_compute_vertex(normal, directional_lights.data[i].direction, view, + directional_lights.data[i].color * directional_lights.data[i].energy, + true, roughness, + diffuse_light_interp.rgb, + specular_light_interp.rgb); + } + } + + // Calculate the contribution from the shadowed light so we can scale the shadows accordingly. + float diff_avg = dot(diffuse_light_interp.rgb, vec3(0.33333)); + float diff_dir_avg = dot(directional_diffuse, vec3(0.33333)); + if (diff_avg > 0.0) { + diffuse_light_interp.a = diff_dir_avg / (diff_avg + diff_dir_avg); + } else { + diffuse_light_interp.a = 1.0; + } + + diffuse_light_interp.rgb += directional_diffuse; + + float spec_avg = dot(specular_light_interp.rgb, vec3(0.33333)); + float spec_dir_avg = dot(directional_specular, vec3(0.33333)); + if (spec_avg > 0.0) { + specular_light_interp.a = spec_dir_avg / (spec_avg + spec_dir_avg); + } else { + specular_light_interp.a = 1.0; + } + + specular_light_interp.rgb += directional_specular; + } + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) + #ifdef MODE_RENDER_DEPTH #ifdef MODE_DUAL_PARABOLOID @@ -564,6 +675,11 @@ layout(location = 5) mediump in vec3 tangent_interp; layout(location = 6) mediump in vec3 binormal_interp; #endif +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) +layout(location = 7) highp in vec4 diffuse_light_interp; +layout(location = 8) highp in vec4 specular_light_interp; +#endif + #ifdef MODE_DUAL_PARABOLOID layout(location = 9) highp in float dp_clip; @@ -709,7 +825,7 @@ layout(location = 0) out mediump vec4 frag_color; #include "../scene_forward_aa_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) // && !defined(USE_VERTEX_LIGHTING) // Default to SPECULAR_SCHLICK_GGX. #if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON) @@ -718,7 +834,7 @@ layout(location = 0) out mediump vec4 frag_color; #include "../scene_forward_lights_inc.glsl" -#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && !defined(USE_VERTEX_LIGHTING) #ifndef MODE_RENDER_DEPTH @@ -1401,6 +1517,10 @@ void main() { // LIGHTING #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#ifdef USE_VERTEX_LIGHTING + diffuse_light += diffuse_light_interp.rgb; + specular_light += specular_light_interp.rgb * f0; +#endif if (!sc_disable_directional_lights) { //directional light #ifndef SHADOWS_DISABLED @@ -1408,10 +1528,12 @@ void main() { uint shadow0 = 0; uint shadow1 = 0; - for (uint i = 0; i < 8; i++) { - if (i >= scene_data.directional_light_count) { - break; - } +#ifdef USE_VERTEX_LIGHTING + // Only process the first light's shadow for vertex lighting. + for (uint i = 0; i < 1; i++) { +#else + for (uint i = 0; i < scene_data.directional_light_count; i++) { +#endif if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; //not masked @@ -1419,164 +1541,6 @@ void main() { float shadow = 1.0; - // Directional light shadow code is basically the same as forward clustered at this point in time minus `LIGHT_TRANSMITTANCE_USED` support. - // Not sure if there is a reason to change this seeing directional lights are part of our global data - // Should think about whether we may want to move this code into an include file or function?? - -#ifdef USE_SOFT_SHADOWS - //version with soft shadows, more expensive - if (directional_lights.data[i].shadow_opacity > 0.001) { - float depth_z = -vertex.z; - - vec4 pssm_coord; - vec3 light_dir = directional_lights.data[i].direction; - -#define BIAS_FUNC(m_var, m_idx) \ - m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \ - normal_bias -= light_dir * dot(light_dir, normal_bias); \ - m_var.xyz += normal_bias; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 0) - - pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.x; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 1) - - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.y; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 2) - - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.z; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - } else { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 3) - - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.w; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - } - - if (directional_lights.data[i].blend_splits) { - float pssm_blend; - float shadow2; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 1) - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.y; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - - pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 2) - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.z; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - - pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 3) - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); - pssm_coord /= pssm_coord.w; - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.w; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count); - } else { - shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count); - } - - pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); - } else { - pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) - } - - pssm_blend = sqrt(pssm_blend); - - shadow = mix(shadow, shadow2, pssm_blend); - } - - shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance - -#undef BIAS_FUNC - } -#else - // Soft shadow disabled version - if (directional_lights.data[i].shadow_opacity > 0.001) { float depth_z = -vertex.z; @@ -1667,6 +1631,10 @@ void main() { shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance +#ifdef USE_VERTEX_LIGHTING + diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a); + specular_light *= mix(1.0, shadow, specular_light_interp.a); +#endif #undef BIAS_FUNC } #endif @@ -1678,13 +1646,8 @@ void main() { } } -#endif // SHADOWS_DISABLED - - for (uint i = 0; i < 8; i++) { - if (i >= scene_data.directional_light_count) { - break; - } - +#ifndef USE_VERTEX_LIGHTING + for (uint i = 0; i < scene_data.directional_light_count; i++) { if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; //not masked } @@ -1703,8 +1666,8 @@ void main() { #endif blur_shadow(shadow); -#ifdef DEBUG_DRAW_PSSM_SPLITS vec3 tint = vec3(1.0); +#ifdef DEBUG_DRAW_PSSM_SPLITS if (-vertex.z < directional_lights.data[i].shadow_split_offsets.x) { tint = vec3(1.0, 0.0, 0.0); } else if (-vertex.z < directional_lights.data[i].shadow_split_offsets.y) { @@ -1718,12 +1681,10 @@ void main() { shadow = 1.0; #endif - light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0, -#ifndef DEBUG_DRAW_PSSM_SPLITS - directional_lights.data[i].color * directional_lights.data[i].energy, -#else + float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0; + + light_compute(normal, directional_lights.data[i].direction, view, size_A, directional_lights.data[i].color * directional_lights.data[i].energy * tint, -#endif true, shadow, f0, orms, 1.0, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, @@ -1745,14 +1706,13 @@ void main() { #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif -#ifdef USE_SOFT_SHADOW - directional_lights.data[i].size, -#endif diffuse_light, specular_light); } +#endif // USE_VERTEX_LIGHTING } //directional light +#ifndef USE_VERTEX_LIGHTING if (!sc_disable_omni_lights) { //omni lights uint light_indices = instances.data[draw_call.instance_index].omni_lights.x; for (uint i = 0; i < 8; i++) { @@ -1771,6 +1731,7 @@ void main() { shadow = blur_shadow(shadow); + // Fragment lighting light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, @@ -1841,6 +1802,9 @@ void main() { diffuse_light, specular_light); } } //spot lights +#endif // !VERTEX_LIGHTING + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifdef USE_SHADOW_TO_OPACITY #ifndef MODE_RENDER_DEPTH @@ -1855,8 +1819,6 @@ void main() { #endif // !MODE_RENDER_DEPTH #endif // USE_SHADOW_TO_OPACITY -#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - #ifdef MODE_RENDER_DEPTH #ifdef MODE_RENDER_MATERIAL diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl new file mode 100644 index 0000000000..e962c8f7f3 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl @@ -0,0 +1,82 @@ +// Simplified versions of light functions intended for the vertex shader. + +// Eyeballed approximation of `exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25`. +// Uses slightly more FMA instructions (2x rate) to avoid special instructions (0.25x rate). +// Range is reduced to [0.64,4977] from [068,2,221,528] which makes mediump feasible for the rest of the shader. +mediump float roughness_to_shininess(mediump float roughness) { + mediump float r = 1.2 - roughness; + mediump float r2 = r * r; + return r * r2 * r2 * 2000.0; +} + +void light_compute_vertex(vec3 N, vec3 L, vec3 V, vec3 light_color, bool is_directional, float roughness, + inout vec3 diffuse_light, inout vec3 specular_light) { + float NdotL = min(dot(N, L), 1.0); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + +#if defined(DIFFUSE_LAMBERT_WRAP) + // Energy conserving lambert wrap shader. + // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/ + float diffuse_brdf_NL = max(0.0, (cNdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI); +#else + // lambert + float diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + diffuse_light += light_color * diffuse_brdf_NL; + +#if !defined(SPECULAR_DISABLED) + float specular_brdf_NL = 0.0; + // Normalized blinn always unless disabled. + vec3 H = normalize(V + L); + float cNdotH = clamp(dot(N, H), 0.0, 1.0); + float shininess = roughness_to_shininess(roughness); + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)) * cNdotL; + specular_brdf_NL = blinn; + specular_light += specular_brdf_NL * light_color; +#endif +} + +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + +void light_process_omni_vertex(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, + inout vec3 diffuse_light, inout vec3 specular_light) { + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); + vec3 color = omni_lights.data[idx].color * omni_attenuation; + + light_compute_vertex(normal, normalize(light_rel_vec), eye_vec, color, false, roughness, + diffuse_light, + specular_light); +} + +void light_process_spot_vertex(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, + inout vec3 diffuse_light, + inout vec3 specular_light) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); + vec3 spot_dir = spot_lights.data[idx].direction; + + // This conversion to a highp float is crucial to prevent light leaking + // due to precision errors in the following calculations (cone angle is mediump). + highp float cone_angle = spot_lights.data[idx].cone_angle; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle)); + + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); + vec3 color = spot_lights.data[idx].color * spot_attenuation; + float specular_amount = spot_lights.data[idx].specular_amount; + + light_compute_vertex(normal, normalize(light_rel_vec), eye_vec, color, false, roughness, + diffuse_light, specular_light); +} diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index e5a8dbb9b2..84e8d1d671 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -40,25 +40,12 @@ using namespace RendererRD; /////////////////////////////////////////////////////////////////////////// // TextureStorage::CanvasTexture -void TextureStorage::CanvasTexture::clear_sets() { - if (cleared_cache) { - return; - } - for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { - for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { - for (int k = 0; k < 2; k++) { - if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j][k])) { - RD::get_singleton()->free(uniform_sets[i][j][k]); - uniform_sets[i][j][k] = RID(); - } - } - } - } - cleared_cache = true; +void TextureStorage::CanvasTexture::clear_cache() { + info_cache[0] = CanvasTextureCache(); + info_cache[1] = CanvasTextureCache(); } TextureStorage::CanvasTexture::~CanvasTexture() { - clear_sets(); } /////////////////////////////////////////////////////////////////////////// @@ -612,8 +599,7 @@ void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::Canvas ct->specular = p_texture; } break; } - - ct->clear_sets(); + ct->clear_cache(); } void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { @@ -624,7 +610,6 @@ void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, ct->specular_color.g = p_specular_color.g; ct->specular_color.b = p_specular_color.b; ct->specular_color.a = p_shininess; - ct->clear_sets(); } void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { @@ -632,7 +617,6 @@ void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS: ERR_FAIL_NULL(ct); ct->texture_filter = p_filter; - ct->clear_sets(); } void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { @@ -640,17 +624,14 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS: ERR_FAIL_NULL(ct); ct->texture_repeat = p_repeat; - ct->clear_sets(); } -bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data) { +TextureStorage::CanvasTextureInfo TextureStorage::canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data) { MaterialStorage *material_storage = MaterialStorage::get_singleton(); CanvasTexture *ct = nullptr; Texture *t = get_texture(p_texture); - // TODO once we have our texture storage split off we'll look into moving this code into canvas_texture - if (t) { //regular texture if (!t->canvas_texture) { @@ -667,93 +648,71 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte } if (!ct) { - return false; //invalid texture RID + return CanvasTextureInfo(); //invalid texture RID } RS::CanvasItemTextureFilter filter = ct->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? ct->texture_filter : p_base_filter; - ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, false); + ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasTextureInfo()); RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat; - ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false); + ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, CanvasTextureInfo()); - RID uniform_set = ct->uniform_sets[filter][repeat][int(p_use_srgb)]; - if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //create and update - Vector<RD::Uniform> uniforms; + CanvasTextureCache &ctc = ct->info_cache[int(p_use_srgb)]; + if (!RD::get_singleton()->texture_is_valid(ctc.diffuse) || + !RD::get_singleton()->texture_is_valid(ctc.normal) || + !RD::get_singleton()->texture_is_valid(ctc.specular)) { { //diffuse - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 0; - t = get_texture(ct->diffuse); if (!t) { - u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); + ctc.diffuse = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); ct->size_cache = Size2i(1, 1); } else { - u.append_id(t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture); + ctc.diffuse = t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture; ct->size_cache = Size2i(t->width_2d, t->height_2d); if (t->render_target) { t->render_target->was_used = true; } } - uniforms.push_back(u); } { //normal - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; - t = get_texture(ct->normal_map); if (!t) { - u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL)); + ctc.normal = texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); ct->use_normal_cache = false; } else { - u.append_id(t->rd_texture); + ctc.normal = t->rd_texture; ct->use_normal_cache = true; if (t->render_target) { t->render_target->was_used = true; } } - uniforms.push_back(u); } { //specular - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; - t = get_texture(ct->specular); if (!t) { - u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); + ctc.specular = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); ct->use_specular_cache = false; } else { - u.append_id(t->rd_texture); + ctc.specular = t->rd_texture; ct->use_specular_cache = true; if (t->render_target) { t->render_target->was_used = true; } } - uniforms.push_back(u); } - { //sampler - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 3; - u.append_id(material_storage->sampler_rd_get_default(filter, repeat)); - uniforms.push_back(u); - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set); - ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set; - ct->cleared_cache = false; } - r_uniform_set = uniform_set; - r_size = ct->size_cache; - r_specular_shininess = ct->specular_color; - r_use_normal = ct->use_normal_cache; - r_use_specular = ct->use_specular_cache; + CanvasTextureInfo res; + res.diffuse = ctc.diffuse; + res.normal = ctc.normal; + res.specular = ctc.specular; + res.sampler = material_storage->sampler_rd_get_default(filter, repeat); + res.size = ct->size_cache; + res.specular_color = ct->specular_color; + res.use_normal = ct->use_normal_cache; + res.use_specular = ct->use_specular_cache; - return true; + return res; } /* Texture API */ diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 9de4ff7b6b..8aecc78f07 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -76,6 +76,21 @@ public: TYPE_3D }; + struct CanvasTextureInfo { + RID diffuse; + RID normal; + RID specular; + RID sampler; + Size2i size; + Color specular_color; + + bool use_normal = false; + bool use_specular = false; + + _FORCE_INLINE_ bool is_valid() const { return diffuse.is_valid(); } + _FORCE_INLINE_ bool is_null() const { return diffuse.is_null(); } + }; + private: friend class LightStorage; friend class MaterialStorage; @@ -86,6 +101,12 @@ private: /* Canvas Texture API */ + struct CanvasTextureCache { + RID diffuse = RID(); + RID normal = RID(); + RID specular = RID(); + }; + class CanvasTexture { public: RID diffuse; @@ -96,14 +117,14 @@ private: RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; - RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX][2]; + CanvasTextureCache info_cache[2]; Size2i size_cache = Size2i(1, 1); bool use_normal_cache = false; bool use_specular_cache = false; bool cleared_cache = true; - void clear_sets(); + void clear_cache(); ~CanvasTexture(); }; @@ -477,7 +498,7 @@ public: virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override; virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override; - bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data); + CanvasTextureInfo canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data); /* Texture API */ diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 0ad56961c0..5c85080298 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3580,8 +3580,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/global_illumination/voxel_gi/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)"), 0); - GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false); - GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true); + GLOBAL_DEF_RST("rendering/shading/overrides/force_vertex_shading", false); GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false); GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true); diff --git a/thirdparty/README.md b/thirdparty/README.md index b3de256405..a219839afc 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -650,6 +650,10 @@ comments and a patch is provided in the `patches` folder. Collection of single-file libraries used in Godot components. +- `bcdec.h` + * Upstream: https://github.com/iOrange/bcdec + * Version: git (026acf98ea271045cb10713daa96ba98528badb7, 2022) + * License: MIT - `clipper.{cpp,hpp}` * Upstream: https://sourceforge.net/projects/polyclipping * Version: 6.4.2 (2017) + Godot changes (added optional exceptions handling) @@ -873,23 +877,6 @@ They can be reapplied using the patches included in the `patches` folder, in order. -## squish - -- Upstream: https://sourceforge.net/projects/libsquish -- Version: 1.15 (r104, 2017) -- License: MIT - -Files extracted from upstream source: - -- `LICENSE.txt` -- All `.cpp`, `.h` and `.inl` files - -Some downstream changes have been made and are identified by -`// -- GODOT begin --` and `// -- GODOT end --` comments. -They can be reapplied using the patches included in the `patches` -folder. - - ## tinyexr - Upstream: https://github.com/syoyo/tinyexr diff --git a/thirdparty/misc/bcdec.h b/thirdparty/misc/bcdec.h new file mode 100644 index 0000000000..78074a0c90 --- /dev/null +++ b/thirdparty/misc/bcdec.h @@ -0,0 +1,1329 @@ +/* bcdec.h - v0.96 + provides functions to decompress blocks of BC compressed images + written by Sergii "iOrange" Kudlai in 2022 + + This library does not allocate memory and is trying to use as less stack as possible + + The library was never optimized specifically for speed but for the overall size + it has zero external dependencies and is not using any runtime functions + + Supported BC formats: + BC1 (also known as DXT1) + it's "binary alpha" variant BC1A (DXT1A) + BC2 (also known as DXT3) + BC3 (also known as DXT5) + BC4 (also known as ATI1N) + BC5 (also known as ATI2N) + BC6H (HDR format) + BC7 + + BC1/BC2/BC3/BC7 are expected to decompress into 4*4 RGBA blocks 8bit per component (32bit pixel) + BC4/BC5 are expected to decompress into 4*4 R/RG blocks 8bit per component (8bit and 16bit pixel) + BC6H is expected to decompress into 4*4 RGB blocks of either 32bit float or 16bit "half" per + component (96bit or 48bit pixel) + + For more info, issues and suggestions please visit https://github.com/iOrange/bcdec + + CREDITS: + Aras Pranckevicius (@aras-p) - BC1/BC3 decoders optimizations (up to 3x the speed) + - BC6H/BC7 bits pulling routines optimizations + - optimized BC6H by moving unquantize out of the loop + - Split BC6H decompression function into 'half' and + 'float' variants + + bugfixes: + @linkmauve + + LICENSE: See end of file for license information. +*/ + +#ifndef BCDEC_HEADER_INCLUDED +#define BCDEC_HEADER_INCLUDED + +/* if BCDEC_STATIC causes problems, try defining BCDECDEF to 'inline' or 'static inline' */ +#ifndef BCDECDEF +#ifdef BCDEC_STATIC +#define BCDECDEF static +#else +#ifdef __cplusplus +#define BCDECDEF extern "C" +#else +#define BCDECDEF extern +#endif +#endif +#endif + +/* Used information sources: + https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression + https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc6h-format + https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format + https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format-mode-reference + + ! WARNING ! Khronos's BPTC partitions tables contain mistakes, do not use them! + https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#BPTC + + ! Use tables from here instead ! + https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt + + Leaving it here as it's a nice read + https://fgiesen.wordpress.com/2021/10/04/gpu-bcn-decoding/ + + Fast half to float function from here + https://gist.github.com/rygorous/2144712 +*/ + +#define BCDEC_BC1_BLOCK_SIZE 8 +#define BCDEC_BC2_BLOCK_SIZE 16 +#define BCDEC_BC3_BLOCK_SIZE 16 +#define BCDEC_BC4_BLOCK_SIZE 8 +#define BCDEC_BC5_BLOCK_SIZE 16 +#define BCDEC_BC6H_BLOCK_SIZE 16 +#define BCDEC_BC7_BLOCK_SIZE 16 + +#define BCDEC_BC1_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC1_BLOCK_SIZE) +#define BCDEC_BC2_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC2_BLOCK_SIZE) +#define BCDEC_BC3_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC3_BLOCK_SIZE) +#define BCDEC_BC4_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC4_BLOCK_SIZE) +#define BCDEC_BC5_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC5_BLOCK_SIZE) +#define BCDEC_BC6H_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC6H_BLOCK_SIZE) +#define BCDEC_BC7_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC7_BLOCK_SIZE) + +BCDECDEF void bcdec_bc1(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc2(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc6h_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned); +BCDECDEF void bcdec_bc6h_half(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned); +BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, int destinationPitch); + + +#ifdef BCDEC_IMPLEMENTATION + +static void bcdec__color_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode) { + unsigned short c0, c1; + unsigned int refColors[4]; /* 0xAABBGGRR */ + unsigned char* dstColors; + unsigned int colorIndices; + int i, j, idx; + unsigned int r0, g0, b0, r1, g1, b1, r, g, b; + + c0 = ((unsigned short*)compressedBlock)[0]; + c1 = ((unsigned short*)compressedBlock)[1]; + + /* Expand 565 ref colors to 888 */ + r0 = (((c0 >> 11) & 0x1F) * 527 + 23) >> 6; + g0 = (((c0 >> 5) & 0x3F) * 259 + 33) >> 6; + b0 = ((c0 & 0x1F) * 527 + 23) >> 6; + refColors[0] = 0xFF000000 | (b0 << 16) | (g0 << 8) | r0; + + r1 = (((c1 >> 11) & 0x1F) * 527 + 23) >> 6; + g1 = (((c1 >> 5) & 0x3F) * 259 + 33) >> 6; + b1 = ((c1 & 0x1F) * 527 + 23) >> 6; + refColors[1] = 0xFF000000 | (b1 << 16) | (g1 << 8) | r1; + + if (c0 > c1 || onlyOpaqueMode) { /* Standard BC1 mode (also BC3 color block uses ONLY this mode) */ + /* color_2 = 2/3*color_0 + 1/3*color_1 + color_3 = 1/3*color_0 + 2/3*color_1 */ + r = (2 * r0 + r1 + 1) / 3; + g = (2 * g0 + g1 + 1) / 3; + b = (2 * b0 + b1 + 1) / 3; + refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r; + + r = (r0 + 2 * r1 + 1) / 3; + g = (g0 + 2 * g1 + 1) / 3; + b = (b0 + 2 * b1 + 1) / 3; + refColors[3] = 0xFF000000 | (b << 16) | (g << 8) | r; + } else { /* Quite rare BC1A mode */ + /* color_2 = 1/2*color_0 + 1/2*color_1; + color_3 = 0; */ + r = (r0 + r1 + 1) >> 1; + g = (g0 + g1 + 1) >> 1; + b = (b0 + b1 + 1) >> 1; + refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r; + + refColors[3] = 0x00000000; + } + + colorIndices = ((unsigned int*)compressedBlock)[1]; + + /* Fill out the decompressed color block */ + dstColors = (unsigned char*)decompressedBlock; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + idx = colorIndices & 0x03; + ((unsigned int*)dstColors)[j] = refColors[idx]; + colorIndices >>= 2; + } + + dstColors += destinationPitch; + } +} + +static void bcdec__sharp_alpha_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + unsigned short* alpha; + unsigned char* decompressed; + int i, j; + + alpha = (unsigned short*)compressedBlock; + decompressed = (unsigned char*)decompressedBlock; + + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 4] = ((alpha[i] >> (4 * j)) & 0x0F) * 17; + } + + decompressed += destinationPitch; + } +} + +static void bcdec__smooth_alpha_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int pixelSize) { + unsigned char* decompressed; + unsigned char alpha[8]; + int i, j; + unsigned long long block, indices; + + block = *(unsigned long long*)compressedBlock; + decompressed = (unsigned char*)decompressedBlock; + + alpha[0] = block & 0xFF; + alpha[1] = (block >> 8) & 0xFF; + + if (alpha[0] > alpha[1]) { + /* 6 interpolated alpha values. */ + alpha[2] = (6 * alpha[0] + alpha[1] + 1) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */ + alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 1) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */ + alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 1) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */ + alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 1) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */ + alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 1) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */ + alpha[7] = ( alpha[0] + 6 * alpha[1] + 1) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */ + } + else { + /* 4 interpolated alpha values. */ + alpha[2] = (4 * alpha[0] + alpha[1] + 1) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */ + alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 1) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */ + alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 1) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */ + alpha[5] = ( alpha[0] + 4 * alpha[1] + 1) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */ + alpha[6] = 0x00; + alpha[7] = 0xFF; + } + + indices = block >> 16; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * pixelSize] = alpha[indices & 0x07]; + indices >>= 3; + } + + decompressed += destinationPitch; + } +} + +typedef struct bcdec__bitstream { + unsigned long long low; + unsigned long long high; +} bcdec__bitstream_t; + +static int bcdec__bitstream_read_bits(bcdec__bitstream_t* bstream, int numBits) { + unsigned int mask = (1 << numBits) - 1; + /* Read the low N bits */ + unsigned int bits = (bstream->low & mask); + + bstream->low >>= numBits; + /* Put the low N bits of "high" into the high 64-N bits of "low". */ + bstream->low |= (bstream->high & mask) << (sizeof(bstream->high) * 8 - numBits); + bstream->high >>= numBits; + + return bits; +} + +static int bcdec__bitstream_read_bit(bcdec__bitstream_t* bstream) { + return bcdec__bitstream_read_bits(bstream, 1); +} + +/* reversed bits pulling, used in BC6H decoding + why ?? just why ??? */ +static int bcdec__bitstream_read_bits_r(bcdec__bitstream_t* bstream, int numBits) { + int bits = bcdec__bitstream_read_bits(bstream, numBits); + /* Reverse the bits. */ + int result = 0; + while (numBits--) { + result <<= 1; + result |= (bits & 1); + bits >>= 1; + } + return result; +} + + + +BCDECDEF void bcdec_bc1(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__color_block(compressedBlock, decompressedBlock, destinationPitch, 0); +} + +BCDECDEF void bcdec_bc2(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__color_block(((char*)compressedBlock) + 8, decompressedBlock, destinationPitch, 1); + bcdec__sharp_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch); +} + +BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__color_block(((char*)compressedBlock) + 8, decompressedBlock, destinationPitch, 1); + bcdec__smooth_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch, 4); +} + +BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 1); +} + +BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 2); + bcdec__smooth_alpha_block(((char*)compressedBlock) + 8, ((char*)decompressedBlock) + 1, destinationPitch, 2); +} + +/* http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend */ +static int bcdec__extend_sign(int val, int bits) { + return (val << (32 - bits)) >> (32 - bits); +} + +static int bcdec__transform_inverse(int val, int a0, int bits, int isSigned) { + /* If the precision of A0 is "p" bits, then the transform algorithm is: + B0 = (B0 + A0) & ((1 << p) - 1) */ + val = (val + a0) & ((1 << bits) - 1); + if (isSigned) { + val = bcdec__extend_sign(val, bits); + } + return val; +} + +/* pretty much copy-paste from documentation */ +static int bcdec__unquantize(int val, int bits, int isSigned) { + int unq, s = 0; + + if (!isSigned) { + if (bits >= 15) { + unq = val; + } else if (!val) { + unq = 0; + } else if (val == ((1 << bits) - 1)) { + unq = 0xFFFF; + } else { + unq = ((val << 16) + 0x8000) >> bits; + } + } else { + if (bits >= 16) { + unq = val; + } else { + if (val < 0) { + s = 1; + val = -val; + } + + if (val == 0) { + unq = 0; + } else if (val >= ((1 << (bits - 1)) - 1)) { + unq = 0x7FFF; + } else { + unq = ((val << 15) + 0x4000) >> (bits - 1); + } + + if (s) { + unq = -unq; + } + } + } + return unq; +} + +static int bcdec__interpolate(int a, int b, int* weights, int index) { + return (a * (64 - weights[index]) + b * weights[index] + 32) >> 6; +} + +static unsigned short bcdec__finish_unquantize(int val, int isSigned) { + int s; + + if (!isSigned) { + return (unsigned short)((val * 31) >> 6); /* scale the magnitude by 31 / 64 */ + } else { + val = (val < 0) ? -(((-val) * 31) >> 5) : (val * 31) >> 5; /* scale the magnitude by 31 / 32 */ + s = 0; + if (val < 0) { + s = 0x8000; + val = -val; + } + return (unsigned short)(s | val); + } +} + +/* modified half_to_float_fast4 from https://gist.github.com/rygorous/2144712 */ +static float bcdec__half_to_float_quick(unsigned short half) { + typedef union { + unsigned int u; + float f; + } FP32; + + static const FP32 magic = { 113 << 23 }; + static const unsigned int shifted_exp = 0x7c00 << 13; /* exponent mask after shift */ + FP32 o; + unsigned int exp; + + o.u = (half & 0x7fff) << 13; /* exponent/mantissa bits */ + exp = shifted_exp & o.u; /* just the exponent */ + o.u += (127 - 15) << 23; /* exponent adjust */ + + /* handle exponent special cases */ + if (exp == shifted_exp) { /* Inf/NaN? */ + o.u += (128 - 16) << 23; /* extra exp adjust */ + } else if (exp == 0) { /* Zero/Denormal? */ + o.u += 1 << 23; /* extra exp adjust */ + o.f -= magic.f; /* renormalize */ + } + + o.u |= (half & 0x8000) << 16; /* sign bit */ + return o.f; +} + +BCDECDEF void bcdec_bc6h_half(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) { + static char actual_bits_count[4][14] = { + { 10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16 }, /* W */ + { 5, 6, 5, 4, 4, 5, 6, 5, 5, 6, 10, 9, 8, 4 }, /* dR */ + { 5, 6, 4, 5, 4, 5, 5, 6, 5, 6, 10, 9, 8, 4 }, /* dG */ + { 5, 6, 4, 4, 5, 5, 5, 5, 6, 6, 10, 9, 8, 4 } /* dB */ + }; + + /* There are 32 possible partition sets for a two-region tile. + Each 4x4 block represents a single shape. + Here also every fix-up index has MSB bit set. */ + static unsigned char partition_sets[32][4][4] = { + { {128, 0, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} }, /* 0 */ + { {128, 0, 0, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 129} }, /* 1 */ + { {128, 1, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {0, 1, 1, 129} }, /* 2 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 3 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 4 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 5 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 6 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 7 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 8 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 9 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 10 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 1, 1, 129} }, /* 11 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 12 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 13 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 14 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, {1, 1, 1, 129} }, /* 15 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {1, 1, 1, 129} }, /* 16 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 17 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 1, 0} }, /* 18 */ + { {128, 1, 129, 1}, {0, 0, 1, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 19 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 20 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 1, 0, 0}, {1, 1, 1, 0} }, /* 21 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 22 */ + { {128, 1, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 0, 129} }, /* 23 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 24 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 25 */ + { {128, 1, 129, 0}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {0, 1, 1, 0} }, /* 26 */ + { {128, 0, 129, 1}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {1, 1, 0, 0} }, /* 27 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, {129, 1, 1, 0}, {1, 0, 0, 0} }, /* 28 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, {0, 0, 0, 0} }, /* 29 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 1, 0, 0, 0}, {1, 1, 1, 0} }, /* 30 */ + { {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} } /* 31 */ + }; + + static int aWeight3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 }; + static int aWeight4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; + + bcdec__bitstream_t bstream; + int mode, partition, numPartitions, i, j, partitionSet, indexBits, index, ep_i, actualBits0Mode; + int r[4], g[4], b[4]; /* wxyz */ + unsigned short* decompressed; + int* weights; + + decompressed = (unsigned short*)decompressedBlock; + + bstream.low = ((unsigned long long*)compressedBlock)[0]; + bstream.high = ((unsigned long long*)compressedBlock)[1]; + + r[0] = r[1] = r[2] = r[3] = 0; + g[0] = g[1] = g[2] = g[3] = 0; + b[0] = b[1] = b[2] = b[3] = 0; + + mode = bcdec__bitstream_read_bits(&bstream, 2); + if (mode > 1) { + mode |= (bcdec__bitstream_read_bits(&bstream, 3) << 2); + } + + /* modes >= 11 (10 in my code) are using 0 one, others will read it from the bitstream */ + partition = 0; + + switch (mode) { + /* mode 1 */ + case 0b00: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 75 bits (10.555, 10.555, 10.555) */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 0; + } break; + + /* mode 2 */ + case 0b01: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 75 bits (7666, 7666, 7666) */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gy[5] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gz[5] */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 7); /* rw[6:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 7); /* gw[6:0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* by[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 7); /* bw[6:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* bz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* rx[5:0] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* gx[5:0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* bx[5:0] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 6); /* ry[5:0] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 6); /* rz[5:0] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 1; + } break; + + /* mode 3 */ + case 0b00010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (11.555, 11.444, 11.444) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* bx[3:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 2; + } break; + + /* mode 4 */ + case 0b00110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (11.444, 11.555, 11.444) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* rx[3:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* bx[3:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* ry[3:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* rz[3:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 3; + } break; + + /* mode 5 */ + case 0b01010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (11.444, 11.444, 11.555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* rx[3:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* ry[3:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* rz[3:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 4; + } break; + + /* mode 6 */ + case 0b01110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (9555, 9555, 9555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 9); /* rw[8:0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 9); /* gw[8:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 9); /* bw[8:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 5; + } break; + + /* mode 7 */ + case 0b10010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (8666, 8555, 8555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* rw[7:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* gw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* bw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* rx[5:0] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 6); /* ry[5:0] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 6); /* rz[5:0] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 6; + } break; + + /* mode 8 */ + case 0b10110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (8555, 8666, 8555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* rw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* gw[7:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gy[5] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* bw[7:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* gx[5:0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* zx[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 7; + } break; + + /* mode 9 */ + case 0b11010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (8555, 8555, 8666) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* rw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* gw[7:0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* by[5] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* bw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* bz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bw[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* bx[5:0] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 8; + } break; + + /* mode 10 */ + case 0b11110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (6666, 6666, 6666) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 6); /* rw[5:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 6); /* gw[5:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gy[5] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* by[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 6); /* bw[5:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* bz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* rx[5:0] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* gx[5:0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* bx[5:0] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 6); /* ry[5:0] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 6); /* rz[5:0] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 9; + } break; + + /* mode 11 */ + case 0b00011: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (10.10, 10.10, 10.10) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 10); /* rx[9:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 10); /* gx[9:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 10); /* bx[9:0] */ + mode = 10; + } break; + + /* mode 12 */ + case 0b00111: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (11.9, 11.9, 11.9) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 9); /* rx[8:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 9); /* gx[8:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 9); /* bx[8:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + mode = 11; + } break; + + /* mode 13 */ + case 0b01011: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (12.8, 12.8, 12.8) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 8); /* rx[7:0] */ + r[0] |= bcdec__bitstream_read_bits_r(&bstream, 2) << 10;/* rx[10:11] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 8); /* gx[7:0] */ + g[0] |= bcdec__bitstream_read_bits_r(&bstream, 2) << 10;/* gx[10:11] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 8); /* bx[7:0] */ + b[0] |= bcdec__bitstream_read_bits_r(&bstream, 2) << 10;/* bx[10:11] */ + mode = 12; + } break; + + /* mode 14 */ + case 0b01111: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (16.4, 16.4, 16.4) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* rx[3:0] */ + r[0] |= bcdec__bitstream_read_bits_r(&bstream, 6) << 10;/* rw[10:15] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + g[0] |= bcdec__bitstream_read_bits_r(&bstream, 6) << 10;/* gw[10:15] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* bx[3:0] */ + b[0] |= bcdec__bitstream_read_bits_r(&bstream, 6) << 10;/* bw[10:15] */ + mode = 13; + } break; + + default: { + /* Modes 10011, 10111, 11011, and 11111 (not shown) are reserved. + Do not use these in your encoder. If the hardware is passed blocks + with one of these modes specified, the resulting decompressed block + must contain all zeroes in all channels except for the alpha channel. */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 3 + 0] = 0; + decompressed[j * 3 + 1] = 0; + decompressed[j * 3 + 2] = 0; + } + decompressed += destinationPitch; + } + + return; + } + } + + numPartitions = (mode >= 10) ? 0 : 1; + + actualBits0Mode = actual_bits_count[0][mode]; + if (isSigned) { + r[0] = bcdec__extend_sign(r[0], actualBits0Mode); + g[0] = bcdec__extend_sign(g[0], actualBits0Mode); + b[0] = bcdec__extend_sign(b[0], actualBits0Mode); + } + + /* Mode 11 (like Mode 10) does not use delta compression, + and instead stores both color endpoints explicitly. */ + if ((mode != 9 && mode != 10) || isSigned) { + for (i = 1; i < (numPartitions + 1) * 2; ++i) { + r[i] = bcdec__extend_sign(r[i], actual_bits_count[1][mode]); + g[i] = bcdec__extend_sign(g[i], actual_bits_count[2][mode]); + b[i] = bcdec__extend_sign(b[i], actual_bits_count[3][mode]); + } + } + + if (mode != 9 && mode != 10) { + for (i = 1; i < (numPartitions + 1) * 2; ++i) { + r[i] = bcdec__transform_inverse(r[i], r[0], actualBits0Mode, isSigned); + g[i] = bcdec__transform_inverse(g[i], g[0], actualBits0Mode, isSigned); + b[i] = bcdec__transform_inverse(b[i], b[0], actualBits0Mode, isSigned); + } + } + + for (i = 0; i < (numPartitions + 1) * 2; ++i) { + r[i] = bcdec__unquantize(r[i], actualBits0Mode, isSigned); + g[i] = bcdec__unquantize(g[i], actualBits0Mode, isSigned); + b[i] = bcdec__unquantize(b[i], actualBits0Mode, isSigned); + } + + weights = (mode >= 10) ? aWeight4 : aWeight3; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + partitionSet = (mode >= 10) ? ((i|j) ? 0 : 128) : partition_sets[partition][i][j]; + + indexBits = (mode >= 10) ? 4 : 3; + /* fix-up index is specified with one less bit */ + /* The fix-up index for subset 0 is always index 0 */ + if (partitionSet & 0x80) { + indexBits--; + } + partitionSet &= 0x01; + + index = bcdec__bitstream_read_bits(&bstream, indexBits); + + ep_i = partitionSet * 2; + decompressed[j * 3 + 0] = bcdec__finish_unquantize( + bcdec__interpolate(r[ep_i], r[ep_i+1], weights, index), isSigned); + decompressed[j * 3 + 1] = bcdec__finish_unquantize( + bcdec__interpolate(g[ep_i], g[ep_i+1], weights, index), isSigned); + decompressed[j * 3 + 2] = bcdec__finish_unquantize( + bcdec__interpolate(b[ep_i], b[ep_i+1], weights, index), isSigned); + } + + decompressed += destinationPitch; + } +} + +BCDECDEF void bcdec_bc6h_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) { + unsigned short block[16*3]; + float* decompressed; + const unsigned short* b; + int i, j; + + bcdec_bc6h_half(compressedBlock, block, 4*3, isSigned); + b = block; + decompressed = (float*)decompressedBlock; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 3 + 0] = bcdec__half_to_float_quick(*b++); + decompressed[j * 3 + 1] = bcdec__half_to_float_quick(*b++); + decompressed[j * 3 + 2] = bcdec__half_to_float_quick(*b++); + } + decompressed += destinationPitch; + } +} + +static void bcdec__swap_values(int* a, int* b) { + a[0] ^= b[0], b[0] ^= a[0], a[0] ^= b[0]; +} + +BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + static char actual_bits_count[2][8] = { + { 4, 6, 5, 7, 5, 7, 7, 5 }, /* RGBA */ + { 0, 0, 0, 0, 6, 8, 7, 5 }, /* Alpha */ + }; + + /* There are 64 possible partition sets for a two-region tile. + Each 4x4 block represents a single shape. + Here also every fix-up index has MSB bit set. */ + static unsigned char partition_sets[2][64][4][4] = { + { /* Partition table for 2-subset BPTC */ + { {128, 0, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} }, /* 0 */ + { {128, 0, 0, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 129} }, /* 1 */ + { {128, 1, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {0, 1, 1, 129} }, /* 2 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 3 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 4 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 5 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 6 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 7 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 8 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 9 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 10 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 1, 1, 129} }, /* 11 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 12 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 13 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 14 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, {1, 1, 1, 129} }, /* 15 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {1, 1, 1, 129} }, /* 16 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 17 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 1, 0} }, /* 18 */ + { {128, 1, 129, 1}, {0, 0, 1, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 19 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 20 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 1, 0, 0}, {1, 1, 1, 0} }, /* 21 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 22 */ + { {128, 1, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 0, 129} }, /* 23 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 24 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 25 */ + { {128, 1, 129, 0}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {0, 1, 1, 0} }, /* 26 */ + { {128, 0, 129, 1}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {1, 1, 0, 0} }, /* 27 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, {129, 1, 1, 0}, {1, 0, 0, 0} }, /* 28 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, {0, 0, 0, 0} }, /* 29 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 1, 0, 0, 0}, {1, 1, 1, 0} }, /* 30 */ + { {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} }, /* 31 */ + { {128, 1, 0, 1}, {0, 1, 0, 1}, { 0, 1, 0, 1}, {0, 1, 0, 129} }, /* 32 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 0, 0, 0, 0}, {1, 1, 1, 129} }, /* 33 */ + { {128, 1, 0, 1}, {1, 0, 129, 0}, { 0, 1, 0, 1}, {1, 0, 1, 0} }, /* 34 */ + { {128, 0, 1, 1}, {0, 0, 1, 1}, {129, 1, 0, 0}, {1, 1, 0, 0} }, /* 35 */ + { {128, 0, 129, 1}, {1, 1, 0, 0}, { 0, 0, 1, 1}, {1, 1, 0, 0} }, /* 36 */ + { {128, 1, 0, 1}, {0, 1, 0, 1}, {129, 0, 1, 0}, {1, 0, 1, 0} }, /* 37 */ + { {128, 1, 1, 0}, {1, 0, 0, 1}, { 0, 1, 1, 0}, {1, 0, 0, 129} }, /* 38 */ + { {128, 1, 0, 1}, {1, 0, 1, 0}, { 1, 0, 1, 0}, {0, 1, 0, 129} }, /* 39 */ + { {128, 1, 129, 1}, {0, 0, 1, 1}, { 1, 1, 0, 0}, {1, 1, 1, 0} }, /* 40 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, {129, 1, 0, 0}, {1, 0, 0, 0} }, /* 41 */ + { {128, 0, 129, 1}, {0, 0, 1, 0}, { 0, 1, 0, 0}, {1, 1, 0, 0} }, /* 42 */ + { {128, 0, 129, 1}, {1, 0, 1, 1}, { 1, 1, 0, 1}, {1, 1, 0, 0} }, /* 43 */ + { {128, 1, 129, 0}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {0, 1, 1, 0} }, /* 44 */ + { {128, 0, 1, 1}, {1, 1, 0, 0}, { 1, 1, 0, 0}, {0, 0, 1, 129} }, /* 45 */ + { {128, 1, 1, 0}, {0, 1, 1, 0}, { 1, 0, 0, 1}, {1, 0, 0, 129} }, /* 46 */ + { {128, 0, 0, 0}, {0, 1, 129, 0}, { 0, 1, 1, 0}, {0, 0, 0, 0} }, /* 47 */ + { {128, 1, 0, 0}, {1, 1, 129, 0}, { 0, 1, 0, 0}, {0, 0, 0, 0} }, /* 48 */ + { {128, 0, 129, 0}, {0, 1, 1, 1}, { 0, 0, 1, 0}, {0, 0, 0, 0} }, /* 49 */ + { {128, 0, 0, 0}, {0, 0, 129, 0}, { 0, 1, 1, 1}, {0, 0, 1, 0} }, /* 50 */ + { {128, 0, 0, 0}, {0, 1, 0, 0}, {129, 1, 1, 0}, {0, 1, 0, 0} }, /* 51 */ + { {128, 1, 1, 0}, {1, 1, 0, 0}, { 1, 0, 0, 1}, {0, 0, 1, 129} }, /* 52 */ + { {128, 0, 1, 1}, {0, 1, 1, 0}, { 1, 1, 0, 0}, {1, 0, 0, 129} }, /* 53 */ + { {128, 1, 129, 0}, {0, 0, 1, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} }, /* 54 */ + { {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 1, 0, 0}, {0, 1, 1, 0} }, /* 55 */ + { {128, 1, 1, 0}, {1, 1, 0, 0}, { 1, 1, 0, 0}, {1, 0, 0, 129} }, /* 56 */ + { {128, 1, 1, 0}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {1, 0, 0, 129} }, /* 57 */ + { {128, 1, 1, 1}, {1, 1, 1, 0}, { 1, 0, 0, 0}, {0, 0, 0, 129} }, /* 58 */ + { {128, 0, 0, 1}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {0, 1, 1, 129} }, /* 59 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} }, /* 60 */ + { {128, 0, 129, 1}, {0, 0, 1, 1}, { 1, 1, 1, 1}, {0, 0, 0, 0} }, /* 61 */ + { {128, 0, 129, 0}, {0, 0, 1, 0}, { 1, 1, 1, 0}, {1, 1, 1, 0} }, /* 62 */ + { {128, 1, 0, 0}, {0, 1, 0, 0}, { 0, 1, 1, 1}, {0, 1, 1, 129} } /* 63 */ + }, + { /* Partition table for 3-subset BPTC */ + { {128, 0, 1, 129}, {0, 0, 1, 1}, { 0, 2, 2, 1}, { 2, 2, 2, 130} }, /* 0 */ + { {128, 0, 0, 129}, {0, 0, 1, 1}, {130, 2, 1, 1}, { 2, 2, 2, 1} }, /* 1 */ + { {128, 0, 0, 0}, {2, 0, 0, 1}, {130, 2, 1, 1}, { 2, 2, 1, 129} }, /* 2 */ + { {128, 2, 2, 130}, {0, 0, 2, 2}, { 0, 0, 1, 1}, { 0, 1, 1, 129} }, /* 3 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 1, 2, 2}, { 1, 1, 2, 130} }, /* 4 */ + { {128, 0, 1, 129}, {0, 0, 1, 1}, { 0, 0, 2, 2}, { 0, 0, 2, 130} }, /* 5 */ + { {128, 0, 2, 130}, {0, 0, 2, 2}, { 1, 1, 1, 1}, { 1, 1, 1, 129} }, /* 6 */ + { {128, 0, 1, 1}, {0, 0, 1, 1}, {130, 2, 1, 1}, { 2, 2, 1, 129} }, /* 7 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 1, 1, 1}, { 2, 2, 2, 130} }, /* 8 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, { 2, 2, 2, 130} }, /* 9 */ + { {128, 0, 0, 0}, {1, 1, 129, 1}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 10 */ + { {128, 0, 1, 2}, {0, 0, 129, 2}, { 0, 0, 1, 2}, { 0, 0, 1, 130} }, /* 11 */ + { {128, 1, 1, 2}, {0, 1, 129, 2}, { 0, 1, 1, 2}, { 0, 1, 1, 130} }, /* 12 */ + { {128, 1, 2, 2}, {0, 129, 2, 2}, { 0, 1, 2, 2}, { 0, 1, 2, 130} }, /* 13 */ + { {128, 0, 1, 129}, {0, 1, 1, 2}, { 1, 1, 2, 2}, { 1, 2, 2, 130} }, /* 14 */ + { {128, 0, 1, 129}, {2, 0, 0, 1}, {130, 2, 0, 0}, { 2, 2, 2, 0} }, /* 15 */ + { {128, 0, 0, 129}, {0, 0, 1, 1}, { 0, 1, 1, 2}, { 1, 1, 2, 130} }, /* 16 */ + { {128, 1, 1, 129}, {0, 0, 1, 1}, {130, 0, 0, 1}, { 2, 2, 0, 0} }, /* 17 */ + { {128, 0, 0, 0}, {1, 1, 2, 2}, {129, 1, 2, 2}, { 1, 1, 2, 130} }, /* 18 */ + { {128, 0, 2, 130}, {0, 0, 2, 2}, { 0, 0, 2, 2}, { 1, 1, 1, 129} }, /* 19 */ + { {128, 1, 1, 129}, {0, 1, 1, 1}, { 0, 2, 2, 2}, { 0, 2, 2, 130} }, /* 20 */ + { {128, 0, 0, 129}, {0, 0, 0, 1}, {130, 2, 2, 1}, { 2, 2, 2, 1} }, /* 21 */ + { {128, 0, 0, 0}, {0, 0, 129, 1}, { 0, 1, 2, 2}, { 0, 1, 2, 130} }, /* 22 */ + { {128, 0, 0, 0}, {1, 1, 0, 0}, {130, 2, 129, 0}, { 2, 2, 1, 0} }, /* 23 */ + { {128, 1, 2, 130}, {0, 129, 2, 2}, { 0, 0, 1, 1}, { 0, 0, 0, 0} }, /* 24 */ + { {128, 0, 1, 2}, {0, 0, 1, 2}, {129, 1, 2, 2}, { 2, 2, 2, 130} }, /* 25 */ + { {128, 1, 1, 0}, {1, 2, 130, 1}, {129, 2, 2, 1}, { 0, 1, 1, 0} }, /* 26 */ + { {128, 0, 0, 0}, {0, 1, 129, 0}, { 1, 2, 130, 1}, { 1, 2, 2, 1} }, /* 27 */ + { {128, 0, 2, 2}, {1, 1, 0, 2}, {129, 1, 0, 2}, { 0, 0, 2, 130} }, /* 28 */ + { {128, 1, 1, 0}, {0, 129, 1, 0}, { 2, 0, 0, 2}, { 2, 2, 2, 130} }, /* 29 */ + { {128, 0, 1, 1}, {0, 1, 2, 2}, { 0, 1, 130, 2}, { 0, 0, 1, 129} }, /* 30 */ + { {128, 0, 0, 0}, {2, 0, 0, 0}, {130, 2, 1, 1}, { 2, 2, 2, 129} }, /* 31 */ + { {128, 0, 0, 0}, {0, 0, 0, 2}, {129, 1, 2, 2}, { 1, 2, 2, 130} }, /* 32 */ + { {128, 2, 2, 130}, {0, 0, 2, 2}, { 0, 0, 1, 2}, { 0, 0, 1, 129} }, /* 33 */ + { {128, 0, 1, 129}, {0, 0, 1, 2}, { 0, 0, 2, 2}, { 0, 2, 2, 130} }, /* 34 */ + { {128, 1, 2, 0}, {0, 129, 2, 0}, { 0, 1, 130, 0}, { 0, 1, 2, 0} }, /* 35 */ + { {128, 0, 0, 0}, {1, 1, 129, 1}, { 2, 2, 130, 2}, { 0, 0, 0, 0} }, /* 36 */ + { {128, 1, 2, 0}, {1, 2, 0, 1}, {130, 0, 129, 2}, { 0, 1, 2, 0} }, /* 37 */ + { {128, 1, 2, 0}, {2, 0, 1, 2}, {129, 130, 0, 1}, { 0, 1, 2, 0} }, /* 38 */ + { {128, 0, 1, 1}, {2, 2, 0, 0}, { 1, 1, 130, 2}, { 0, 0, 1, 129} }, /* 39 */ + { {128, 0, 1, 1}, {1, 1, 130, 2}, { 2, 2, 0, 0}, { 0, 0, 1, 129} }, /* 40 */ + { {128, 1, 0, 129}, {0, 1, 0, 1}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 41 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {130, 1, 2, 1}, { 2, 1, 2, 129} }, /* 42 */ + { {128, 0, 2, 2}, {1, 129, 2, 2}, { 0, 0, 2, 2}, { 1, 1, 2, 130} }, /* 43 */ + { {128, 0, 2, 130}, {0, 0, 1, 1}, { 0, 0, 2, 2}, { 0, 0, 1, 129} }, /* 44 */ + { {128, 2, 2, 0}, {1, 2, 130, 1}, { 0, 2, 2, 0}, { 1, 2, 2, 129} }, /* 45 */ + { {128, 1, 0, 1}, {2, 2, 130, 2}, { 2, 2, 2, 2}, { 0, 1, 0, 129} }, /* 46 */ + { {128, 0, 0, 0}, {2, 1, 2, 1}, {130, 1, 2, 1}, { 2, 1, 2, 129} }, /* 47 */ + { {128, 1, 0, 129}, {0, 1, 0, 1}, { 0, 1, 0, 1}, { 2, 2, 2, 130} }, /* 48 */ + { {128, 2, 2, 130}, {0, 1, 1, 1}, { 0, 2, 2, 2}, { 0, 1, 1, 129} }, /* 49 */ + { {128, 0, 0, 2}, {1, 129, 1, 2}, { 0, 0, 0, 2}, { 1, 1, 1, 130} }, /* 50 */ + { {128, 0, 0, 0}, {2, 129, 1, 2}, { 2, 1, 1, 2}, { 2, 1, 1, 130} }, /* 51 */ + { {128, 2, 2, 2}, {0, 129, 1, 1}, { 0, 1, 1, 1}, { 0, 2, 2, 130} }, /* 52 */ + { {128, 0, 0, 2}, {1, 1, 1, 2}, {129, 1, 1, 2}, { 0, 0, 0, 130} }, /* 53 */ + { {128, 1, 1, 0}, {0, 129, 1, 0}, { 0, 1, 1, 0}, { 2, 2, 2, 130} }, /* 54 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 2, 1, 129, 2}, { 2, 1, 1, 130} }, /* 55 */ + { {128, 1, 1, 0}, {0, 129, 1, 0}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 56 */ + { {128, 0, 2, 2}, {0, 0, 1, 1}, { 0, 0, 129, 1}, { 0, 0, 2, 130} }, /* 57 */ + { {128, 0, 2, 2}, {1, 1, 2, 2}, {129, 1, 2, 2}, { 0, 0, 2, 130} }, /* 58 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, { 2, 129, 1, 130} }, /* 59 */ + { {128, 0, 0, 130}, {0, 0, 0, 1}, { 0, 0, 0, 2}, { 0, 0, 0, 129} }, /* 60 */ + { {128, 2, 2, 2}, {1, 2, 2, 2}, { 0, 2, 2, 2}, {129, 2, 2, 130} }, /* 61 */ + { {128, 1, 0, 129}, {2, 2, 2, 2}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 62 */ + { {128, 1, 1, 129}, {2, 0, 1, 1}, {130, 2, 0, 1}, { 2, 2, 2, 0} } /* 63 */ + } + }; + + static int aWeight2[] = { 0, 21, 43, 64 }; + static int aWeight3[] = { 0, 9, 18, 27, 37, 46, 55, 64 }; + static int aWeight4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; + + static unsigned char sModeHasPBits = 0b11001011; + + bcdec__bitstream_t bstream; + int mode, partition, numPartitions, numEndpoints, i, j, k, rotation, partitionSet; + int indexSelectionBit, indexBits, indexBits2, index, index2; + int endpoints[6][4]; + char indices[4][4]; + int r, g, b, a; + int* weights, * weights2; + unsigned char* decompressed; + + decompressed = (unsigned char*)decompressedBlock; + + bstream.low = ((unsigned long long*)compressedBlock)[0]; + bstream.high = ((unsigned long long*)compressedBlock)[1]; + + for (mode = 0; mode < 8 && (0 == bcdec__bitstream_read_bit(&bstream)); ++mode); + + /* unexpected mode, clear the block (transparent black) */ + if (mode >= 8) { + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 4 + 0] = 0; + decompressed[j * 4 + 1] = 0; + decompressed[j * 4 + 2] = 0; + decompressed[j * 4 + 3] = 0; + } + decompressed += destinationPitch; + } + + return; + } + + partition = 0; + numPartitions = 1; + rotation = 0; + indexSelectionBit = 0; + + if (mode == 0 || mode == 1 || mode == 2 || mode == 3 || mode == 7) { + numPartitions = (mode == 0 || mode == 2) ? 3 : 2; + partition = bcdec__bitstream_read_bits(&bstream, (mode == 0) ? 4 : 6); + } + + numEndpoints = numPartitions * 2; + + if (mode == 4 || mode == 5) { + rotation = bcdec__bitstream_read_bits(&bstream, 2); + + if (mode == 4) { + indexSelectionBit = bcdec__bitstream_read_bit(&bstream); + } + } + + /* Extract endpoints */ + /* RGB */ + for (i = 0; i < 3; ++i) { + for (j = 0; j < numEndpoints; ++j) { + endpoints[j][i] = bcdec__bitstream_read_bits(&bstream, actual_bits_count[0][mode]); + } + } + /* Alpha (if any) */ + if (actual_bits_count[1][mode] > 0) { + for (j = 0; j < numEndpoints; ++j) { + endpoints[j][3] = bcdec__bitstream_read_bits(&bstream, actual_bits_count[1][mode]); + } + } + + /* Fully decode endpoints */ + /* First handle modes that have P-bits */ + if (mode == 0 || mode == 1 || mode == 3 || mode == 6 || mode == 7) { + for (i = 0; i < numEndpoints; ++i) { + /* component-wise left-shift */ + for (j = 0; j < 4; ++j) { + endpoints[i][j] <<= 1; + } + } + + /* if P-bit is shared */ + if (mode == 1) { + i = bcdec__bitstream_read_bit(&bstream); + j = bcdec__bitstream_read_bit(&bstream); + + /* rgb component-wise insert pbits */ + for (k = 0; k < 3; ++k) { + endpoints[0][k] |= i; + endpoints[1][k] |= i; + endpoints[2][k] |= j; + endpoints[3][k] |= j; + } + } else if (sModeHasPBits & (1 << mode)) { + /* unique P-bit per endpoint */ + for (i = 0; i < numEndpoints; ++i) { + j = bcdec__bitstream_read_bit(&bstream); + for (k = 0; k < 4; ++k) { + endpoints[i][k] |= j; + } + } + } + } + + for (i = 0; i < numEndpoints; ++i) { + /* get color components precision including pbit */ + j = actual_bits_count[0][mode] + ((sModeHasPBits >> mode) & 1); + + for (k = 0; k < 3; ++k) { + /* left shift endpoint components so that their MSB lies in bit 7 */ + endpoints[i][k] = endpoints[i][k] << (8 - j); + /* Replicate each component's MSB into the LSBs revealed by the left-shift operation above */ + endpoints[i][k] = endpoints[i][k] | (endpoints[i][k] >> j); + } + + /* get alpha component precision including pbit */ + j = actual_bits_count[1][mode] + ((sModeHasPBits >> mode) & 1); + + /* left shift endpoint components so that their MSB lies in bit 7 */ + endpoints[i][3] = endpoints[i][3] << (8 - j); + /* Replicate each component's MSB into the LSBs revealed by the left-shift operation above */ + endpoints[i][3] = endpoints[i][3] | (endpoints[i][3] >> j); + } + + /* If this mode does not explicitly define the alpha component */ + /* set alpha equal to 1.0 */ + if (!actual_bits_count[1][mode]) { + for (j = 0; j < numEndpoints; ++j) { + endpoints[j][3] = 0xFF; + } + } + + /* Determine weights tables */ + indexBits = (mode == 0 || mode == 1) ? 3 : ((mode == 6) ? 4 : 2); + indexBits2 = (mode == 4) ? 3 : ((mode == 5) ? 2 : 0); + weights = (indexBits == 2) ? aWeight2 : ((indexBits == 3) ? aWeight3 : aWeight4); + weights2 = (indexBits2 == 2) ? aWeight2 : aWeight3; + + /* Quite inconvenient that indices aren't interleaved so we have to make 2 passes here */ + /* Pass #1: collecting color indices */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + partitionSet = (numPartitions == 1) ? ((i | j) ? 0 : 128) : partition_sets[numPartitions - 2][partition][i][j]; + + indexBits = (mode == 0 || mode == 1) ? 3 : ((mode == 6) ? 4 : 2); + /* fix-up index is specified with one less bit */ + /* The fix-up index for subset 0 is always index 0 */ + if (partitionSet & 0x80) { + indexBits--; + } + + indices[i][j] = bcdec__bitstream_read_bits(&bstream, indexBits); + } + } + + /* Pass #2: reading alpha indices (if any) and interpolating & rotating */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + partitionSet = (numPartitions == 1) ? ((i|j) ? 0 : 128) : partition_sets[numPartitions - 2][partition][i][j]; + partitionSet &= 0x03; + + index = indices[i][j]; + + if (!indexBits2) { + r = bcdec__interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights, index); + g = bcdec__interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights, index); + b = bcdec__interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights, index); + a = bcdec__interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights, index); + } else { + index2 = bcdec__bitstream_read_bits(&bstream, (i|j) ? indexBits2 : (indexBits2 - 1)); + /* The index value for interpolating color comes from the secondary index bits for the texel + if the mode has an index selection bit and its value is one, and from the primary index bits otherwise. + The alpha index comes from the secondary index bits if the block has a secondary index and + the block either doesn’t have an index selection bit or that bit is zero, and from the primary index bits otherwise. */ + if (!indexSelectionBit) { + r = bcdec__interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights, index); + g = bcdec__interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights, index); + b = bcdec__interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights, index); + a = bcdec__interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights2, index2); + } else { + r = bcdec__interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights2, index2); + g = bcdec__interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights2, index2); + b = bcdec__interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights2, index2); + a = bcdec__interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights, index); + } + } + + switch (rotation) { + case 1: { /* 01 – Block format is Scalar(R) Vector(AGB) - swap A and R */ + bcdec__swap_values(&a, &r); + } break; + case 2: { /* 10 – Block format is Scalar(G) Vector(RAB) - swap A and G */ + bcdec__swap_values(&a, &g); + } break; + case 3: { /* 11 - Block format is Scalar(B) Vector(RGA) - swap A and B */ + bcdec__swap_values(&a, &b); + } break; + } + + decompressed[j * 4 + 0] = r; + decompressed[j * 4 + 1] = g; + decompressed[j * 4 + 2] = b; + decompressed[j * 4 + 3] = a; + } + + decompressed += destinationPitch; + } +} + +#endif /* BCDEC_IMPLEMENTATION */ + +#endif /* BCDEC_HEADER_INCLUDED */ + +/* LICENSE: + +This software is available under 2 licenses -- choose whichever you prefer. + +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License + +Copyright (c) 2022 Sergii Kudlai + +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. + +------------------------------------------------------------------------------ +ALTERNATIVE B - The Unlicense + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to <https://unlicense.org> + +*/
\ No newline at end of file diff --git a/thirdparty/squish/LICENSE.txt b/thirdparty/squish/LICENSE.txt deleted file mode 100644 index e491e36226..0000000000 --- a/thirdparty/squish/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - -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. diff --git a/thirdparty/squish/alpha.cpp b/thirdparty/squish/alpha.cpp deleted file mode 100644 index 7039c1a3b8..0000000000 --- a/thirdparty/squish/alpha.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 "alpha.h" - -#include <climits> -#include <algorithm> - -namespace squish { - -static int FloatToInt( float a, int limit ) -{ - // use ANSI round-to-zero behaviour to get round-to-nearest - int i = ( int )( a + 0.5f ); - - // clamp to the limit - if( i < 0 ) - i = 0; - else if( i > limit ) - i = limit; - - // done - return i; -} - -void CompressAlphaDxt3( u8 const* rgba, int mask, void* block ) -{ - u8* bytes = reinterpret_cast< u8* >( block ); - - // quantise and pack the alpha values pairwise - for( int i = 0; i < 8; ++i ) - { - // quantise down to 4 bits - float alpha1 = ( float )rgba[8*i + 3] * ( 15.0f/255.0f ); - float alpha2 = ( float )rgba[8*i + 7] * ( 15.0f/255.0f ); - int quant1 = FloatToInt( alpha1, 15 ); - int quant2 = FloatToInt( alpha2, 15 ); - - // set alpha to zero where masked - int bit1 = 1 << ( 2*i ); - int bit2 = 1 << ( 2*i + 1 ); - if( ( mask & bit1 ) == 0 ) - quant1 = 0; - if( ( mask & bit2 ) == 0 ) - quant2 = 0; - - // pack into the byte - bytes[i] = ( u8 )( quant1 | ( quant2 << 4 ) ); - } -} - -void DecompressAlphaDxt3( u8* rgba, void const* block ) -{ - u8 const* bytes = reinterpret_cast< u8 const* >( block ); - - // unpack the alpha values pairwise - for( int i = 0; i < 8; ++i ) - { - // quantise down to 4 bits - u8 quant = bytes[i]; - - // unpack the values - u8 lo = quant & 0x0f; - u8 hi = quant & 0xf0; - - // convert back up to bytes - rgba[8*i + 3] = lo | ( lo << 4 ); - rgba[8*i + 7] = hi | ( hi >> 4 ); - } -} - -static void FixRange( int& min, int& max, int steps ) -{ - if( max - min < steps ) - max = std::min( min + steps, 255 ); - if( max - min < steps ) - min = std::max( 0, max - steps ); -} - -static int FitCodes( u8 const* rgba, int mask, u8 const* codes, u8* indices ) -{ - // fit each alpha value to the codebook - int err = 0; - for( int i = 0; i < 16; ++i ) - { - // check this pixel is valid - int bit = 1 << i; - if( ( mask & bit ) == 0 ) - { - // use the first code - indices[i] = 0; - continue; - } - - // find the least error and corresponding index - int value = rgba[4*i + 3]; - int least = INT_MAX; - int index = 0; - for( int j = 0; j < 8; ++j ) - { - // get the squared error from this code - int dist = ( int )value - ( int )codes[j]; - dist *= dist; - - // compare with the best so far - if( dist < least ) - { - least = dist; - index = j; - } - } - - // save this index and accumulate the error - indices[i] = ( u8 )index; - err += least; - } - - // return the total error - return err; -} - -static void WriteAlphaBlock( int alpha0, int alpha1, u8 const* indices, void* block ) -{ - u8* bytes = reinterpret_cast< u8* >( block ); - - // write the first two bytes - bytes[0] = ( u8 )alpha0; - bytes[1] = ( u8 )alpha1; - - // pack the indices with 3 bits each - u8* dest = bytes + 2; - u8 const* src = indices; - for( int i = 0; i < 2; ++i ) - { - // pack 8 3-bit values - int value = 0; - for( int j = 0; j < 8; ++j ) - { - int index = *src++; - value |= ( index << 3*j ); - } - - // store in 3 bytes - for( int j = 0; j < 3; ++j ) - { - int byte = ( value >> 8*j ) & 0xff; - *dest++ = ( u8 )byte; - } - } -} - -static void WriteAlphaBlock5( int alpha0, int alpha1, u8 const* indices, void* block ) -{ - // check the relative values of the endpoints - if( alpha0 > alpha1 ) - { - // swap the indices - u8 swapped[16]; - for( int i = 0; i < 16; ++i ) - { - u8 index = indices[i]; - if( index == 0 ) - swapped[i] = 1; - else if( index == 1 ) - swapped[i] = 0; - else if( index <= 5 ) - swapped[i] = 7 - index; - else - swapped[i] = index; - } - - // write the block - WriteAlphaBlock( alpha1, alpha0, swapped, block ); - } - else - { - // write the block - WriteAlphaBlock( alpha0, alpha1, indices, block ); - } -} - -static void WriteAlphaBlock7( int alpha0, int alpha1, u8 const* indices, void* block ) -{ - // check the relative values of the endpoints - if( alpha0 < alpha1 ) - { - // swap the indices - u8 swapped[16]; - for( int i = 0; i < 16; ++i ) - { - u8 index = indices[i]; - if( index == 0 ) - swapped[i] = 1; - else if( index == 1 ) - swapped[i] = 0; - else - swapped[i] = 9 - index; - } - - // write the block - WriteAlphaBlock( alpha1, alpha0, swapped, block ); - } - else - { - // write the block - WriteAlphaBlock( alpha0, alpha1, indices, block ); - } -} - -void CompressAlphaDxt5( u8 const* rgba, int mask, void* block ) -{ - // get the range for 5-alpha and 7-alpha interpolation - int min5 = 255; - int max5 = 0; - int min7 = 255; - int max7 = 0; - for( int i = 0; i < 16; ++i ) - { - // check this pixel is valid - int bit = 1 << i; - if( ( mask & bit ) == 0 ) - continue; - - // incorporate into the min/max - int value = rgba[4*i + 3]; - if( value < min7 ) - min7 = value; - if( value > max7 ) - max7 = value; - if( value != 0 && value < min5 ) - min5 = value; - if( value != 255 && value > max5 ) - max5 = value; - } - - // handle the case that no valid range was found - if( min5 > max5 ) - min5 = max5; - if( min7 > max7 ) - min7 = max7; - - // fix the range to be the minimum in each case - FixRange( min5, max5, 5 ); - FixRange( min7, max7, 7 ); - - // set up the 5-alpha code book - u8 codes5[8]; - codes5[0] = ( u8 )min5; - codes5[1] = ( u8 )max5; - for( int i = 1; i < 5; ++i ) - codes5[1 + i] = ( u8 )( ( ( 5 - i )*min5 + i*max5 )/5 ); - codes5[6] = 0; - codes5[7] = 255; - - // set up the 7-alpha code book - u8 codes7[8]; - codes7[0] = ( u8 )min7; - codes7[1] = ( u8 )max7; - for( int i = 1; i < 7; ++i ) - codes7[1 + i] = ( u8 )( ( ( 7 - i )*min7 + i*max7 )/7 ); - - // fit the data to both code books - u8 indices5[16]; - u8 indices7[16]; - int err5 = FitCodes( rgba, mask, codes5, indices5 ); - int err7 = FitCodes( rgba, mask, codes7, indices7 ); - - // save the block with least error - if( err5 <= err7 ) - WriteAlphaBlock5( min5, max5, indices5, block ); - else - WriteAlphaBlock7( min7, max7, indices7, block ); -} - -void DecompressAlphaDxt5( u8* rgba, void const* block ) -{ - // get the two alpha values - u8 const* bytes = reinterpret_cast< u8 const* >( block ); - int alpha0 = bytes[0]; - int alpha1 = bytes[1]; - - // compare the values to build the codebook - u8 codes[8]; - codes[0] = ( u8 )alpha0; - codes[1] = ( u8 )alpha1; - if( alpha0 <= alpha1 ) - { - // use 5-alpha codebook - for( int i = 1; i < 5; ++i ) - codes[1 + i] = ( u8 )( ( ( 5 - i )*alpha0 + i*alpha1 )/5 ); - codes[6] = 0; - codes[7] = 255; - } - else - { - // use 7-alpha codebook - for( int i = 1; i < 7; ++i ) - codes[1 + i] = ( u8 )( ( ( 7 - i )*alpha0 + i*alpha1 )/7 ); - } - - // decode the indices - u8 indices[16]; - u8 const* src = bytes + 2; - u8* dest = indices; - for( int i = 0; i < 2; ++i ) - { - // grab 3 bytes - int value = 0; - for( int j = 0; j < 3; ++j ) - { - int byte = *src++; - value |= ( byte << 8*j ); - } - - // unpack 8 3-bit values from it - for( int j = 0; j < 8; ++j ) - { - int index = ( value >> 3*j ) & 0x7; - *dest++ = ( u8 )index; - } - } - - // write out the indexed codebook values - for( int i = 0; i < 16; ++i ) - rgba[4*i + 3] = codes[indices[i]]; -} - -} // namespace squish diff --git a/thirdparty/squish/alpha.h b/thirdparty/squish/alpha.h deleted file mode 100644 index a1fffd4049..0000000000 --- a/thirdparty/squish/alpha.h +++ /dev/null @@ -1,41 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_ALPHA_H -#define SQUISH_ALPHA_H - -#include "squish.h" - -namespace squish { - -void CompressAlphaDxt3( u8 const* rgba, int mask, void* block ); -void CompressAlphaDxt5( u8 const* rgba, int mask, void* block ); - -void DecompressAlphaDxt3( u8* rgba, void const* block ); -void DecompressAlphaDxt5( u8* rgba, void const* block ); - -} // namespace squish - -#endif // ndef SQUISH_ALPHA_H diff --git a/thirdparty/squish/clusterfit.cpp b/thirdparty/squish/clusterfit.cpp deleted file mode 100644 index 1610ecb5d8..0000000000 --- a/thirdparty/squish/clusterfit.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - Copyright (c) 2007 Ignacio Castano icastano@nvidia.com - - 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 "clusterfit.h" -#include "colourset.h" -#include "colourblock.h" -#include <cfloat> - -namespace squish { - -ClusterFit::ClusterFit( ColourSet const* colours, int flags, float* metric ) - : ColourFit( colours, flags ) -{ - // set the iteration count - m_iterationCount = ( m_flags & kColourIterativeClusterFit ) ? kMaxIterations : 1; - - // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f) - if( metric ) - m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f ); - else - m_metric = VEC4_CONST( 1.0f ); - - // initialise the best error - m_besterror = VEC4_CONST( FLT_MAX ); - - // cache some values - int const count = m_colours->GetCount(); - Vec3 const* values = m_colours->GetPoints(); - - // get the covariance matrix - Sym3x3 covariance = ComputeWeightedCovariance( count, values, m_colours->GetWeights() ); - - // compute the principle component - m_principle = ComputePrincipleComponent( covariance ); -} - -bool ClusterFit::ConstructOrdering( Vec3 const& axis, int iteration ) -{ - // cache some values - int const count = m_colours->GetCount(); - Vec3 const* values = m_colours->GetPoints(); - - // build the list of dot products - float dps[16]; - u8* order = ( u8* )m_order + 16*iteration; - for( int i = 0; i < count; ++i ) - { - dps[i] = Dot( values[i], axis ); - order[i] = ( u8 )i; - } - - // stable sort using them - for( int i = 0; i < count; ++i ) - { - for( int j = i; j > 0 && dps[j] < dps[j - 1]; --j ) - { - std::swap( dps[j], dps[j - 1] ); - std::swap( order[j], order[j - 1] ); - } - } - - // check this ordering is unique - for( int it = 0; it < iteration; ++it ) - { - u8 const* prev = ( u8* )m_order + 16*it; - bool same = true; - for( int i = 0; i < count; ++i ) - { - if( order[i] != prev[i] ) - { - same = false; - break; - } - } - if( same ) - return false; - } - - // copy the ordering and weight all the points - Vec3 const* unweighted = m_colours->GetPoints(); - float const* weights = m_colours->GetWeights(); - m_xsum_wsum = VEC4_CONST( 0.0f ); - for( int i = 0; i < count; ++i ) - { - int j = order[i]; - Vec4 p( unweighted[j].X(), unweighted[j].Y(), unweighted[j].Z(), 1.0f ); - Vec4 w( weights[j] ); - Vec4 x = p*w; - m_points_weights[i] = x; - m_xsum_wsum += x; - } - return true; -} - -void ClusterFit::Compress3( void* block ) -{ - // declare variables - int const count = m_colours->GetCount(); - Vec4 const two = VEC4_CONST( 2.0 ); - Vec4 const one = VEC4_CONST( 1.0f ); - Vec4 const half_half2( 0.5f, 0.5f, 0.5f, 0.25f ); - Vec4 const zero = VEC4_CONST( 0.0f ); - Vec4 const half = VEC4_CONST( 0.5f ); - Vec4 const grid( 31.0f, 63.0f, 31.0f, 0.0f ); - Vec4 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f, 0.0f ); - - // prepare an ordering using the principle axis - ConstructOrdering( m_principle, 0 ); - - // check all possible clusters and iterate on the total order - Vec4 beststart = VEC4_CONST( 0.0f ); - Vec4 bestend = VEC4_CONST( 0.0f ); - Vec4 besterror = m_besterror; - u8 bestindices[16]; - int bestiteration = 0; - int besti = 0, bestj = 0; - - // loop over iterations (we avoid the case that all points in first or last cluster) - for( int iterationIndex = 0;; ) - { - // first cluster [0,i) is at the start - Vec4 part0 = VEC4_CONST( 0.0f ); - for( int i = 0; i < count; ++i ) - { - // second cluster [i,j) is half along - Vec4 part1 = ( i == 0 ) ? m_points_weights[0] : VEC4_CONST( 0.0f ); - int jmin = ( i == 0 ) ? 1 : i; - for( int j = jmin;; ) - { - // last cluster [j,count) is at the end - Vec4 part2 = m_xsum_wsum - part1 - part0; - - // compute least squares terms directly - Vec4 alphax_sum = MultiplyAdd( part1, half_half2, part0 ); - Vec4 alpha2_sum = alphax_sum.SplatW(); - - Vec4 betax_sum = MultiplyAdd( part1, half_half2, part2 ); - Vec4 beta2_sum = betax_sum.SplatW(); - - Vec4 alphabeta_sum = ( part1*half_half2 ).SplatW(); - - // compute the least-squares optimal points - Vec4 factor = Reciprocal( NegativeMultiplySubtract( alphabeta_sum, alphabeta_sum, alpha2_sum*beta2_sum ) ); - Vec4 a = NegativeMultiplySubtract( betax_sum, alphabeta_sum, alphax_sum*beta2_sum )*factor; - Vec4 b = NegativeMultiplySubtract( alphax_sum, alphabeta_sum, betax_sum*alpha2_sum )*factor; - - // clamp to the grid - a = Min( one, Max( zero, a ) ); - b = Min( one, Max( zero, b ) ); - a = Truncate( MultiplyAdd( grid, a, half ) )*gridrcp; - b = Truncate( MultiplyAdd( grid, b, half ) )*gridrcp; - - // compute the error (we skip the constant xxsum) - Vec4 e1 = MultiplyAdd( a*a, alpha2_sum, b*b*beta2_sum ); - Vec4 e2 = NegativeMultiplySubtract( a, alphax_sum, a*b*alphabeta_sum ); - Vec4 e3 = NegativeMultiplySubtract( b, betax_sum, e2 ); - Vec4 e4 = MultiplyAdd( two, e3, e1 ); - - // apply the metric to the error term - Vec4 e5 = e4*m_metric; - Vec4 error = e5.SplatX() + e5.SplatY() + e5.SplatZ(); - - // keep the solution if it wins - if( CompareAnyLessThan( error, besterror ) ) - { - beststart = a; - bestend = b; - besti = i; - bestj = j; - besterror = error; - bestiteration = iterationIndex; - } - - // advance - if( j == count ) - break; - part1 += m_points_weights[j]; - ++j; - } - - // advance - part0 += m_points_weights[i]; - } - - // stop if we didn't improve in this iteration - if( bestiteration != iterationIndex ) - break; - - // advance if possible - ++iterationIndex; - if( iterationIndex == m_iterationCount ) - break; - - // stop if a new iteration is an ordering that has already been tried - Vec3 axis = ( bestend - beststart ).GetVec3(); - if( !ConstructOrdering( axis, iterationIndex ) ) - break; - } - - // save the block if necessary - if( CompareAnyLessThan( besterror, m_besterror ) ) - { - // remap the indices - u8 const* order = ( u8* )m_order + 16*bestiteration; - - u8 unordered[16]; - for( int m = 0; m < besti; ++m ) - unordered[order[m]] = 0; - for( int m = besti; m < bestj; ++m ) - unordered[order[m]] = 2; - for( int m = bestj; m < count; ++m ) - unordered[order[m]] = 1; - - m_colours->RemapIndices( unordered, bestindices ); - - // save the block - WriteColourBlock3( beststart.GetVec3(), bestend.GetVec3(), bestindices, block ); - - // save the error - m_besterror = besterror; - } -} - -void ClusterFit::Compress4( void* block ) -{ - // declare variables - int const count = m_colours->GetCount(); - Vec4 const two = VEC4_CONST( 2.0f ); - Vec4 const one = VEC4_CONST( 1.0f ); - Vec4 const onethird_onethird2( 1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 1.0f/9.0f ); - Vec4 const twothirds_twothirds2( 2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f, 4.0f/9.0f ); - Vec4 const twonineths = VEC4_CONST( 2.0f/9.0f ); - Vec4 const zero = VEC4_CONST( 0.0f ); - Vec4 const half = VEC4_CONST( 0.5f ); - Vec4 const grid( 31.0f, 63.0f, 31.0f, 0.0f ); - Vec4 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f, 0.0f ); - - // prepare an ordering using the principle axis - ConstructOrdering( m_principle, 0 ); - - // check all possible clusters and iterate on the total order - Vec4 beststart = VEC4_CONST( 0.0f ); - Vec4 bestend = VEC4_CONST( 0.0f ); - Vec4 besterror = m_besterror; - u8 bestindices[16]; - int bestiteration = 0; - int besti = 0, bestj = 0, bestk = 0; - - // loop over iterations (we avoid the case that all points in first or last cluster) - for( int iterationIndex = 0;; ) - { - // first cluster [0,i) is at the start - Vec4 part0 = VEC4_CONST( 0.0f ); - for( int i = 0; i < count; ++i ) - { - // second cluster [i,j) is one third along - Vec4 part1 = VEC4_CONST( 0.0f ); - for( int j = i;; ) - { - // third cluster [j,k) is two thirds along - Vec4 part2 = ( j == 0 ) ? m_points_weights[0] : VEC4_CONST( 0.0f ); - int kmin = ( j == 0 ) ? 1 : j; - for( int k = kmin;; ) - { - // last cluster [k,count) is at the end - Vec4 part3 = m_xsum_wsum - part2 - part1 - part0; - - // compute least squares terms directly - Vec4 const alphax_sum = MultiplyAdd( part2, onethird_onethird2, MultiplyAdd( part1, twothirds_twothirds2, part0 ) ); - Vec4 const alpha2_sum = alphax_sum.SplatW(); - - Vec4 const betax_sum = MultiplyAdd( part1, onethird_onethird2, MultiplyAdd( part2, twothirds_twothirds2, part3 ) ); - Vec4 const beta2_sum = betax_sum.SplatW(); - - Vec4 const alphabeta_sum = twonineths*( part1 + part2 ).SplatW(); - - // compute the least-squares optimal points - Vec4 factor = Reciprocal( NegativeMultiplySubtract( alphabeta_sum, alphabeta_sum, alpha2_sum*beta2_sum ) ); - Vec4 a = NegativeMultiplySubtract( betax_sum, alphabeta_sum, alphax_sum*beta2_sum )*factor; - Vec4 b = NegativeMultiplySubtract( alphax_sum, alphabeta_sum, betax_sum*alpha2_sum )*factor; - - // clamp to the grid - a = Min( one, Max( zero, a ) ); - b = Min( one, Max( zero, b ) ); - a = Truncate( MultiplyAdd( grid, a, half ) )*gridrcp; - b = Truncate( MultiplyAdd( grid, b, half ) )*gridrcp; - - // compute the error (we skip the constant xxsum) - Vec4 e1 = MultiplyAdd( a*a, alpha2_sum, b*b*beta2_sum ); - Vec4 e2 = NegativeMultiplySubtract( a, alphax_sum, a*b*alphabeta_sum ); - Vec4 e3 = NegativeMultiplySubtract( b, betax_sum, e2 ); - Vec4 e4 = MultiplyAdd( two, e3, e1 ); - - // apply the metric to the error term - Vec4 e5 = e4*m_metric; - Vec4 error = e5.SplatX() + e5.SplatY() + e5.SplatZ(); - - // keep the solution if it wins - if( CompareAnyLessThan( error, besterror ) ) - { - beststart = a; - bestend = b; - besterror = error; - besti = i; - bestj = j; - bestk = k; - bestiteration = iterationIndex; - } - - // advance - if( k == count ) - break; - part2 += m_points_weights[k]; - ++k; - } - - // advance - if( j == count ) - break; - part1 += m_points_weights[j]; - ++j; - } - - // advance - part0 += m_points_weights[i]; - } - - // stop if we didn't improve in this iteration - if( bestiteration != iterationIndex ) - break; - - // advance if possible - ++iterationIndex; - if( iterationIndex == m_iterationCount ) - break; - - // stop if a new iteration is an ordering that has already been tried - Vec3 axis = ( bestend - beststart ).GetVec3(); - if( !ConstructOrdering( axis, iterationIndex ) ) - break; - } - - // save the block if necessary - if( CompareAnyLessThan( besterror, m_besterror ) ) - { - // remap the indices - u8 const* order = ( u8* )m_order + 16*bestiteration; - - u8 unordered[16]; - for( int m = 0; m < besti; ++m ) - unordered[order[m]] = 0; - for( int m = besti; m < bestj; ++m ) - unordered[order[m]] = 2; - for( int m = bestj; m < bestk; ++m ) - unordered[order[m]] = 3; - for( int m = bestk; m < count; ++m ) - unordered[order[m]] = 1; - - m_colours->RemapIndices( unordered, bestindices ); - - // save the block - WriteColourBlock4( beststart.GetVec3(), bestend.GetVec3(), bestindices, block ); - - // save the error - m_besterror = besterror; - } -} - -} // namespace squish diff --git a/thirdparty/squish/clusterfit.h b/thirdparty/squish/clusterfit.h deleted file mode 100644 index 999396b262..0000000000 --- a/thirdparty/squish/clusterfit.h +++ /dev/null @@ -1,61 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - Copyright (c) 2007 Ignacio Castano icastano@nvidia.com - - 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 SQUISH_CLUSTERFIT_H -#define SQUISH_CLUSTERFIT_H - -#include "squish.h" -#include "maths.h" -#include "simd.h" -#include "colourfit.h" - -namespace squish { - -class ClusterFit : public ColourFit -{ -public: - ClusterFit( ColourSet const* colours, int flags, float* metric ); - -private: - bool ConstructOrdering( Vec3 const& axis, int iteration ); - - virtual void Compress3( void* block ); - virtual void Compress4( void* block ); - - enum { kMaxIterations = 8 }; - - int m_iterationCount; - Vec3 m_principle; - u8 m_order[16*kMaxIterations]; - Vec4 m_points_weights[16]; - Vec4 m_xsum_wsum; - Vec4 m_metric; - Vec4 m_besterror; -}; - -} // namespace squish - -#endif // ndef SQUISH_CLUSTERFIT_H diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp deleted file mode 100644 index f14c9362bd..0000000000 --- a/thirdparty/squish/colourblock.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 "colourblock.h" -// -- GODOT start -- -#include "alpha.h" -// -- GODOT end -- - -namespace squish { - -static int FloatToInt( float a, int limit ) -{ - // use ANSI round-to-zero behaviour to get round-to-nearest - int i = ( int )( a + 0.5f ); - - // clamp to the limit - if( i < 0 ) - i = 0; - else if( i > limit ) - i = limit; - - // done - return i; -} - -static int FloatTo565( Vec3::Arg colour ) -{ - // get the components in the correct range - int r = FloatToInt( 31.0f*colour.X(), 31 ); - int g = FloatToInt( 63.0f*colour.Y(), 63 ); - int b = FloatToInt( 31.0f*colour.Z(), 31 ); - - // pack into a single value - return ( r << 11 ) | ( g << 5 ) | b; -} - -static void WriteColourBlock( int a, int b, u8* indices, void* block ) -{ - // get the block as bytes - u8* bytes = ( u8* )block; - - // write the endpoints - bytes[0] = ( u8 )( a & 0xff ); - bytes[1] = ( u8 )( a >> 8 ); - bytes[2] = ( u8 )( b & 0xff ); - bytes[3] = ( u8 )( b >> 8 ); - - // write the indices - for( int i = 0; i < 4; ++i ) - { - u8 const* ind = indices + 4*i; - bytes[4 + i] = ind[0] | ( ind[1] << 2 ) | ( ind[2] << 4 ) | ( ind[3] << 6 ); - } -} - -void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ) -{ - // get the packed values - int a = FloatTo565( start ); - int b = FloatTo565( end ); - - // remap the indices - u8 remapped[16]; - if( a <= b ) - { - // use the indices directly - for( int i = 0; i < 16; ++i ) - remapped[i] = indices[i]; - } - else - { - // swap a and b - std::swap( a, b ); - for( int i = 0; i < 16; ++i ) - { - if( indices[i] == 0 ) - remapped[i] = 1; - else if( indices[i] == 1 ) - remapped[i] = 0; - else - remapped[i] = indices[i]; - } - } - - // write the block - WriteColourBlock( a, b, remapped, block ); -} - -void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ) -{ - // get the packed values - int a = FloatTo565( start ); - int b = FloatTo565( end ); - - // remap the indices - u8 remapped[16]; - if( a < b ) - { - // swap a and b - std::swap( a, b ); - for( int i = 0; i < 16; ++i ) - remapped[i] = ( indices[i] ^ 0x1 ) & 0x3; - } - else if( a == b ) - { - // use index 0 - for( int i = 0; i < 16; ++i ) - remapped[i] = 0; - } - else - { - // use the indices directly - for( int i = 0; i < 16; ++i ) - remapped[i] = indices[i]; - } - - // write the block - WriteColourBlock( a, b, remapped, block ); -} - -static int Unpack565( u8 const* packed, u8* colour ) -{ - // build the packed value - int value = ( int )packed[0] | ( ( int )packed[1] << 8 ); - - // get the components in the stored range - u8 red = ( u8 )( ( value >> 11 ) & 0x1f ); - u8 green = ( u8 )( ( value >> 5 ) & 0x3f ); - u8 blue = ( u8 )( value & 0x1f ); - - // scale up to 8 bits - colour[0] = ( red << 3 ) | ( red >> 2 ); - colour[1] = ( green << 2 ) | ( green >> 4 ); - colour[2] = ( blue << 3 ) | ( blue >> 2 ); - colour[3] = 255; - - // return the value - return value; -} - -void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) -{ - // get the block bytes - u8 const* bytes = reinterpret_cast< u8 const* >( block ); - - // unpack the endpoints - u8 codes[16]; - int a = Unpack565( bytes, codes ); - int b = Unpack565( bytes + 2, codes + 4 ); - - // generate the midpoints - for( int i = 0; i < 3; ++i ) - { - int c = codes[i]; - int d = codes[4 + i]; - - if( isDxt1 && a <= b ) - { - codes[8 + i] = ( u8 )( ( c + d )/2 ); - codes[12 + i] = 0; - } - else - { - codes[8 + i] = ( u8 )( ( 2*c + d )/3 ); - codes[12 + i] = ( u8 )( ( c + 2*d )/3 ); - } - } - - // fill in alpha for the intermediate values - codes[8 + 3] = 255; - codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255; - - // unpack the indices - u8 indices[16]; - for( int i = 0; i < 4; ++i ) - { - u8* ind = indices + 4*i; - u8 packed = bytes[4 + i]; - - ind[0] = packed & 0x3; - ind[1] = ( packed >> 2 ) & 0x3; - ind[2] = ( packed >> 4 ) & 0x3; - ind[3] = ( packed >> 6 ) & 0x3; - } - - // store out the colours - for( int i = 0; i < 16; ++i ) - { - u8 offset = 4*indices[i]; - for( int j = 0; j < 4; ++j ) - rgba[4*i + j] = codes[offset + j]; - } -} - -// -- GODOT start -- -void DecompressColourBc4( u8* rgba, void const* block) -{ - DecompressAlphaDxt5(rgba,block); - for ( int i = 0; i < 16; ++i ) { - rgba[i*4] = rgba[i*4 + 3]; - rgba[i*4 + 1] = 0; - rgba[i*4 + 2] = 0; - rgba[i*4 + 3] = 255; - } -} - -void DecompressColourBc5( u8* rgba, void const* block) -{ - void const* rblock = block; - void const* gblock = reinterpret_cast< u8 const* >( block ) + 8; - DecompressAlphaDxt5(rgba,rblock); - for ( int i = 0; i < 16; ++i ) { - rgba[i*4] = rgba[i*4 + 3]; - } - DecompressAlphaDxt5(rgba,gblock); - for ( int i = 0; i < 16; ++i ) { - rgba[i*4+1] = rgba[i*4 + 3]; - rgba[i*4 + 2] = 0; - rgba[i*4 + 3] = 255; - } -} -// -- GODOT end -- - - -} // namespace squish diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h deleted file mode 100644 index e1eb9e4917..0000000000 --- a/thirdparty/squish/colourblock.h +++ /dev/null @@ -1,45 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_COLOURBLOCK_H -#define SQUISH_COLOURBLOCK_H - -#include "squish.h" -#include "maths.h" - -namespace squish { - -void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); -void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); - -void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); -// -- GODOT start -- -void DecompressColourBc4( u8* rgba, void const* block ); -void DecompressColourBc5( u8* rgba, void const* block ); -// -- GODOT end -- - -} // namespace squish - -#endif // ndef SQUISH_COLOURBLOCK_H diff --git a/thirdparty/squish/colourfit.cpp b/thirdparty/squish/colourfit.cpp deleted file mode 100644 index e45b656557..0000000000 --- a/thirdparty/squish/colourfit.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 "colourfit.h" -#include "colourset.h" - -namespace squish { - -ColourFit::ColourFit( ColourSet const* colours, int flags ) - : m_colours( colours ), - m_flags( flags ) -{ -} - -ColourFit::~ColourFit() -{ -} - -void ColourFit::Compress( void* block ) -{ - bool isDxt1 = ( ( m_flags & kDxt1 ) != 0 ); - if( isDxt1 ) - { - Compress3( block ); - if( !m_colours->IsTransparent() ) - Compress4( block ); - } - else - Compress4( block ); -} - -} // namespace squish diff --git a/thirdparty/squish/colourfit.h b/thirdparty/squish/colourfit.h deleted file mode 100644 index e73dceb2eb..0000000000 --- a/thirdparty/squish/colourfit.h +++ /dev/null @@ -1,56 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_COLOURFIT_H -#define SQUISH_COLOURFIT_H - -#include "squish.h" -#include "maths.h" - -#include <climits> - -namespace squish { - -class ColourSet; - -class ColourFit -{ -public: - ColourFit( ColourSet const* colours, int flags ); - virtual ~ColourFit(); - - void Compress( void* block ); - -protected: - virtual void Compress3( void* block ) = 0; - virtual void Compress4( void* block ) = 0; - - ColourSet const* m_colours; - int m_flags; -}; - -} // namespace squish - -#endif // ndef SQUISH_COLOURFIT_H diff --git a/thirdparty/squish/colourset.cpp b/thirdparty/squish/colourset.cpp deleted file mode 100644 index e900556471..0000000000 --- a/thirdparty/squish/colourset.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 "colourset.h" - -namespace squish { - -ColourSet::ColourSet( u8 const* rgba, int mask, int flags ) - : m_count( 0 ), - m_transparent( false ) -{ - // check the compression mode for dxt1 - bool isDxt1 = ( ( flags & kDxt1 ) != 0 ); - bool weightByAlpha = ( ( flags & kWeightColourByAlpha ) != 0 ); - - // create the minimal set - for( int i = 0; i < 16; ++i ) - { - // check this pixel is enabled - int bit = 1 << i; - if( ( mask & bit ) == 0 ) - { - m_remap[i] = -1; - continue; - } - - // check for transparent pixels when using dxt1 - if( isDxt1 && rgba[4*i + 3] < 128 ) - { - m_remap[i] = -1; - m_transparent = true; - continue; - } - - // loop over previous points for a match - for( int j = 0;; ++j ) - { - // allocate a new point - if( j == i ) - { - // normalise coordinates to [0,1] - float x = ( float )rgba[4*i] / 255.0f; - float y = ( float )rgba[4*i + 1] / 255.0f; - float z = ( float )rgba[4*i + 2] / 255.0f; - - // ensure there is always non-zero weight even for zero alpha - float w = ( float )( rgba[4*i + 3] + 1 ) / 256.0f; - - // add the point - m_points[m_count] = Vec3( x, y, z ); - m_weights[m_count] = ( weightByAlpha ? w : 1.0f ); - m_remap[i] = m_count; - - // advance - ++m_count; - break; - } - - // check for a match - int oldbit = 1 << j; - bool match = ( ( mask & oldbit ) != 0 ) - && ( rgba[4*i] == rgba[4*j] ) - && ( rgba[4*i + 1] == rgba[4*j + 1] ) - && ( rgba[4*i + 2] == rgba[4*j + 2] ) - && ( rgba[4*j + 3] >= 128 || !isDxt1 ); - if( match ) - { - // get the index of the match - int index = m_remap[j]; - - // ensure there is always non-zero weight even for zero alpha - float w = ( float )( rgba[4*i + 3] + 1 ) / 256.0f; - - // map to this point and increase the weight - m_weights[index] += ( weightByAlpha ? w : 1.0f ); - m_remap[i] = index; - break; - } - } - } - - // square root the weights - for( int i = 0; i < m_count; ++i ) - m_weights[i] = std::sqrt( m_weights[i] ); -} - -void ColourSet::RemapIndices( u8 const* source, u8* target ) const -{ - for( int i = 0; i < 16; ++i ) - { - int j = m_remap[i]; - if( j == -1 ) - target[i] = 3; - else - target[i] = source[j]; - } -} - -} // namespace squish diff --git a/thirdparty/squish/colourset.h b/thirdparty/squish/colourset.h deleted file mode 100644 index e13bb6fc35..0000000000 --- a/thirdparty/squish/colourset.h +++ /dev/null @@ -1,58 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_COLOURSET_H -#define SQUISH_COLOURSET_H - -#include "squish.h" -#include "maths.h" - -namespace squish { - -/*! @brief Represents a set of block colours -*/ -class ColourSet -{ -public: - ColourSet( u8 const* rgba, int mask, int flags ); - - int GetCount() const { return m_count; } - Vec3 const* GetPoints() const { return m_points; } - float const* GetWeights() const { return m_weights; } - bool IsTransparent() const { return m_transparent; } - - void RemapIndices( u8 const* source, u8* target ) const; - -private: - int m_count; - Vec3 m_points[16]; - float m_weights[16]; - int m_remap[16]; - bool m_transparent; -}; - -} // namespace sqish - -#endif // ndef SQUISH_COLOURSET_H diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h deleted file mode 100644 index 05f8d72598..0000000000 --- a/thirdparty/squish/config.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_CONFIG_H -#define SQUISH_CONFIG_H - -// Set to 1 when building squish to use Altivec instructions. -#ifndef SQUISH_USE_ALTIVEC -#define SQUISH_USE_ALTIVEC 0 -#endif - -// Set to 1 or 2 when building squish to use SSE or SSE2 instructions. -// -- GODOT start -- -#ifdef _MSC_VER - #if defined(_M_IX86_FP) - #if _M_IX86_FP >= 2 - #define SQUISH_USE_SSE 2 - #elif _M_IX86_FP >= 1 - #define SQUISH_USE_SSE 1 - #endif - #elif defined(_M_X64) - #define SQUISH_USE_SSE 2 - #endif -#else - #if defined(__SSE2__) - #define SQUISH_USE_SSE 2 - #elif defined(__SSE__) - #define SQUISH_USE_SSE 1 - #endif -#endif -// -- GODOT end -- - -#ifndef SQUISH_USE_SSE -#define SQUISH_USE_SSE 0 -#endif - -// Internally set SQUISH_USE_SIMD when either Altivec or SSE is available. -#if SQUISH_USE_ALTIVEC && SQUISH_USE_SSE -#error "Cannot enable both Altivec and SSE!" -#endif -#if SQUISH_USE_ALTIVEC || SQUISH_USE_SSE -#define SQUISH_USE_SIMD 1 -#else -#define SQUISH_USE_SIMD 0 -#endif - -#endif // ndef SQUISH_CONFIG_H diff --git a/thirdparty/squish/maths.cpp b/thirdparty/squish/maths.cpp deleted file mode 100644 index 4fa0bcfb35..0000000000 --- a/thirdparty/squish/maths.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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. - - -------------------------------------------------------------------------- */ - -/*! @file - - The symmetric eigensystem solver algorithm is from - http://www.geometrictools.com/Documentation/EigenSymmetric3x3.pdf -*/ - -#include "maths.h" -#include "simd.h" -#include <cfloat> - -namespace squish { - -Sym3x3 ComputeWeightedCovariance( int n, Vec3 const* points, float const* weights ) -{ - // compute the centroid - float total = 0.0f; - Vec3 centroid( 0.0f ); - for( int i = 0; i < n; ++i ) - { - total += weights[i]; - centroid += weights[i]*points[i]; - } - if( total > FLT_EPSILON ) - centroid /= total; - - // accumulate the covariance matrix - Sym3x3 covariance( 0.0f ); - for( int i = 0; i < n; ++i ) - { - Vec3 a = points[i] - centroid; - Vec3 b = weights[i]*a; - - covariance[0] += a.X()*b.X(); - covariance[1] += a.X()*b.Y(); - covariance[2] += a.X()*b.Z(); - covariance[3] += a.Y()*b.Y(); - covariance[4] += a.Y()*b.Z(); - covariance[5] += a.Z()*b.Z(); - } - - // return it - return covariance; -} - -#if 0 - -static Vec3 GetMultiplicity1Evector( Sym3x3 const& matrix, float evalue ) -{ - // compute M - Sym3x3 m; - m[0] = matrix[0] - evalue; - m[1] = matrix[1]; - m[2] = matrix[2]; - m[3] = matrix[3] - evalue; - m[4] = matrix[4]; - m[5] = matrix[5] - evalue; - - // compute U - Sym3x3 u; - u[0] = m[3]*m[5] - m[4]*m[4]; - u[1] = m[2]*m[4] - m[1]*m[5]; - u[2] = m[1]*m[4] - m[2]*m[3]; - u[3] = m[0]*m[5] - m[2]*m[2]; - u[4] = m[1]*m[2] - m[4]*m[0]; - u[5] = m[0]*m[3] - m[1]*m[1]; - - // find the largest component - float mc = std::fabs( u[0] ); - int mi = 0; - for( int i = 1; i < 6; ++i ) - { - float c = std::fabs( u[i] ); - if( c > mc ) - { - mc = c; - mi = i; - } - } - - // pick the column with this component - switch( mi ) - { - case 0: - return Vec3( u[0], u[1], u[2] ); - - case 1: - case 3: - return Vec3( u[1], u[3], u[4] ); - - default: - return Vec3( u[2], u[4], u[5] ); - } -} - -static Vec3 GetMultiplicity2Evector( Sym3x3 const& matrix, float evalue ) -{ - // compute M - Sym3x3 m; - m[0] = matrix[0] - evalue; - m[1] = matrix[1]; - m[2] = matrix[2]; - m[3] = matrix[3] - evalue; - m[4] = matrix[4]; - m[5] = matrix[5] - evalue; - - // find the largest component - float mc = std::fabs( m[0] ); - int mi = 0; - for( int i = 1; i < 6; ++i ) - { - float c = std::fabs( m[i] ); - if( c > mc ) - { - mc = c; - mi = i; - } - } - - // pick the first eigenvector based on this index - switch( mi ) - { - case 0: - case 1: - return Vec3( -m[1], m[0], 0.0f ); - - case 2: - return Vec3( m[2], 0.0f, -m[0] ); - - case 3: - case 4: - return Vec3( 0.0f, -m[4], m[3] ); - - default: - return Vec3( 0.0f, -m[5], m[4] ); - } -} - -Vec3 ComputePrincipleComponent( Sym3x3 const& matrix ) -{ - // compute the cubic coefficients - float c0 = matrix[0]*matrix[3]*matrix[5] - + 2.0f*matrix[1]*matrix[2]*matrix[4] - - matrix[0]*matrix[4]*matrix[4] - - matrix[3]*matrix[2]*matrix[2] - - matrix[5]*matrix[1]*matrix[1]; - float c1 = matrix[0]*matrix[3] + matrix[0]*matrix[5] + matrix[3]*matrix[5] - - matrix[1]*matrix[1] - matrix[2]*matrix[2] - matrix[4]*matrix[4]; - float c2 = matrix[0] + matrix[3] + matrix[5]; - - // compute the quadratic coefficients - float a = c1 - ( 1.0f/3.0f )*c2*c2; - float b = ( -2.0f/27.0f )*c2*c2*c2 + ( 1.0f/3.0f )*c1*c2 - c0; - - // compute the root count check - float Q = 0.25f*b*b + ( 1.0f/27.0f )*a*a*a; - - // test the multiplicity - if( FLT_EPSILON < Q ) - { - // only one root, which implies we have a multiple of the identity - return Vec3( 1.0f ); - } - else if( Q < -FLT_EPSILON ) - { - // three distinct roots - float theta = std::atan2( std::sqrt( -Q ), -0.5f*b ); - float rho = std::sqrt( 0.25f*b*b - Q ); - - float rt = std::pow( rho, 1.0f/3.0f ); - float ct = std::cos( theta/3.0f ); - float st = std::sin( theta/3.0f ); - - float l1 = ( 1.0f/3.0f )*c2 + 2.0f*rt*ct; - float l2 = ( 1.0f/3.0f )*c2 - rt*( ct + ( float )sqrt( 3.0f )*st ); - float l3 = ( 1.0f/3.0f )*c2 - rt*( ct - ( float )sqrt( 3.0f )*st ); - - // pick the larger - if( std::fabs( l2 ) > std::fabs( l1 ) ) - l1 = l2; - if( std::fabs( l3 ) > std::fabs( l1 ) ) - l1 = l3; - - // get the eigenvector - return GetMultiplicity1Evector( matrix, l1 ); - } - else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON ) - { - // two roots - float rt; - if( b < 0.0f ) - rt = -std::pow( -0.5f*b, 1.0f/3.0f ); - else - rt = std::pow( 0.5f*b, 1.0f/3.0f ); - - float l1 = ( 1.0f/3.0f )*c2 + rt; // repeated - float l2 = ( 1.0f/3.0f )*c2 - 2.0f*rt; - - // get the eigenvector - if( std::fabs( l1 ) > std::fabs( l2 ) ) - return GetMultiplicity2Evector( matrix, l1 ); - else - return GetMultiplicity1Evector( matrix, l2 ); - } -} - -#else - -#define POWER_ITERATION_COUNT 8 - -Vec3 ComputePrincipleComponent( Sym3x3 const& matrix ) -{ - Vec4 const row0( matrix[0], matrix[1], matrix[2], 0.0f ); - Vec4 const row1( matrix[1], matrix[3], matrix[4], 0.0f ); - Vec4 const row2( matrix[2], matrix[4], matrix[5], 0.0f ); - Vec4 v = VEC4_CONST( 1.0f ); - for( int i = 0; i < POWER_ITERATION_COUNT; ++i ) - { - // matrix multiply - Vec4 w = row0*v.SplatX(); - w = MultiplyAdd(row1, v.SplatY(), w); - w = MultiplyAdd(row2, v.SplatZ(), w); - - // get max component from xyz in all channels - Vec4 a = Max(w.SplatX(), Max(w.SplatY(), w.SplatZ())); - - // divide through and advance - v = w*Reciprocal(a); - } - return v.GetVec3(); -} - -#endif - -} // namespace squish diff --git a/thirdparty/squish/maths.h b/thirdparty/squish/maths.h deleted file mode 100644 index 59c32196b1..0000000000 --- a/thirdparty/squish/maths.h +++ /dev/null @@ -1,233 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_MATHS_H -#define SQUISH_MATHS_H - -#include <cmath> -#include <algorithm> -#include "config.h" - -namespace squish { - -class Vec3 -{ -public: - typedef Vec3 const& Arg; - - Vec3() - { - } - - explicit Vec3( float s ) - { - m_x = s; - m_y = s; - m_z = s; - } - - Vec3( float x, float y, float z ) - { - m_x = x; - m_y = y; - m_z = z; - } - - float X() const { return m_x; } - float Y() const { return m_y; } - float Z() const { return m_z; } - - Vec3 operator-() const - { - return Vec3( -m_x, -m_y, -m_z ); - } - - Vec3& operator+=( Arg v ) - { - m_x += v.m_x; - m_y += v.m_y; - m_z += v.m_z; - return *this; - } - - Vec3& operator-=( Arg v ) - { - m_x -= v.m_x; - m_y -= v.m_y; - m_z -= v.m_z; - return *this; - } - - Vec3& operator*=( Arg v ) - { - m_x *= v.m_x; - m_y *= v.m_y; - m_z *= v.m_z; - return *this; - } - - Vec3& operator*=( float s ) - { - m_x *= s; - m_y *= s; - m_z *= s; - return *this; - } - - Vec3& operator/=( Arg v ) - { - m_x /= v.m_x; - m_y /= v.m_y; - m_z /= v.m_z; - return *this; - } - - Vec3& operator/=( float s ) - { - float t = 1.0f/s; - m_x *= t; - m_y *= t; - m_z *= t; - return *this; - } - - friend Vec3 operator+( Arg left, Arg right ) - { - Vec3 copy( left ); - return copy += right; - } - - friend Vec3 operator-( Arg left, Arg right ) - { - Vec3 copy( left ); - return copy -= right; - } - - friend Vec3 operator*( Arg left, Arg right ) - { - Vec3 copy( left ); - return copy *= right; - } - - friend Vec3 operator*( Arg left, float right ) - { - Vec3 copy( left ); - return copy *= right; - } - - friend Vec3 operator*( float left, Arg right ) - { - Vec3 copy( right ); - return copy *= left; - } - - friend Vec3 operator/( Arg left, Arg right ) - { - Vec3 copy( left ); - return copy /= right; - } - - friend Vec3 operator/( Arg left, float right ) - { - Vec3 copy( left ); - return copy /= right; - } - - friend float Dot( Arg left, Arg right ) - { - return left.m_x*right.m_x + left.m_y*right.m_y + left.m_z*right.m_z; - } - - friend Vec3 Min( Arg left, Arg right ) - { - return Vec3( - std::min( left.m_x, right.m_x ), - std::min( left.m_y, right.m_y ), - std::min( left.m_z, right.m_z ) - ); - } - - friend Vec3 Max( Arg left, Arg right ) - { - return Vec3( - std::max( left.m_x, right.m_x ), - std::max( left.m_y, right.m_y ), - std::max( left.m_z, right.m_z ) - ); - } - - friend Vec3 Truncate( Arg v ) - { - return Vec3( - v.m_x > 0.0f ? std::floor( v.m_x ) : std::ceil( v.m_x ), - v.m_y > 0.0f ? std::floor( v.m_y ) : std::ceil( v.m_y ), - v.m_z > 0.0f ? std::floor( v.m_z ) : std::ceil( v.m_z ) - ); - } - -private: - float m_x; - float m_y; - float m_z; -}; - -inline float LengthSquared( Vec3::Arg v ) -{ - return Dot( v, v ); -} - -class Sym3x3 -{ -public: - Sym3x3() - { - } - - Sym3x3( float s ) - { - for( int i = 0; i < 6; ++i ) - m_x[i] = s; - } - - float operator[]( int index ) const - { - return m_x[index]; - } - - float& operator[]( int index ) - { - return m_x[index]; - } - -private: - float m_x[6]; -}; - -Sym3x3 ComputeWeightedCovariance( int n, Vec3 const* points, float const* weights ); -Vec3 ComputePrincipleComponent( Sym3x3 const& matrix ); - -} // namespace squish - -#endif // ndef SQUISH_MATHS_H diff --git a/thirdparty/squish/patches/config_sse.patch b/thirdparty/squish/patches/config_sse.patch deleted file mode 100644 index 047701ee32..0000000000 --- a/thirdparty/squish/patches/config_sse.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h -index 92edefe966..05f8d72598 100644 ---- a/thirdparty/squish/config.h -+++ b/thirdparty/squish/config.h -@@ -32,6 +32,26 @@ - #endif - - // Set to 1 or 2 when building squish to use SSE or SSE2 instructions. -+// -- GODOT start -- -+#ifdef _MSC_VER -+ #if defined(_M_IX86_FP) -+ #if _M_IX86_FP >= 2 -+ #define SQUISH_USE_SSE 2 -+ #elif _M_IX86_FP >= 1 -+ #define SQUISH_USE_SSE 1 -+ #endif -+ #elif defined(_M_X64) -+ #define SQUISH_USE_SSE 2 -+ #endif -+#else -+ #if defined(__SSE2__) -+ #define SQUISH_USE_SSE 2 -+ #elif defined(__SSE__) -+ #define SQUISH_USE_SSE 1 -+ #endif -+#endif -+// -- GODOT end -- -+ - #ifndef SQUISH_USE_SSE - #define SQUISH_USE_SSE 0 - #endif diff --git a/thirdparty/squish/patches/decompress_bc4_bc5.patch b/thirdparty/squish/patches/decompress_bc4_bc5.patch deleted file mode 100644 index 949375560c..0000000000 --- a/thirdparty/squish/patches/decompress_bc4_bc5.patch +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp -index af8b980365..f14c9362bd 100644 ---- a/thirdparty/squish/colourblock.cpp -+++ b/thirdparty/squish/colourblock.cpp -@@ -24,6 +24,9 @@ - -------------------------------------------------------------------------- */ - - #include "colourblock.h" -+// -- GODOT start -- -+#include "alpha.h" -+// -- GODOT end -- - - namespace squish { - -@@ -211,4 +214,34 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) - } - } - -+// -- GODOT start -- -+void DecompressColourBc4( u8* rgba, void const* block) -+{ -+ DecompressAlphaDxt5(rgba,block); -+ for ( int i = 0; i < 16; ++i ) { -+ rgba[i*4] = rgba[i*4 + 3]; -+ rgba[i*4 + 1] = 0; -+ rgba[i*4 + 2] = 0; -+ rgba[i*4 + 3] = 255; -+ } -+} -+ -+void DecompressColourBc5( u8* rgba, void const* block) -+{ -+ void const* rblock = block; -+ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8; -+ DecompressAlphaDxt5(rgba,rblock); -+ for ( int i = 0; i < 16; ++i ) { -+ rgba[i*4] = rgba[i*4 + 3]; -+ } -+ DecompressAlphaDxt5(rgba,gblock); -+ for ( int i = 0; i < 16; ++i ) { -+ rgba[i*4+1] = rgba[i*4 + 3]; -+ rgba[i*4 + 2] = 0; -+ rgba[i*4 + 3] = 255; -+ } -+} -+// -- GODOT end -- -+ -+ - } // namespace squish -diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h -index fee2cd7c5d..e1eb9e4917 100644 ---- a/thirdparty/squish/colourblock.h -+++ b/thirdparty/squish/colourblock.h -@@ -35,6 +35,10 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* - void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); - - void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); -+// -- GODOT start -- -+void DecompressColourBc4( u8* rgba, void const* block ); -+void DecompressColourBc5( u8* rgba, void const* block ); -+// -- GODOT end -- - - } // namespace squish - -diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp -index 1d22a64ad6..086ba11cd0 100644 ---- a/thirdparty/squish/squish.cpp -+++ b/thirdparty/squish/squish.cpp -@@ -135,7 +135,15 @@ void Decompress( u8* rgba, void const* block, int flags ) - colourBlock = reinterpret_cast< u8 const* >( block ) + 8; - - // decompress colour -- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); -+ // -- GODOT start -- -+ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); -+ if(( flags & ( kBc4 ) ) != 0) -+ DecompressColourBc4( rgba, colourBlock); -+ else if(( flags & ( kBc5 ) ) != 0) -+ DecompressColourBc5( rgba, colourBlock); -+ else -+ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); -+ // -- GODOT end -- - - // decompress alpha separately if necessary - if( ( flags & kDxt3 ) != 0 ) diff --git a/thirdparty/squish/rangefit.cpp b/thirdparty/squish/rangefit.cpp deleted file mode 100644 index adc07ed7d2..0000000000 --- a/thirdparty/squish/rangefit.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 "rangefit.h" -#include "colourset.h" -#include "colourblock.h" -#include <cfloat> - -namespace squish { - -RangeFit::RangeFit( ColourSet const* colours, int flags, float* metric ) - : ColourFit( colours, flags ) -{ - // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f) - if( metric ) - m_metric = Vec3( metric[0], metric[1], metric[2] ); - else - m_metric = Vec3( 1.0f ); - - // initialise the best error - m_besterror = FLT_MAX; - - // cache some values - int const count = m_colours->GetCount(); - Vec3 const* values = m_colours->GetPoints(); - float const* weights = m_colours->GetWeights(); - - // get the covariance matrix - Sym3x3 covariance = ComputeWeightedCovariance( count, values, weights ); - - // compute the principle component - Vec3 principle = ComputePrincipleComponent( covariance ); - - // get the min and max range as the codebook endpoints - Vec3 start( 0.0f ); - Vec3 end( 0.0f ); - if( count > 0 ) - { - float min, max; - - // compute the range - start = end = values[0]; - min = max = Dot( values[0], principle ); - for( int i = 1; i < count; ++i ) - { - float val = Dot( values[i], principle ); - if( val < min ) - { - start = values[i]; - min = val; - } - else if( val > max ) - { - end = values[i]; - max = val; - } - } - } - - // clamp the output to [0, 1] - Vec3 const one( 1.0f ); - Vec3 const zero( 0.0f ); - start = Min( one, Max( zero, start ) ); - end = Min( one, Max( zero, end ) ); - - // clamp to the grid and save - Vec3 const grid( 31.0f, 63.0f, 31.0f ); - Vec3 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f ); - Vec3 const half( 0.5f ); - m_start = Truncate( grid*start + half )*gridrcp; - m_end = Truncate( grid*end + half )*gridrcp; -} - -void RangeFit::Compress3( void* block ) -{ - // cache some values - int const count = m_colours->GetCount(); - Vec3 const* values = m_colours->GetPoints(); - - // create a codebook - Vec3 codes[3]; - codes[0] = m_start; - codes[1] = m_end; - codes[2] = 0.5f*m_start + 0.5f*m_end; - - // match each point to the closest code - u8 closest[16]; - float error = 0.0f; - for( int i = 0; i < count; ++i ) - { - // find the closest code - float dist = FLT_MAX; - int idx = 0; - for( int j = 0; j < 3; ++j ) - { - float d = LengthSquared( m_metric*( values[i] - codes[j] ) ); - if( d < dist ) - { - dist = d; - idx = j; - } - } - - // save the index - closest[i] = ( u8 )idx; - - // accumulate the error - error += dist; - } - - // save this scheme if it wins - if( error < m_besterror ) - { - // remap the indices - u8 indices[16]; - m_colours->RemapIndices( closest, indices ); - - // save the block - WriteColourBlock3( m_start, m_end, indices, block ); - - // save the error - m_besterror = error; - } -} - -void RangeFit::Compress4( void* block ) -{ - // cache some values - int const count = m_colours->GetCount(); - Vec3 const* values = m_colours->GetPoints(); - - // create a codebook - Vec3 codes[4]; - codes[0] = m_start; - codes[1] = m_end; - codes[2] = ( 2.0f/3.0f )*m_start + ( 1.0f/3.0f )*m_end; - codes[3] = ( 1.0f/3.0f )*m_start + ( 2.0f/3.0f )*m_end; - - // match each point to the closest code - u8 closest[16]; - float error = 0.0f; - for( int i = 0; i < count; ++i ) - { - // find the closest code - float dist = FLT_MAX; - int idx = 0; - for( int j = 0; j < 4; ++j ) - { - float d = LengthSquared( m_metric*( values[i] - codes[j] ) ); - if( d < dist ) - { - dist = d; - idx = j; - } - } - - // save the index - closest[i] = ( u8 )idx; - - // accumulate the error - error += dist; - } - - // save this scheme if it wins - if( error < m_besterror ) - { - // remap the indices - u8 indices[16]; - m_colours->RemapIndices( closest, indices ); - - // save the block - WriteColourBlock4( m_start, m_end, indices, block ); - - // save the error - m_besterror = error; - } -} - -} // namespace squish diff --git a/thirdparty/squish/rangefit.h b/thirdparty/squish/rangefit.h deleted file mode 100644 index bdb21a9007..0000000000 --- a/thirdparty/squish/rangefit.h +++ /dev/null @@ -1,54 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_RANGEFIT_H -#define SQUISH_RANGEFIT_H - -#include "squish.h" -#include "colourfit.h" -#include "maths.h" - -namespace squish { - -class ColourSet; - -class RangeFit : public ColourFit -{ -public: - RangeFit( ColourSet const* colours, int flags, float* metric ); - -private: - virtual void Compress3( void* block ); - virtual void Compress4( void* block ); - - Vec3 m_metric; - Vec3 m_start; - Vec3 m_end; - float m_besterror; -}; - -} // squish - -#endif // ndef SQUISH_RANGEFIT_H diff --git a/thirdparty/squish/simd.h b/thirdparty/squish/simd.h deleted file mode 100644 index 1e02fa160e..0000000000 --- a/thirdparty/squish/simd.h +++ /dev/null @@ -1,40 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_SIMD_H -#define SQUISH_SIMD_H - -#include "maths.h" - -#if SQUISH_USE_ALTIVEC -#include "simd_ve.h" -#elif SQUISH_USE_SSE -#include "simd_sse.h" -#else -#include "simd_float.h" -#endif - - -#endif // ndef SQUISH_SIMD_H diff --git a/thirdparty/squish/simd_float.h b/thirdparty/squish/simd_float.h deleted file mode 100644 index 030ea70950..0000000000 --- a/thirdparty/squish/simd_float.h +++ /dev/null @@ -1,183 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_SIMD_FLOAT_H -#define SQUISH_SIMD_FLOAT_H - -#include <algorithm> - -namespace squish { - -#define VEC4_CONST( X ) Vec4( X ) - -class Vec4 -{ -public: - typedef Vec4 const& Arg; - - Vec4() {} - - explicit Vec4( float s ) - : m_x( s ), - m_y( s ), - m_z( s ), - m_w( s ) - { - } - - Vec4( float x, float y, float z, float w ) - : m_x( x ), - m_y( y ), - m_z( z ), - m_w( w ) - { - } - - Vec3 GetVec3() const - { - return Vec3( m_x, m_y, m_z ); - } - - Vec4 SplatX() const { return Vec4( m_x ); } - Vec4 SplatY() const { return Vec4( m_y ); } - Vec4 SplatZ() const { return Vec4( m_z ); } - Vec4 SplatW() const { return Vec4( m_w ); } - - Vec4& operator+=( Arg v ) - { - m_x += v.m_x; - m_y += v.m_y; - m_z += v.m_z; - m_w += v.m_w; - return *this; - } - - Vec4& operator-=( Arg v ) - { - m_x -= v.m_x; - m_y -= v.m_y; - m_z -= v.m_z; - m_w -= v.m_w; - return *this; - } - - Vec4& operator*=( Arg v ) - { - m_x *= v.m_x; - m_y *= v.m_y; - m_z *= v.m_z; - m_w *= v.m_w; - return *this; - } - - friend Vec4 operator+( Vec4::Arg left, Vec4::Arg right ) - { - Vec4 copy( left ); - return copy += right; - } - - friend Vec4 operator-( Vec4::Arg left, Vec4::Arg right ) - { - Vec4 copy( left ); - return copy -= right; - } - - friend Vec4 operator*( Vec4::Arg left, Vec4::Arg right ) - { - Vec4 copy( left ); - return copy *= right; - } - - //! Returns a*b + c - friend Vec4 MultiplyAdd( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) - { - return a*b + c; - } - - //! Returns -( a*b - c ) - friend Vec4 NegativeMultiplySubtract( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) - { - return c - a*b; - } - - friend Vec4 Reciprocal( Vec4::Arg v ) - { - return Vec4( - 1.0f/v.m_x, - 1.0f/v.m_y, - 1.0f/v.m_z, - 1.0f/v.m_w - ); - } - - friend Vec4 Min( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( - std::min( left.m_x, right.m_x ), - std::min( left.m_y, right.m_y ), - std::min( left.m_z, right.m_z ), - std::min( left.m_w, right.m_w ) - ); - } - - friend Vec4 Max( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( - std::max( left.m_x, right.m_x ), - std::max( left.m_y, right.m_y ), - std::max( left.m_z, right.m_z ), - std::max( left.m_w, right.m_w ) - ); - } - - friend Vec4 Truncate( Vec4::Arg v ) - { - return Vec4( - v.m_x > 0.0f ? std::floor( v.m_x ) : std::ceil( v.m_x ), - v.m_y > 0.0f ? std::floor( v.m_y ) : std::ceil( v.m_y ), - v.m_z > 0.0f ? std::floor( v.m_z ) : std::ceil( v.m_z ), - v.m_w > 0.0f ? std::floor( v.m_w ) : std::ceil( v.m_w ) - ); - } - - friend bool CompareAnyLessThan( Vec4::Arg left, Vec4::Arg right ) - { - return left.m_x < right.m_x - || left.m_y < right.m_y - || left.m_z < right.m_z - || left.m_w < right.m_w; - } - -private: - float m_x; - float m_y; - float m_z; - float m_w; -}; - -} // namespace squish - -#endif // ndef SQUISH_SIMD_FLOAT_H - diff --git a/thirdparty/squish/simd_sse.h b/thirdparty/squish/simd_sse.h deleted file mode 100644 index 2e8be4ca7b..0000000000 --- a/thirdparty/squish/simd_sse.h +++ /dev/null @@ -1,180 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_SIMD_SSE_H -#define SQUISH_SIMD_SSE_H - -#include <xmmintrin.h> -#if ( SQUISH_USE_SSE > 1 ) -#include <emmintrin.h> -#endif - -#define SQUISH_SSE_SPLAT( a ) \ - ( ( a ) | ( ( a ) << 2 ) | ( ( a ) << 4 ) | ( ( a ) << 6 ) ) - -#define SQUISH_SSE_SHUF( x, y, z, w ) \ - ( ( x ) | ( ( y ) << 2 ) | ( ( z ) << 4 ) | ( ( w ) << 6 ) ) - -namespace squish { - -#define VEC4_CONST( X ) Vec4( X ) - -class Vec4 -{ -public: - typedef Vec4 const& Arg; - - Vec4() {} - - explicit Vec4( __m128 v ) : m_v( v ) {} - - Vec4( Vec4 const& arg ) : m_v( arg.m_v ) {} - - Vec4& operator=( Vec4 const& arg ) - { - m_v = arg.m_v; - return *this; - } - - explicit Vec4( float s ) : m_v( _mm_set1_ps( s ) ) {} - - Vec4( float x, float y, float z, float w ) : m_v( _mm_setr_ps( x, y, z, w ) ) {} - - Vec3 GetVec3() const - { -#ifdef __GNUC__ - __attribute__ ((__aligned__ (16))) float c[4]; -#else - __declspec(align(16)) float c[4]; -#endif - _mm_store_ps( c, m_v ); - return Vec3( c[0], c[1], c[2] ); - } - - Vec4 SplatX() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 0 ) ) ); } - Vec4 SplatY() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 1 ) ) ); } - Vec4 SplatZ() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 2 ) ) ); } - Vec4 SplatW() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 3 ) ) ); } - - Vec4& operator+=( Arg v ) - { - m_v = _mm_add_ps( m_v, v.m_v ); - return *this; - } - - Vec4& operator-=( Arg v ) - { - m_v = _mm_sub_ps( m_v, v.m_v ); - return *this; - } - - Vec4& operator*=( Arg v ) - { - m_v = _mm_mul_ps( m_v, v.m_v ); - return *this; - } - - friend Vec4 operator+( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( _mm_add_ps( left.m_v, right.m_v ) ); - } - - friend Vec4 operator-( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( _mm_sub_ps( left.m_v, right.m_v ) ); - } - - friend Vec4 operator*( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( _mm_mul_ps( left.m_v, right.m_v ) ); - } - - //! Returns a*b + c - friend Vec4 MultiplyAdd( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) - { - return Vec4( _mm_add_ps( _mm_mul_ps( a.m_v, b.m_v ), c.m_v ) ); - } - - //! Returns -( a*b - c ) - friend Vec4 NegativeMultiplySubtract( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) - { - return Vec4( _mm_sub_ps( c.m_v, _mm_mul_ps( a.m_v, b.m_v ) ) ); - } - - friend Vec4 Reciprocal( Vec4::Arg v ) - { - // get the reciprocal estimate - __m128 estimate = _mm_rcp_ps( v.m_v ); - - // one round of Newton-Rhaphson refinement - __m128 diff = _mm_sub_ps( _mm_set1_ps( 1.0f ), _mm_mul_ps( estimate, v.m_v ) ); - return Vec4( _mm_add_ps( _mm_mul_ps( diff, estimate ), estimate ) ); - } - - friend Vec4 Min( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( _mm_min_ps( left.m_v, right.m_v ) ); - } - - friend Vec4 Max( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( _mm_max_ps( left.m_v, right.m_v ) ); - } - - friend Vec4 Truncate( Vec4::Arg v ) - { -#if ( SQUISH_USE_SSE == 1 ) - // convert to ints - __m128 input = v.m_v; - __m64 lo = _mm_cvttps_pi32( input ); - __m64 hi = _mm_cvttps_pi32( _mm_movehl_ps( input, input ) ); - - // convert to floats - __m128 part = _mm_movelh_ps( input, _mm_cvtpi32_ps( input, hi ) ); - __m128 truncated = _mm_cvtpi32_ps( part, lo ); - - // clear out the MMX multimedia state to allow FP calls later - _mm_empty(); - return Vec4( truncated ); -#else - // use SSE2 instructions - return Vec4( _mm_cvtepi32_ps( _mm_cvttps_epi32( v.m_v ) ) ); -#endif - } - - friend bool CompareAnyLessThan( Vec4::Arg left, Vec4::Arg right ) - { - __m128 bits = _mm_cmplt_ps( left.m_v, right.m_v ); - int value = _mm_movemask_ps( bits ); - return value != 0; - } - -private: - __m128 m_v; -}; - -} // namespace squish - -#endif // ndef SQUISH_SIMD_SSE_H diff --git a/thirdparty/squish/simd_ve.h b/thirdparty/squish/simd_ve.h deleted file mode 100644 index 08a1537503..0000000000 --- a/thirdparty/squish/simd_ve.h +++ /dev/null @@ -1,166 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_SIMD_VE_H -#define SQUISH_SIMD_VE_H - -#include <altivec.h> -#undef bool - -namespace squish { - -#define VEC4_CONST( X ) Vec4( ( vector float ){ X } ) - -class Vec4 -{ -public: - typedef Vec4 Arg; - - Vec4() {} - - explicit Vec4( vector float v ) : m_v( v ) {} - - Vec4( Vec4 const& arg ) : m_v( arg.m_v ) {} - - Vec4& operator=( Vec4 const& arg ) - { - m_v = arg.m_v; - return *this; - } - - explicit Vec4( float s ) - { - union { vector float v; float c[4]; } u; - u.c[0] = s; - u.c[1] = s; - u.c[2] = s; - u.c[3] = s; - m_v = u.v; - } - - Vec4( float x, float y, float z, float w ) - { - union { vector float v; float c[4]; } u; - u.c[0] = x; - u.c[1] = y; - u.c[2] = z; - u.c[3] = w; - m_v = u.v; - } - - Vec3 GetVec3() const - { - union { vector float v; float c[4]; } u; - u.v = m_v; - return Vec3( u.c[0], u.c[1], u.c[2] ); - } - - Vec4 SplatX() const { return Vec4( vec_splat( m_v, 0 ) ); } - Vec4 SplatY() const { return Vec4( vec_splat( m_v, 1 ) ); } - Vec4 SplatZ() const { return Vec4( vec_splat( m_v, 2 ) ); } - Vec4 SplatW() const { return Vec4( vec_splat( m_v, 3 ) ); } - - Vec4& operator+=( Arg v ) - { - m_v = vec_add( m_v, v.m_v ); - return *this; - } - - Vec4& operator-=( Arg v ) - { - m_v = vec_sub( m_v, v.m_v ); - return *this; - } - - Vec4& operator*=( Arg v ) - { - m_v = vec_madd( m_v, v.m_v, ( vector float ){ -0.0f } ); - return *this; - } - - friend Vec4 operator+( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( vec_add( left.m_v, right.m_v ) ); - } - - friend Vec4 operator-( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( vec_sub( left.m_v, right.m_v ) ); - } - - friend Vec4 operator*( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( vec_madd( left.m_v, right.m_v, ( vector float ){ -0.0f } ) ); - } - - //! Returns a*b + c - friend Vec4 MultiplyAdd( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) - { - return Vec4( vec_madd( a.m_v, b.m_v, c.m_v ) ); - } - - //! Returns -( a*b - c ) - friend Vec4 NegativeMultiplySubtract( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) - { - return Vec4( vec_nmsub( a.m_v, b.m_v, c.m_v ) ); - } - - friend Vec4 Reciprocal( Vec4::Arg v ) - { - // get the reciprocal estimate - vector float estimate = vec_re( v.m_v ); - - // one round of Newton-Rhaphson refinement - vector float diff = vec_nmsub( estimate, v.m_v, ( vector float ){ 1.0f } ); - return Vec4( vec_madd( diff, estimate, estimate ) ); - } - - friend Vec4 Min( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( vec_min( left.m_v, right.m_v ) ); - } - - friend Vec4 Max( Vec4::Arg left, Vec4::Arg right ) - { - return Vec4( vec_max( left.m_v, right.m_v ) ); - } - - friend Vec4 Truncate( Vec4::Arg v ) - { - return Vec4( vec_trunc( v.m_v ) ); - } - - friend bool CompareAnyLessThan( Vec4::Arg left, Vec4::Arg right ) - { - return vec_any_lt( left.m_v, right.m_v ) != 0; - } - -private: - vector float m_v; -}; - -} // namespace squish - -#endif // ndef SQUISH_SIMD_VE_H diff --git a/thirdparty/squish/singlecolourfit.cpp b/thirdparty/squish/singlecolourfit.cpp deleted file mode 100644 index cef0ebc410..0000000000 --- a/thirdparty/squish/singlecolourfit.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 "singlecolourfit.h" -#include "colourset.h" -#include "colourblock.h" - -namespace squish { - -struct SourceBlock -{ - u8 start; - u8 end; - u8 error; -}; - -struct SingleColourLookup -{ - SourceBlock sources[2]; -}; - -#include "singlecolourlookup.inl" - -static int FloatToInt( float a, int limit ) -{ - // use ANSI round-to-zero behaviour to get round-to-nearest - int i = ( int )( a + 0.5f ); - - // clamp to the limit - if( i < 0 ) - i = 0; - else if( i > limit ) - i = limit; - - // done - return i; -} - -SingleColourFit::SingleColourFit( ColourSet const* colours, int flags ) - : ColourFit( colours, flags ) -{ - // grab the single colour - Vec3 const* values = m_colours->GetPoints(); - m_colour[0] = ( u8 )FloatToInt( 255.0f*values->X(), 255 ); - m_colour[1] = ( u8 )FloatToInt( 255.0f*values->Y(), 255 ); - m_colour[2] = ( u8 )FloatToInt( 255.0f*values->Z(), 255 ); - - // initialise the best error - m_besterror = INT_MAX; -} - -void SingleColourFit::Compress3( void* block ) -{ - // build the table of lookups - SingleColourLookup const* const lookups[] = - { - lookup_5_3, - lookup_6_3, - lookup_5_3 - }; - - // find the best end-points and index - ComputeEndPoints( lookups ); - - // build the block if we win - if( m_error < m_besterror ) - { - // remap the indices - u8 indices[16]; - m_colours->RemapIndices( &m_index, indices ); - - // save the block - WriteColourBlock3( m_start, m_end, indices, block ); - - // save the error - m_besterror = m_error; - } -} - -void SingleColourFit::Compress4( void* block ) -{ - // build the table of lookups - SingleColourLookup const* const lookups[] = - { - lookup_5_4, - lookup_6_4, - lookup_5_4 - }; - - // find the best end-points and index - ComputeEndPoints( lookups ); - - // build the block if we win - if( m_error < m_besterror ) - { - // remap the indices - u8 indices[16]; - m_colours->RemapIndices( &m_index, indices ); - - // save the block - WriteColourBlock4( m_start, m_end, indices, block ); - - // save the error - m_besterror = m_error; - } -} - -void SingleColourFit::ComputeEndPoints( SingleColourLookup const* const* lookups ) -{ - // check each index combination (endpoint or intermediate) - m_error = INT_MAX; - for( int index = 0; index < 2; ++index ) - { - // check the error for this codebook index - SourceBlock const* sources[3]; - int error = 0; - for( int channel = 0; channel < 3; ++channel ) - { - // grab the lookup table and index for this channel - SingleColourLookup const* lookup = lookups[channel]; - int target = m_colour[channel]; - - // store a pointer to the source for this channel - sources[channel] = lookup[target].sources + index; - - // accumulate the error - int diff = sources[channel]->error; - error += diff*diff; - } - - // keep it if the error is lower - if( error < m_error ) - { - m_start = Vec3( - ( float )sources[0]->start/31.0f, - ( float )sources[1]->start/63.0f, - ( float )sources[2]->start/31.0f - ); - m_end = Vec3( - ( float )sources[0]->end/31.0f, - ( float )sources[1]->end/63.0f, - ( float )sources[2]->end/31.0f - ); - m_index = ( u8 )( 2*index ); - m_error = error; - } - } -} - -} // namespace squish diff --git a/thirdparty/squish/singlecolourfit.h b/thirdparty/squish/singlecolourfit.h deleted file mode 100644 index 974ce77256..0000000000 --- a/thirdparty/squish/singlecolourfit.h +++ /dev/null @@ -1,58 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_SINGLECOLOURFIT_H -#define SQUISH_SINGLECOLOURFIT_H - -#include "squish.h" -#include "colourfit.h" - -namespace squish { - -class ColourSet; -struct SingleColourLookup; - -class SingleColourFit : public ColourFit -{ -public: - SingleColourFit( ColourSet const* colours, int flags ); - -private: - virtual void Compress3( void* block ); - virtual void Compress4( void* block ); - - void ComputeEndPoints( SingleColourLookup const* const* lookups ); - - u8 m_colour[3]; - Vec3 m_start; - Vec3 m_end; - u8 m_index; - int m_error; - int m_besterror; -}; - -} // namespace squish - -#endif // ndef SQUISH_SINGLECOLOURFIT_H diff --git a/thirdparty/squish/singlecolourlookup.inl b/thirdparty/squish/singlecolourlookup.inl deleted file mode 100644 index 5b44a1e5e6..0000000000 --- a/thirdparty/squish/singlecolourlookup.inl +++ /dev/null @@ -1,1064 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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. - - -------------------------------------------------------------------------- */ - -static SingleColourLookup const lookup_5_3[] = -{ - { { { 0, 0, 0 }, { 0, 0, 0 } } }, - { { { 0, 0, 1 }, { 0, 0, 1 } } }, - { { { 0, 0, 2 }, { 0, 0, 2 } } }, - { { { 0, 0, 3 }, { 0, 1, 1 } } }, - { { { 0, 0, 4 }, { 0, 1, 0 } } }, - { { { 1, 0, 3 }, { 0, 1, 1 } } }, - { { { 1, 0, 2 }, { 0, 1, 2 } } }, - { { { 1, 0, 1 }, { 0, 2, 1 } } }, - { { { 1, 0, 0 }, { 0, 2, 0 } } }, - { { { 1, 0, 1 }, { 0, 2, 1 } } }, - { { { 1, 0, 2 }, { 0, 2, 2 } } }, - { { { 1, 0, 3 }, { 0, 3, 1 } } }, - { { { 1, 0, 4 }, { 0, 3, 0 } } }, - { { { 2, 0, 3 }, { 0, 3, 1 } } }, - { { { 2, 0, 2 }, { 0, 3, 2 } } }, - { { { 2, 0, 1 }, { 0, 4, 1 } } }, - { { { 2, 0, 0 }, { 0, 4, 0 } } }, - { { { 2, 0, 1 }, { 0, 4, 1 } } }, - { { { 2, 0, 2 }, { 0, 4, 2 } } }, - { { { 2, 0, 3 }, { 0, 5, 1 } } }, - { { { 2, 0, 4 }, { 0, 5, 0 } } }, - { { { 3, 0, 3 }, { 0, 5, 1 } } }, - { { { 3, 0, 2 }, { 0, 5, 2 } } }, - { { { 3, 0, 1 }, { 0, 6, 1 } } }, - { { { 3, 0, 0 }, { 0, 6, 0 } } }, - { { { 3, 0, 1 }, { 0, 6, 1 } } }, - { { { 3, 0, 2 }, { 0, 6, 2 } } }, - { { { 3, 0, 3 }, { 0, 7, 1 } } }, - { { { 3, 0, 4 }, { 0, 7, 0 } } }, - { { { 4, 0, 4 }, { 0, 7, 1 } } }, - { { { 4, 0, 3 }, { 0, 7, 2 } } }, - { { { 4, 0, 2 }, { 1, 7, 1 } } }, - { { { 4, 0, 1 }, { 1, 7, 0 } } }, - { { { 4, 0, 0 }, { 0, 8, 0 } } }, - { { { 4, 0, 1 }, { 0, 8, 1 } } }, - { { { 4, 0, 2 }, { 2, 7, 1 } } }, - { { { 4, 0, 3 }, { 2, 7, 0 } } }, - { { { 4, 0, 4 }, { 0, 9, 0 } } }, - { { { 5, 0, 3 }, { 0, 9, 1 } } }, - { { { 5, 0, 2 }, { 3, 7, 1 } } }, - { { { 5, 0, 1 }, { 3, 7, 0 } } }, - { { { 5, 0, 0 }, { 0, 10, 0 } } }, - { { { 5, 0, 1 }, { 0, 10, 1 } } }, - { { { 5, 0, 2 }, { 0, 10, 2 } } }, - { { { 5, 0, 3 }, { 0, 11, 1 } } }, - { { { 5, 0, 4 }, { 0, 11, 0 } } }, - { { { 6, 0, 3 }, { 0, 11, 1 } } }, - { { { 6, 0, 2 }, { 0, 11, 2 } } }, - { { { 6, 0, 1 }, { 0, 12, 1 } } }, - { { { 6, 0, 0 }, { 0, 12, 0 } } }, - { { { 6, 0, 1 }, { 0, 12, 1 } } }, - { { { 6, 0, 2 }, { 0, 12, 2 } } }, - { { { 6, 0, 3 }, { 0, 13, 1 } } }, - { { { 6, 0, 4 }, { 0, 13, 0 } } }, - { { { 7, 0, 3 }, { 0, 13, 1 } } }, - { { { 7, 0, 2 }, { 0, 13, 2 } } }, - { { { 7, 0, 1 }, { 0, 14, 1 } } }, - { { { 7, 0, 0 }, { 0, 14, 0 } } }, - { { { 7, 0, 1 }, { 0, 14, 1 } } }, - { { { 7, 0, 2 }, { 0, 14, 2 } } }, - { { { 7, 0, 3 }, { 0, 15, 1 } } }, - { { { 7, 0, 4 }, { 0, 15, 0 } } }, - { { { 8, 0, 4 }, { 0, 15, 1 } } }, - { { { 8, 0, 3 }, { 0, 15, 2 } } }, - { { { 8, 0, 2 }, { 1, 15, 1 } } }, - { { { 8, 0, 1 }, { 1, 15, 0 } } }, - { { { 8, 0, 0 }, { 0, 16, 0 } } }, - { { { 8, 0, 1 }, { 0, 16, 1 } } }, - { { { 8, 0, 2 }, { 2, 15, 1 } } }, - { { { 8, 0, 3 }, { 2, 15, 0 } } }, - { { { 8, 0, 4 }, { 0, 17, 0 } } }, - { { { 9, 0, 3 }, { 0, 17, 1 } } }, - { { { 9, 0, 2 }, { 3, 15, 1 } } }, - { { { 9, 0, 1 }, { 3, 15, 0 } } }, - { { { 9, 0, 0 }, { 0, 18, 0 } } }, - { { { 9, 0, 1 }, { 0, 18, 1 } } }, - { { { 9, 0, 2 }, { 0, 18, 2 } } }, - { { { 9, 0, 3 }, { 0, 19, 1 } } }, - { { { 9, 0, 4 }, { 0, 19, 0 } } }, - { { { 10, 0, 3 }, { 0, 19, 1 } } }, - { { { 10, 0, 2 }, { 0, 19, 2 } } }, - { { { 10, 0, 1 }, { 0, 20, 1 } } }, - { { { 10, 0, 0 }, { 0, 20, 0 } } }, - { { { 10, 0, 1 }, { 0, 20, 1 } } }, - { { { 10, 0, 2 }, { 0, 20, 2 } } }, - { { { 10, 0, 3 }, { 0, 21, 1 } } }, - { { { 10, 0, 4 }, { 0, 21, 0 } } }, - { { { 11, 0, 3 }, { 0, 21, 1 } } }, - { { { 11, 0, 2 }, { 0, 21, 2 } } }, - { { { 11, 0, 1 }, { 0, 22, 1 } } }, - { { { 11, 0, 0 }, { 0, 22, 0 } } }, - { { { 11, 0, 1 }, { 0, 22, 1 } } }, - { { { 11, 0, 2 }, { 0, 22, 2 } } }, - { { { 11, 0, 3 }, { 0, 23, 1 } } }, - { { { 11, 0, 4 }, { 0, 23, 0 } } }, - { { { 12, 0, 4 }, { 0, 23, 1 } } }, - { { { 12, 0, 3 }, { 0, 23, 2 } } }, - { { { 12, 0, 2 }, { 1, 23, 1 } } }, - { { { 12, 0, 1 }, { 1, 23, 0 } } }, - { { { 12, 0, 0 }, { 0, 24, 0 } } }, - { { { 12, 0, 1 }, { 0, 24, 1 } } }, - { { { 12, 0, 2 }, { 2, 23, 1 } } }, - { { { 12, 0, 3 }, { 2, 23, 0 } } }, - { { { 12, 0, 4 }, { 0, 25, 0 } } }, - { { { 13, 0, 3 }, { 0, 25, 1 } } }, - { { { 13, 0, 2 }, { 3, 23, 1 } } }, - { { { 13, 0, 1 }, { 3, 23, 0 } } }, - { { { 13, 0, 0 }, { 0, 26, 0 } } }, - { { { 13, 0, 1 }, { 0, 26, 1 } } }, - { { { 13, 0, 2 }, { 0, 26, 2 } } }, - { { { 13, 0, 3 }, { 0, 27, 1 } } }, - { { { 13, 0, 4 }, { 0, 27, 0 } } }, - { { { 14, 0, 3 }, { 0, 27, 1 } } }, - { { { 14, 0, 2 }, { 0, 27, 2 } } }, - { { { 14, 0, 1 }, { 0, 28, 1 } } }, - { { { 14, 0, 0 }, { 0, 28, 0 } } }, - { { { 14, 0, 1 }, { 0, 28, 1 } } }, - { { { 14, 0, 2 }, { 0, 28, 2 } } }, - { { { 14, 0, 3 }, { 0, 29, 1 } } }, - { { { 14, 0, 4 }, { 0, 29, 0 } } }, - { { { 15, 0, 3 }, { 0, 29, 1 } } }, - { { { 15, 0, 2 }, { 0, 29, 2 } } }, - { { { 15, 0, 1 }, { 0, 30, 1 } } }, - { { { 15, 0, 0 }, { 0, 30, 0 } } }, - { { { 15, 0, 1 }, { 0, 30, 1 } } }, - { { { 15, 0, 2 }, { 0, 30, 2 } } }, - { { { 15, 0, 3 }, { 0, 31, 1 } } }, - { { { 15, 0, 4 }, { 0, 31, 0 } } }, - { { { 16, 0, 4 }, { 0, 31, 1 } } }, - { { { 16, 0, 3 }, { 0, 31, 2 } } }, - { { { 16, 0, 2 }, { 1, 31, 1 } } }, - { { { 16, 0, 1 }, { 1, 31, 0 } } }, - { { { 16, 0, 0 }, { 4, 28, 0 } } }, - { { { 16, 0, 1 }, { 4, 28, 1 } } }, - { { { 16, 0, 2 }, { 2, 31, 1 } } }, - { { { 16, 0, 3 }, { 2, 31, 0 } } }, - { { { 16, 0, 4 }, { 4, 29, 0 } } }, - { { { 17, 0, 3 }, { 4, 29, 1 } } }, - { { { 17, 0, 2 }, { 3, 31, 1 } } }, - { { { 17, 0, 1 }, { 3, 31, 0 } } }, - { { { 17, 0, 0 }, { 4, 30, 0 } } }, - { { { 17, 0, 1 }, { 4, 30, 1 } } }, - { { { 17, 0, 2 }, { 4, 30, 2 } } }, - { { { 17, 0, 3 }, { 4, 31, 1 } } }, - { { { 17, 0, 4 }, { 4, 31, 0 } } }, - { { { 18, 0, 3 }, { 4, 31, 1 } } }, - { { { 18, 0, 2 }, { 4, 31, 2 } } }, - { { { 18, 0, 1 }, { 5, 31, 1 } } }, - { { { 18, 0, 0 }, { 5, 31, 0 } } }, - { { { 18, 0, 1 }, { 5, 31, 1 } } }, - { { { 18, 0, 2 }, { 5, 31, 2 } } }, - { { { 18, 0, 3 }, { 6, 31, 1 } } }, - { { { 18, 0, 4 }, { 6, 31, 0 } } }, - { { { 19, 0, 3 }, { 6, 31, 1 } } }, - { { { 19, 0, 2 }, { 6, 31, 2 } } }, - { { { 19, 0, 1 }, { 7, 31, 1 } } }, - { { { 19, 0, 0 }, { 7, 31, 0 } } }, - { { { 19, 0, 1 }, { 7, 31, 1 } } }, - { { { 19, 0, 2 }, { 7, 31, 2 } } }, - { { { 19, 0, 3 }, { 8, 31, 1 } } }, - { { { 19, 0, 4 }, { 8, 31, 0 } } }, - { { { 20, 0, 4 }, { 8, 31, 1 } } }, - { { { 20, 0, 3 }, { 8, 31, 2 } } }, - { { { 20, 0, 2 }, { 9, 31, 1 } } }, - { { { 20, 0, 1 }, { 9, 31, 0 } } }, - { { { 20, 0, 0 }, { 12, 28, 0 } } }, - { { { 20, 0, 1 }, { 12, 28, 1 } } }, - { { { 20, 0, 2 }, { 10, 31, 1 } } }, - { { { 20, 0, 3 }, { 10, 31, 0 } } }, - { { { 20, 0, 4 }, { 12, 29, 0 } } }, - { { { 21, 0, 3 }, { 12, 29, 1 } } }, - { { { 21, 0, 2 }, { 11, 31, 1 } } }, - { { { 21, 0, 1 }, { 11, 31, 0 } } }, - { { { 21, 0, 0 }, { 12, 30, 0 } } }, - { { { 21, 0, 1 }, { 12, 30, 1 } } }, - { { { 21, 0, 2 }, { 12, 30, 2 } } }, - { { { 21, 0, 3 }, { 12, 31, 1 } } }, - { { { 21, 0, 4 }, { 12, 31, 0 } } }, - { { { 22, 0, 3 }, { 12, 31, 1 } } }, - { { { 22, 0, 2 }, { 12, 31, 2 } } }, - { { { 22, 0, 1 }, { 13, 31, 1 } } }, - { { { 22, 0, 0 }, { 13, 31, 0 } } }, - { { { 22, 0, 1 }, { 13, 31, 1 } } }, - { { { 22, 0, 2 }, { 13, 31, 2 } } }, - { { { 22, 0, 3 }, { 14, 31, 1 } } }, - { { { 22, 0, 4 }, { 14, 31, 0 } } }, - { { { 23, 0, 3 }, { 14, 31, 1 } } }, - { { { 23, 0, 2 }, { 14, 31, 2 } } }, - { { { 23, 0, 1 }, { 15, 31, 1 } } }, - { { { 23, 0, 0 }, { 15, 31, 0 } } }, - { { { 23, 0, 1 }, { 15, 31, 1 } } }, - { { { 23, 0, 2 }, { 15, 31, 2 } } }, - { { { 23, 0, 3 }, { 16, 31, 1 } } }, - { { { 23, 0, 4 }, { 16, 31, 0 } } }, - { { { 24, 0, 4 }, { 16, 31, 1 } } }, - { { { 24, 0, 3 }, { 16, 31, 2 } } }, - { { { 24, 0, 2 }, { 17, 31, 1 } } }, - { { { 24, 0, 1 }, { 17, 31, 0 } } }, - { { { 24, 0, 0 }, { 20, 28, 0 } } }, - { { { 24, 0, 1 }, { 20, 28, 1 } } }, - { { { 24, 0, 2 }, { 18, 31, 1 } } }, - { { { 24, 0, 3 }, { 18, 31, 0 } } }, - { { { 24, 0, 4 }, { 20, 29, 0 } } }, - { { { 25, 0, 3 }, { 20, 29, 1 } } }, - { { { 25, 0, 2 }, { 19, 31, 1 } } }, - { { { 25, 0, 1 }, { 19, 31, 0 } } }, - { { { 25, 0, 0 }, { 20, 30, 0 } } }, - { { { 25, 0, 1 }, { 20, 30, 1 } } }, - { { { 25, 0, 2 }, { 20, 30, 2 } } }, - { { { 25, 0, 3 }, { 20, 31, 1 } } }, - { { { 25, 0, 4 }, { 20, 31, 0 } } }, - { { { 26, 0, 3 }, { 20, 31, 1 } } }, - { { { 26, 0, 2 }, { 20, 31, 2 } } }, - { { { 26, 0, 1 }, { 21, 31, 1 } } }, - { { { 26, 0, 0 }, { 21, 31, 0 } } }, - { { { 26, 0, 1 }, { 21, 31, 1 } } }, - { { { 26, 0, 2 }, { 21, 31, 2 } } }, - { { { 26, 0, 3 }, { 22, 31, 1 } } }, - { { { 26, 0, 4 }, { 22, 31, 0 } } }, - { { { 27, 0, 3 }, { 22, 31, 1 } } }, - { { { 27, 0, 2 }, { 22, 31, 2 } } }, - { { { 27, 0, 1 }, { 23, 31, 1 } } }, - { { { 27, 0, 0 }, { 23, 31, 0 } } }, - { { { 27, 0, 1 }, { 23, 31, 1 } } }, - { { { 27, 0, 2 }, { 23, 31, 2 } } }, - { { { 27, 0, 3 }, { 24, 31, 1 } } }, - { { { 27, 0, 4 }, { 24, 31, 0 } } }, - { { { 28, 0, 4 }, { 24, 31, 1 } } }, - { { { 28, 0, 3 }, { 24, 31, 2 } } }, - { { { 28, 0, 2 }, { 25, 31, 1 } } }, - { { { 28, 0, 1 }, { 25, 31, 0 } } }, - { { { 28, 0, 0 }, { 28, 28, 0 } } }, - { { { 28, 0, 1 }, { 28, 28, 1 } } }, - { { { 28, 0, 2 }, { 26, 31, 1 } } }, - { { { 28, 0, 3 }, { 26, 31, 0 } } }, - { { { 28, 0, 4 }, { 28, 29, 0 } } }, - { { { 29, 0, 3 }, { 28, 29, 1 } } }, - { { { 29, 0, 2 }, { 27, 31, 1 } } }, - { { { 29, 0, 1 }, { 27, 31, 0 } } }, - { { { 29, 0, 0 }, { 28, 30, 0 } } }, - { { { 29, 0, 1 }, { 28, 30, 1 } } }, - { { { 29, 0, 2 }, { 28, 30, 2 } } }, - { { { 29, 0, 3 }, { 28, 31, 1 } } }, - { { { 29, 0, 4 }, { 28, 31, 0 } } }, - { { { 30, 0, 3 }, { 28, 31, 1 } } }, - { { { 30, 0, 2 }, { 28, 31, 2 } } }, - { { { 30, 0, 1 }, { 29, 31, 1 } } }, - { { { 30, 0, 0 }, { 29, 31, 0 } } }, - { { { 30, 0, 1 }, { 29, 31, 1 } } }, - { { { 30, 0, 2 }, { 29, 31, 2 } } }, - { { { 30, 0, 3 }, { 30, 31, 1 } } }, - { { { 30, 0, 4 }, { 30, 31, 0 } } }, - { { { 31, 0, 3 }, { 30, 31, 1 } } }, - { { { 31, 0, 2 }, { 30, 31, 2 } } }, - { { { 31, 0, 1 }, { 31, 31, 1 } } }, - { { { 31, 0, 0 }, { 31, 31, 0 } } } -}; - -static SingleColourLookup const lookup_6_3[] = -{ - { { { 0, 0, 0 }, { 0, 0, 0 } } }, - { { { 0, 0, 1 }, { 0, 1, 1 } } }, - { { { 0, 0, 2 }, { 0, 1, 0 } } }, - { { { 1, 0, 1 }, { 0, 2, 1 } } }, - { { { 1, 0, 0 }, { 0, 2, 0 } } }, - { { { 1, 0, 1 }, { 0, 3, 1 } } }, - { { { 1, 0, 2 }, { 0, 3, 0 } } }, - { { { 2, 0, 1 }, { 0, 4, 1 } } }, - { { { 2, 0, 0 }, { 0, 4, 0 } } }, - { { { 2, 0, 1 }, { 0, 5, 1 } } }, - { { { 2, 0, 2 }, { 0, 5, 0 } } }, - { { { 3, 0, 1 }, { 0, 6, 1 } } }, - { { { 3, 0, 0 }, { 0, 6, 0 } } }, - { { { 3, 0, 1 }, { 0, 7, 1 } } }, - { { { 3, 0, 2 }, { 0, 7, 0 } } }, - { { { 4, 0, 1 }, { 0, 8, 1 } } }, - { { { 4, 0, 0 }, { 0, 8, 0 } } }, - { { { 4, 0, 1 }, { 0, 9, 1 } } }, - { { { 4, 0, 2 }, { 0, 9, 0 } } }, - { { { 5, 0, 1 }, { 0, 10, 1 } } }, - { { { 5, 0, 0 }, { 0, 10, 0 } } }, - { { { 5, 0, 1 }, { 0, 11, 1 } } }, - { { { 5, 0, 2 }, { 0, 11, 0 } } }, - { { { 6, 0, 1 }, { 0, 12, 1 } } }, - { { { 6, 0, 0 }, { 0, 12, 0 } } }, - { { { 6, 0, 1 }, { 0, 13, 1 } } }, - { { { 6, 0, 2 }, { 0, 13, 0 } } }, - { { { 7, 0, 1 }, { 0, 14, 1 } } }, - { { { 7, 0, 0 }, { 0, 14, 0 } } }, - { { { 7, 0, 1 }, { 0, 15, 1 } } }, - { { { 7, 0, 2 }, { 0, 15, 0 } } }, - { { { 8, 0, 1 }, { 0, 16, 1 } } }, - { { { 8, 0, 0 }, { 0, 16, 0 } } }, - { { { 8, 0, 1 }, { 0, 17, 1 } } }, - { { { 8, 0, 2 }, { 0, 17, 0 } } }, - { { { 9, 0, 1 }, { 0, 18, 1 } } }, - { { { 9, 0, 0 }, { 0, 18, 0 } } }, - { { { 9, 0, 1 }, { 0, 19, 1 } } }, - { { { 9, 0, 2 }, { 0, 19, 0 } } }, - { { { 10, 0, 1 }, { 0, 20, 1 } } }, - { { { 10, 0, 0 }, { 0, 20, 0 } } }, - { { { 10, 0, 1 }, { 0, 21, 1 } } }, - { { { 10, 0, 2 }, { 0, 21, 0 } } }, - { { { 11, 0, 1 }, { 0, 22, 1 } } }, - { { { 11, 0, 0 }, { 0, 22, 0 } } }, - { { { 11, 0, 1 }, { 0, 23, 1 } } }, - { { { 11, 0, 2 }, { 0, 23, 0 } } }, - { { { 12, 0, 1 }, { 0, 24, 1 } } }, - { { { 12, 0, 0 }, { 0, 24, 0 } } }, - { { { 12, 0, 1 }, { 0, 25, 1 } } }, - { { { 12, 0, 2 }, { 0, 25, 0 } } }, - { { { 13, 0, 1 }, { 0, 26, 1 } } }, - { { { 13, 0, 0 }, { 0, 26, 0 } } }, - { { { 13, 0, 1 }, { 0, 27, 1 } } }, - { { { 13, 0, 2 }, { 0, 27, 0 } } }, - { { { 14, 0, 1 }, { 0, 28, 1 } } }, - { { { 14, 0, 0 }, { 0, 28, 0 } } }, - { { { 14, 0, 1 }, { 0, 29, 1 } } }, - { { { 14, 0, 2 }, { 0, 29, 0 } } }, - { { { 15, 0, 1 }, { 0, 30, 1 } } }, - { { { 15, 0, 0 }, { 0, 30, 0 } } }, - { { { 15, 0, 1 }, { 0, 31, 1 } } }, - { { { 15, 0, 2 }, { 0, 31, 0 } } }, - { { { 16, 0, 2 }, { 1, 31, 1 } } }, - { { { 16, 0, 1 }, { 1, 31, 0 } } }, - { { { 16, 0, 0 }, { 0, 32, 0 } } }, - { { { 16, 0, 1 }, { 2, 31, 0 } } }, - { { { 16, 0, 2 }, { 0, 33, 0 } } }, - { { { 17, 0, 1 }, { 3, 31, 0 } } }, - { { { 17, 0, 0 }, { 0, 34, 0 } } }, - { { { 17, 0, 1 }, { 4, 31, 0 } } }, - { { { 17, 0, 2 }, { 0, 35, 0 } } }, - { { { 18, 0, 1 }, { 5, 31, 0 } } }, - { { { 18, 0, 0 }, { 0, 36, 0 } } }, - { { { 18, 0, 1 }, { 6, 31, 0 } } }, - { { { 18, 0, 2 }, { 0, 37, 0 } } }, - { { { 19, 0, 1 }, { 7, 31, 0 } } }, - { { { 19, 0, 0 }, { 0, 38, 0 } } }, - { { { 19, 0, 1 }, { 8, 31, 0 } } }, - { { { 19, 0, 2 }, { 0, 39, 0 } } }, - { { { 20, 0, 1 }, { 9, 31, 0 } } }, - { { { 20, 0, 0 }, { 0, 40, 0 } } }, - { { { 20, 0, 1 }, { 10, 31, 0 } } }, - { { { 20, 0, 2 }, { 0, 41, 0 } } }, - { { { 21, 0, 1 }, { 11, 31, 0 } } }, - { { { 21, 0, 0 }, { 0, 42, 0 } } }, - { { { 21, 0, 1 }, { 12, 31, 0 } } }, - { { { 21, 0, 2 }, { 0, 43, 0 } } }, - { { { 22, 0, 1 }, { 13, 31, 0 } } }, - { { { 22, 0, 0 }, { 0, 44, 0 } } }, - { { { 22, 0, 1 }, { 14, 31, 0 } } }, - { { { 22, 0, 2 }, { 0, 45, 0 } } }, - { { { 23, 0, 1 }, { 15, 31, 0 } } }, - { { { 23, 0, 0 }, { 0, 46, 0 } } }, - { { { 23, 0, 1 }, { 0, 47, 1 } } }, - { { { 23, 0, 2 }, { 0, 47, 0 } } }, - { { { 24, 0, 1 }, { 0, 48, 1 } } }, - { { { 24, 0, 0 }, { 0, 48, 0 } } }, - { { { 24, 0, 1 }, { 0, 49, 1 } } }, - { { { 24, 0, 2 }, { 0, 49, 0 } } }, - { { { 25, 0, 1 }, { 0, 50, 1 } } }, - { { { 25, 0, 0 }, { 0, 50, 0 } } }, - { { { 25, 0, 1 }, { 0, 51, 1 } } }, - { { { 25, 0, 2 }, { 0, 51, 0 } } }, - { { { 26, 0, 1 }, { 0, 52, 1 } } }, - { { { 26, 0, 0 }, { 0, 52, 0 } } }, - { { { 26, 0, 1 }, { 0, 53, 1 } } }, - { { { 26, 0, 2 }, { 0, 53, 0 } } }, - { { { 27, 0, 1 }, { 0, 54, 1 } } }, - { { { 27, 0, 0 }, { 0, 54, 0 } } }, - { { { 27, 0, 1 }, { 0, 55, 1 } } }, - { { { 27, 0, 2 }, { 0, 55, 0 } } }, - { { { 28, 0, 1 }, { 0, 56, 1 } } }, - { { { 28, 0, 0 }, { 0, 56, 0 } } }, - { { { 28, 0, 1 }, { 0, 57, 1 } } }, - { { { 28, 0, 2 }, { 0, 57, 0 } } }, - { { { 29, 0, 1 }, { 0, 58, 1 } } }, - { { { 29, 0, 0 }, { 0, 58, 0 } } }, - { { { 29, 0, 1 }, { 0, 59, 1 } } }, - { { { 29, 0, 2 }, { 0, 59, 0 } } }, - { { { 30, 0, 1 }, { 0, 60, 1 } } }, - { { { 30, 0, 0 }, { 0, 60, 0 } } }, - { { { 30, 0, 1 }, { 0, 61, 1 } } }, - { { { 30, 0, 2 }, { 0, 61, 0 } } }, - { { { 31, 0, 1 }, { 0, 62, 1 } } }, - { { { 31, 0, 0 }, { 0, 62, 0 } } }, - { { { 31, 0, 1 }, { 0, 63, 1 } } }, - { { { 31, 0, 2 }, { 0, 63, 0 } } }, - { { { 32, 0, 2 }, { 1, 63, 1 } } }, - { { { 32, 0, 1 }, { 1, 63, 0 } } }, - { { { 32, 0, 0 }, { 16, 48, 0 } } }, - { { { 32, 0, 1 }, { 2, 63, 0 } } }, - { { { 32, 0, 2 }, { 16, 49, 0 } } }, - { { { 33, 0, 1 }, { 3, 63, 0 } } }, - { { { 33, 0, 0 }, { 16, 50, 0 } } }, - { { { 33, 0, 1 }, { 4, 63, 0 } } }, - { { { 33, 0, 2 }, { 16, 51, 0 } } }, - { { { 34, 0, 1 }, { 5, 63, 0 } } }, - { { { 34, 0, 0 }, { 16, 52, 0 } } }, - { { { 34, 0, 1 }, { 6, 63, 0 } } }, - { { { 34, 0, 2 }, { 16, 53, 0 } } }, - { { { 35, 0, 1 }, { 7, 63, 0 } } }, - { { { 35, 0, 0 }, { 16, 54, 0 } } }, - { { { 35, 0, 1 }, { 8, 63, 0 } } }, - { { { 35, 0, 2 }, { 16, 55, 0 } } }, - { { { 36, 0, 1 }, { 9, 63, 0 } } }, - { { { 36, 0, 0 }, { 16, 56, 0 } } }, - { { { 36, 0, 1 }, { 10, 63, 0 } } }, - { { { 36, 0, 2 }, { 16, 57, 0 } } }, - { { { 37, 0, 1 }, { 11, 63, 0 } } }, - { { { 37, 0, 0 }, { 16, 58, 0 } } }, - { { { 37, 0, 1 }, { 12, 63, 0 } } }, - { { { 37, 0, 2 }, { 16, 59, 0 } } }, - { { { 38, 0, 1 }, { 13, 63, 0 } } }, - { { { 38, 0, 0 }, { 16, 60, 0 } } }, - { { { 38, 0, 1 }, { 14, 63, 0 } } }, - { { { 38, 0, 2 }, { 16, 61, 0 } } }, - { { { 39, 0, 1 }, { 15, 63, 0 } } }, - { { { 39, 0, 0 }, { 16, 62, 0 } } }, - { { { 39, 0, 1 }, { 16, 63, 1 } } }, - { { { 39, 0, 2 }, { 16, 63, 0 } } }, - { { { 40, 0, 1 }, { 17, 63, 1 } } }, - { { { 40, 0, 0 }, { 17, 63, 0 } } }, - { { { 40, 0, 1 }, { 18, 63, 1 } } }, - { { { 40, 0, 2 }, { 18, 63, 0 } } }, - { { { 41, 0, 1 }, { 19, 63, 1 } } }, - { { { 41, 0, 0 }, { 19, 63, 0 } } }, - { { { 41, 0, 1 }, { 20, 63, 1 } } }, - { { { 41, 0, 2 }, { 20, 63, 0 } } }, - { { { 42, 0, 1 }, { 21, 63, 1 } } }, - { { { 42, 0, 0 }, { 21, 63, 0 } } }, - { { { 42, 0, 1 }, { 22, 63, 1 } } }, - { { { 42, 0, 2 }, { 22, 63, 0 } } }, - { { { 43, 0, 1 }, { 23, 63, 1 } } }, - { { { 43, 0, 0 }, { 23, 63, 0 } } }, - { { { 43, 0, 1 }, { 24, 63, 1 } } }, - { { { 43, 0, 2 }, { 24, 63, 0 } } }, - { { { 44, 0, 1 }, { 25, 63, 1 } } }, - { { { 44, 0, 0 }, { 25, 63, 0 } } }, - { { { 44, 0, 1 }, { 26, 63, 1 } } }, - { { { 44, 0, 2 }, { 26, 63, 0 } } }, - { { { 45, 0, 1 }, { 27, 63, 1 } } }, - { { { 45, 0, 0 }, { 27, 63, 0 } } }, - { { { 45, 0, 1 }, { 28, 63, 1 } } }, - { { { 45, 0, 2 }, { 28, 63, 0 } } }, - { { { 46, 0, 1 }, { 29, 63, 1 } } }, - { { { 46, 0, 0 }, { 29, 63, 0 } } }, - { { { 46, 0, 1 }, { 30, 63, 1 } } }, - { { { 46, 0, 2 }, { 30, 63, 0 } } }, - { { { 47, 0, 1 }, { 31, 63, 1 } } }, - { { { 47, 0, 0 }, { 31, 63, 0 } } }, - { { { 47, 0, 1 }, { 32, 63, 1 } } }, - { { { 47, 0, 2 }, { 32, 63, 0 } } }, - { { { 48, 0, 2 }, { 33, 63, 1 } } }, - { { { 48, 0, 1 }, { 33, 63, 0 } } }, - { { { 48, 0, 0 }, { 48, 48, 0 } } }, - { { { 48, 0, 1 }, { 34, 63, 0 } } }, - { { { 48, 0, 2 }, { 48, 49, 0 } } }, - { { { 49, 0, 1 }, { 35, 63, 0 } } }, - { { { 49, 0, 0 }, { 48, 50, 0 } } }, - { { { 49, 0, 1 }, { 36, 63, 0 } } }, - { { { 49, 0, 2 }, { 48, 51, 0 } } }, - { { { 50, 0, 1 }, { 37, 63, 0 } } }, - { { { 50, 0, 0 }, { 48, 52, 0 } } }, - { { { 50, 0, 1 }, { 38, 63, 0 } } }, - { { { 50, 0, 2 }, { 48, 53, 0 } } }, - { { { 51, 0, 1 }, { 39, 63, 0 } } }, - { { { 51, 0, 0 }, { 48, 54, 0 } } }, - { { { 51, 0, 1 }, { 40, 63, 0 } } }, - { { { 51, 0, 2 }, { 48, 55, 0 } } }, - { { { 52, 0, 1 }, { 41, 63, 0 } } }, - { { { 52, 0, 0 }, { 48, 56, 0 } } }, - { { { 52, 0, 1 }, { 42, 63, 0 } } }, - { { { 52, 0, 2 }, { 48, 57, 0 } } }, - { { { 53, 0, 1 }, { 43, 63, 0 } } }, - { { { 53, 0, 0 }, { 48, 58, 0 } } }, - { { { 53, 0, 1 }, { 44, 63, 0 } } }, - { { { 53, 0, 2 }, { 48, 59, 0 } } }, - { { { 54, 0, 1 }, { 45, 63, 0 } } }, - { { { 54, 0, 0 }, { 48, 60, 0 } } }, - { { { 54, 0, 1 }, { 46, 63, 0 } } }, - { { { 54, 0, 2 }, { 48, 61, 0 } } }, - { { { 55, 0, 1 }, { 47, 63, 0 } } }, - { { { 55, 0, 0 }, { 48, 62, 0 } } }, - { { { 55, 0, 1 }, { 48, 63, 1 } } }, - { { { 55, 0, 2 }, { 48, 63, 0 } } }, - { { { 56, 0, 1 }, { 49, 63, 1 } } }, - { { { 56, 0, 0 }, { 49, 63, 0 } } }, - { { { 56, 0, 1 }, { 50, 63, 1 } } }, - { { { 56, 0, 2 }, { 50, 63, 0 } } }, - { { { 57, 0, 1 }, { 51, 63, 1 } } }, - { { { 57, 0, 0 }, { 51, 63, 0 } } }, - { { { 57, 0, 1 }, { 52, 63, 1 } } }, - { { { 57, 0, 2 }, { 52, 63, 0 } } }, - { { { 58, 0, 1 }, { 53, 63, 1 } } }, - { { { 58, 0, 0 }, { 53, 63, 0 } } }, - { { { 58, 0, 1 }, { 54, 63, 1 } } }, - { { { 58, 0, 2 }, { 54, 63, 0 } } }, - { { { 59, 0, 1 }, { 55, 63, 1 } } }, - { { { 59, 0, 0 }, { 55, 63, 0 } } }, - { { { 59, 0, 1 }, { 56, 63, 1 } } }, - { { { 59, 0, 2 }, { 56, 63, 0 } } }, - { { { 60, 0, 1 }, { 57, 63, 1 } } }, - { { { 60, 0, 0 }, { 57, 63, 0 } } }, - { { { 60, 0, 1 }, { 58, 63, 1 } } }, - { { { 60, 0, 2 }, { 58, 63, 0 } } }, - { { { 61, 0, 1 }, { 59, 63, 1 } } }, - { { { 61, 0, 0 }, { 59, 63, 0 } } }, - { { { 61, 0, 1 }, { 60, 63, 1 } } }, - { { { 61, 0, 2 }, { 60, 63, 0 } } }, - { { { 62, 0, 1 }, { 61, 63, 1 } } }, - { { { 62, 0, 0 }, { 61, 63, 0 } } }, - { { { 62, 0, 1 }, { 62, 63, 1 } } }, - { { { 62, 0, 2 }, { 62, 63, 0 } } }, - { { { 63, 0, 1 }, { 63, 63, 1 } } }, - { { { 63, 0, 0 }, { 63, 63, 0 } } } -}; - -static SingleColourLookup const lookup_5_4[] = -{ - { { { 0, 0, 0 }, { 0, 0, 0 } } }, - { { { 0, 0, 1 }, { 0, 1, 1 } } }, - { { { 0, 0, 2 }, { 0, 1, 0 } } }, - { { { 0, 0, 3 }, { 0, 1, 1 } } }, - { { { 0, 0, 4 }, { 0, 2, 1 } } }, - { { { 1, 0, 3 }, { 0, 2, 0 } } }, - { { { 1, 0, 2 }, { 0, 2, 1 } } }, - { { { 1, 0, 1 }, { 0, 3, 1 } } }, - { { { 1, 0, 0 }, { 0, 3, 0 } } }, - { { { 1, 0, 1 }, { 1, 2, 1 } } }, - { { { 1, 0, 2 }, { 1, 2, 0 } } }, - { { { 1, 0, 3 }, { 0, 4, 0 } } }, - { { { 1, 0, 4 }, { 0, 5, 1 } } }, - { { { 2, 0, 3 }, { 0, 5, 0 } } }, - { { { 2, 0, 2 }, { 0, 5, 1 } } }, - { { { 2, 0, 1 }, { 0, 6, 1 } } }, - { { { 2, 0, 0 }, { 0, 6, 0 } } }, - { { { 2, 0, 1 }, { 2, 3, 1 } } }, - { { { 2, 0, 2 }, { 2, 3, 0 } } }, - { { { 2, 0, 3 }, { 0, 7, 0 } } }, - { { { 2, 0, 4 }, { 1, 6, 1 } } }, - { { { 3, 0, 3 }, { 1, 6, 0 } } }, - { { { 3, 0, 2 }, { 0, 8, 0 } } }, - { { { 3, 0, 1 }, { 0, 9, 1 } } }, - { { { 3, 0, 0 }, { 0, 9, 0 } } }, - { { { 3, 0, 1 }, { 0, 9, 1 } } }, - { { { 3, 0, 2 }, { 0, 10, 1 } } }, - { { { 3, 0, 3 }, { 0, 10, 0 } } }, - { { { 3, 0, 4 }, { 2, 7, 1 } } }, - { { { 4, 0, 4 }, { 2, 7, 0 } } }, - { { { 4, 0, 3 }, { 0, 11, 0 } } }, - { { { 4, 0, 2 }, { 1, 10, 1 } } }, - { { { 4, 0, 1 }, { 1, 10, 0 } } }, - { { { 4, 0, 0 }, { 0, 12, 0 } } }, - { { { 4, 0, 1 }, { 0, 13, 1 } } }, - { { { 4, 0, 2 }, { 0, 13, 0 } } }, - { { { 4, 0, 3 }, { 0, 13, 1 } } }, - { { { 4, 0, 4 }, { 0, 14, 1 } } }, - { { { 5, 0, 3 }, { 0, 14, 0 } } }, - { { { 5, 0, 2 }, { 2, 11, 1 } } }, - { { { 5, 0, 1 }, { 2, 11, 0 } } }, - { { { 5, 0, 0 }, { 0, 15, 0 } } }, - { { { 5, 0, 1 }, { 1, 14, 1 } } }, - { { { 5, 0, 2 }, { 1, 14, 0 } } }, - { { { 5, 0, 3 }, { 0, 16, 0 } } }, - { { { 5, 0, 4 }, { 0, 17, 1 } } }, - { { { 6, 0, 3 }, { 0, 17, 0 } } }, - { { { 6, 0, 2 }, { 0, 17, 1 } } }, - { { { 6, 0, 1 }, { 0, 18, 1 } } }, - { { { 6, 0, 0 }, { 0, 18, 0 } } }, - { { { 6, 0, 1 }, { 2, 15, 1 } } }, - { { { 6, 0, 2 }, { 2, 15, 0 } } }, - { { { 6, 0, 3 }, { 0, 19, 0 } } }, - { { { 6, 0, 4 }, { 1, 18, 1 } } }, - { { { 7, 0, 3 }, { 1, 18, 0 } } }, - { { { 7, 0, 2 }, { 0, 20, 0 } } }, - { { { 7, 0, 1 }, { 0, 21, 1 } } }, - { { { 7, 0, 0 }, { 0, 21, 0 } } }, - { { { 7, 0, 1 }, { 0, 21, 1 } } }, - { { { 7, 0, 2 }, { 0, 22, 1 } } }, - { { { 7, 0, 3 }, { 0, 22, 0 } } }, - { { { 7, 0, 4 }, { 2, 19, 1 } } }, - { { { 8, 0, 4 }, { 2, 19, 0 } } }, - { { { 8, 0, 3 }, { 0, 23, 0 } } }, - { { { 8, 0, 2 }, { 1, 22, 1 } } }, - { { { 8, 0, 1 }, { 1, 22, 0 } } }, - { { { 8, 0, 0 }, { 0, 24, 0 } } }, - { { { 8, 0, 1 }, { 0, 25, 1 } } }, - { { { 8, 0, 2 }, { 0, 25, 0 } } }, - { { { 8, 0, 3 }, { 0, 25, 1 } } }, - { { { 8, 0, 4 }, { 0, 26, 1 } } }, - { { { 9, 0, 3 }, { 0, 26, 0 } } }, - { { { 9, 0, 2 }, { 2, 23, 1 } } }, - { { { 9, 0, 1 }, { 2, 23, 0 } } }, - { { { 9, 0, 0 }, { 0, 27, 0 } } }, - { { { 9, 0, 1 }, { 1, 26, 1 } } }, - { { { 9, 0, 2 }, { 1, 26, 0 } } }, - { { { 9, 0, 3 }, { 0, 28, 0 } } }, - { { { 9, 0, 4 }, { 0, 29, 1 } } }, - { { { 10, 0, 3 }, { 0, 29, 0 } } }, - { { { 10, 0, 2 }, { 0, 29, 1 } } }, - { { { 10, 0, 1 }, { 0, 30, 1 } } }, - { { { 10, 0, 0 }, { 0, 30, 0 } } }, - { { { 10, 0, 1 }, { 2, 27, 1 } } }, - { { { 10, 0, 2 }, { 2, 27, 0 } } }, - { { { 10, 0, 3 }, { 0, 31, 0 } } }, - { { { 10, 0, 4 }, { 1, 30, 1 } } }, - { { { 11, 0, 3 }, { 1, 30, 0 } } }, - { { { 11, 0, 2 }, { 4, 24, 0 } } }, - { { { 11, 0, 1 }, { 1, 31, 1 } } }, - { { { 11, 0, 0 }, { 1, 31, 0 } } }, - { { { 11, 0, 1 }, { 1, 31, 1 } } }, - { { { 11, 0, 2 }, { 2, 30, 1 } } }, - { { { 11, 0, 3 }, { 2, 30, 0 } } }, - { { { 11, 0, 4 }, { 2, 31, 1 } } }, - { { { 12, 0, 4 }, { 2, 31, 0 } } }, - { { { 12, 0, 3 }, { 4, 27, 0 } } }, - { { { 12, 0, 2 }, { 3, 30, 1 } } }, - { { { 12, 0, 1 }, { 3, 30, 0 } } }, - { { { 12, 0, 0 }, { 4, 28, 0 } } }, - { { { 12, 0, 1 }, { 3, 31, 1 } } }, - { { { 12, 0, 2 }, { 3, 31, 0 } } }, - { { { 12, 0, 3 }, { 3, 31, 1 } } }, - { { { 12, 0, 4 }, { 4, 30, 1 } } }, - { { { 13, 0, 3 }, { 4, 30, 0 } } }, - { { { 13, 0, 2 }, { 6, 27, 1 } } }, - { { { 13, 0, 1 }, { 6, 27, 0 } } }, - { { { 13, 0, 0 }, { 4, 31, 0 } } }, - { { { 13, 0, 1 }, { 5, 30, 1 } } }, - { { { 13, 0, 2 }, { 5, 30, 0 } } }, - { { { 13, 0, 3 }, { 8, 24, 0 } } }, - { { { 13, 0, 4 }, { 5, 31, 1 } } }, - { { { 14, 0, 3 }, { 5, 31, 0 } } }, - { { { 14, 0, 2 }, { 5, 31, 1 } } }, - { { { 14, 0, 1 }, { 6, 30, 1 } } }, - { { { 14, 0, 0 }, { 6, 30, 0 } } }, - { { { 14, 0, 1 }, { 6, 31, 1 } } }, - { { { 14, 0, 2 }, { 6, 31, 0 } } }, - { { { 14, 0, 3 }, { 8, 27, 0 } } }, - { { { 14, 0, 4 }, { 7, 30, 1 } } }, - { { { 15, 0, 3 }, { 7, 30, 0 } } }, - { { { 15, 0, 2 }, { 8, 28, 0 } } }, - { { { 15, 0, 1 }, { 7, 31, 1 } } }, - { { { 15, 0, 0 }, { 7, 31, 0 } } }, - { { { 15, 0, 1 }, { 7, 31, 1 } } }, - { { { 15, 0, 2 }, { 8, 30, 1 } } }, - { { { 15, 0, 3 }, { 8, 30, 0 } } }, - { { { 15, 0, 4 }, { 10, 27, 1 } } }, - { { { 16, 0, 4 }, { 10, 27, 0 } } }, - { { { 16, 0, 3 }, { 8, 31, 0 } } }, - { { { 16, 0, 2 }, { 9, 30, 1 } } }, - { { { 16, 0, 1 }, { 9, 30, 0 } } }, - { { { 16, 0, 0 }, { 12, 24, 0 } } }, - { { { 16, 0, 1 }, { 9, 31, 1 } } }, - { { { 16, 0, 2 }, { 9, 31, 0 } } }, - { { { 16, 0, 3 }, { 9, 31, 1 } } }, - { { { 16, 0, 4 }, { 10, 30, 1 } } }, - { { { 17, 0, 3 }, { 10, 30, 0 } } }, - { { { 17, 0, 2 }, { 10, 31, 1 } } }, - { { { 17, 0, 1 }, { 10, 31, 0 } } }, - { { { 17, 0, 0 }, { 12, 27, 0 } } }, - { { { 17, 0, 1 }, { 11, 30, 1 } } }, - { { { 17, 0, 2 }, { 11, 30, 0 } } }, - { { { 17, 0, 3 }, { 12, 28, 0 } } }, - { { { 17, 0, 4 }, { 11, 31, 1 } } }, - { { { 18, 0, 3 }, { 11, 31, 0 } } }, - { { { 18, 0, 2 }, { 11, 31, 1 } } }, - { { { 18, 0, 1 }, { 12, 30, 1 } } }, - { { { 18, 0, 0 }, { 12, 30, 0 } } }, - { { { 18, 0, 1 }, { 14, 27, 1 } } }, - { { { 18, 0, 2 }, { 14, 27, 0 } } }, - { { { 18, 0, 3 }, { 12, 31, 0 } } }, - { { { 18, 0, 4 }, { 13, 30, 1 } } }, - { { { 19, 0, 3 }, { 13, 30, 0 } } }, - { { { 19, 0, 2 }, { 16, 24, 0 } } }, - { { { 19, 0, 1 }, { 13, 31, 1 } } }, - { { { 19, 0, 0 }, { 13, 31, 0 } } }, - { { { 19, 0, 1 }, { 13, 31, 1 } } }, - { { { 19, 0, 2 }, { 14, 30, 1 } } }, - { { { 19, 0, 3 }, { 14, 30, 0 } } }, - { { { 19, 0, 4 }, { 14, 31, 1 } } }, - { { { 20, 0, 4 }, { 14, 31, 0 } } }, - { { { 20, 0, 3 }, { 16, 27, 0 } } }, - { { { 20, 0, 2 }, { 15, 30, 1 } } }, - { { { 20, 0, 1 }, { 15, 30, 0 } } }, - { { { 20, 0, 0 }, { 16, 28, 0 } } }, - { { { 20, 0, 1 }, { 15, 31, 1 } } }, - { { { 20, 0, 2 }, { 15, 31, 0 } } }, - { { { 20, 0, 3 }, { 15, 31, 1 } } }, - { { { 20, 0, 4 }, { 16, 30, 1 } } }, - { { { 21, 0, 3 }, { 16, 30, 0 } } }, - { { { 21, 0, 2 }, { 18, 27, 1 } } }, - { { { 21, 0, 1 }, { 18, 27, 0 } } }, - { { { 21, 0, 0 }, { 16, 31, 0 } } }, - { { { 21, 0, 1 }, { 17, 30, 1 } } }, - { { { 21, 0, 2 }, { 17, 30, 0 } } }, - { { { 21, 0, 3 }, { 20, 24, 0 } } }, - { { { 21, 0, 4 }, { 17, 31, 1 } } }, - { { { 22, 0, 3 }, { 17, 31, 0 } } }, - { { { 22, 0, 2 }, { 17, 31, 1 } } }, - { { { 22, 0, 1 }, { 18, 30, 1 } } }, - { { { 22, 0, 0 }, { 18, 30, 0 } } }, - { { { 22, 0, 1 }, { 18, 31, 1 } } }, - { { { 22, 0, 2 }, { 18, 31, 0 } } }, - { { { 22, 0, 3 }, { 20, 27, 0 } } }, - { { { 22, 0, 4 }, { 19, 30, 1 } } }, - { { { 23, 0, 3 }, { 19, 30, 0 } } }, - { { { 23, 0, 2 }, { 20, 28, 0 } } }, - { { { 23, 0, 1 }, { 19, 31, 1 } } }, - { { { 23, 0, 0 }, { 19, 31, 0 } } }, - { { { 23, 0, 1 }, { 19, 31, 1 } } }, - { { { 23, 0, 2 }, { 20, 30, 1 } } }, - { { { 23, 0, 3 }, { 20, 30, 0 } } }, - { { { 23, 0, 4 }, { 22, 27, 1 } } }, - { { { 24, 0, 4 }, { 22, 27, 0 } } }, - { { { 24, 0, 3 }, { 20, 31, 0 } } }, - { { { 24, 0, 2 }, { 21, 30, 1 } } }, - { { { 24, 0, 1 }, { 21, 30, 0 } } }, - { { { 24, 0, 0 }, { 24, 24, 0 } } }, - { { { 24, 0, 1 }, { 21, 31, 1 } } }, - { { { 24, 0, 2 }, { 21, 31, 0 } } }, - { { { 24, 0, 3 }, { 21, 31, 1 } } }, - { { { 24, 0, 4 }, { 22, 30, 1 } } }, - { { { 25, 0, 3 }, { 22, 30, 0 } } }, - { { { 25, 0, 2 }, { 22, 31, 1 } } }, - { { { 25, 0, 1 }, { 22, 31, 0 } } }, - { { { 25, 0, 0 }, { 24, 27, 0 } } }, - { { { 25, 0, 1 }, { 23, 30, 1 } } }, - { { { 25, 0, 2 }, { 23, 30, 0 } } }, - { { { 25, 0, 3 }, { 24, 28, 0 } } }, - { { { 25, 0, 4 }, { 23, 31, 1 } } }, - { { { 26, 0, 3 }, { 23, 31, 0 } } }, - { { { 26, 0, 2 }, { 23, 31, 1 } } }, - { { { 26, 0, 1 }, { 24, 30, 1 } } }, - { { { 26, 0, 0 }, { 24, 30, 0 } } }, - { { { 26, 0, 1 }, { 26, 27, 1 } } }, - { { { 26, 0, 2 }, { 26, 27, 0 } } }, - { { { 26, 0, 3 }, { 24, 31, 0 } } }, - { { { 26, 0, 4 }, { 25, 30, 1 } } }, - { { { 27, 0, 3 }, { 25, 30, 0 } } }, - { { { 27, 0, 2 }, { 28, 24, 0 } } }, - { { { 27, 0, 1 }, { 25, 31, 1 } } }, - { { { 27, 0, 0 }, { 25, 31, 0 } } }, - { { { 27, 0, 1 }, { 25, 31, 1 } } }, - { { { 27, 0, 2 }, { 26, 30, 1 } } }, - { { { 27, 0, 3 }, { 26, 30, 0 } } }, - { { { 27, 0, 4 }, { 26, 31, 1 } } }, - { { { 28, 0, 4 }, { 26, 31, 0 } } }, - { { { 28, 0, 3 }, { 28, 27, 0 } } }, - { { { 28, 0, 2 }, { 27, 30, 1 } } }, - { { { 28, 0, 1 }, { 27, 30, 0 } } }, - { { { 28, 0, 0 }, { 28, 28, 0 } } }, - { { { 28, 0, 1 }, { 27, 31, 1 } } }, - { { { 28, 0, 2 }, { 27, 31, 0 } } }, - { { { 28, 0, 3 }, { 27, 31, 1 } } }, - { { { 28, 0, 4 }, { 28, 30, 1 } } }, - { { { 29, 0, 3 }, { 28, 30, 0 } } }, - { { { 29, 0, 2 }, { 30, 27, 1 } } }, - { { { 29, 0, 1 }, { 30, 27, 0 } } }, - { { { 29, 0, 0 }, { 28, 31, 0 } } }, - { { { 29, 0, 1 }, { 29, 30, 1 } } }, - { { { 29, 0, 2 }, { 29, 30, 0 } } }, - { { { 29, 0, 3 }, { 29, 30, 1 } } }, - { { { 29, 0, 4 }, { 29, 31, 1 } } }, - { { { 30, 0, 3 }, { 29, 31, 0 } } }, - { { { 30, 0, 2 }, { 29, 31, 1 } } }, - { { { 30, 0, 1 }, { 30, 30, 1 } } }, - { { { 30, 0, 0 }, { 30, 30, 0 } } }, - { { { 30, 0, 1 }, { 30, 31, 1 } } }, - { { { 30, 0, 2 }, { 30, 31, 0 } } }, - { { { 30, 0, 3 }, { 30, 31, 1 } } }, - { { { 30, 0, 4 }, { 31, 30, 1 } } }, - { { { 31, 0, 3 }, { 31, 30, 0 } } }, - { { { 31, 0, 2 }, { 31, 30, 1 } } }, - { { { 31, 0, 1 }, { 31, 31, 1 } } }, - { { { 31, 0, 0 }, { 31, 31, 0 } } } -}; - -static SingleColourLookup const lookup_6_4[] = -{ - { { { 0, 0, 0 }, { 0, 0, 0 } } }, - { { { 0, 0, 1 }, { 0, 1, 0 } } }, - { { { 0, 0, 2 }, { 0, 2, 0 } } }, - { { { 1, 0, 1 }, { 0, 3, 1 } } }, - { { { 1, 0, 0 }, { 0, 3, 0 } } }, - { { { 1, 0, 1 }, { 0, 4, 0 } } }, - { { { 1, 0, 2 }, { 0, 5, 0 } } }, - { { { 2, 0, 1 }, { 0, 6, 1 } } }, - { { { 2, 0, 0 }, { 0, 6, 0 } } }, - { { { 2, 0, 1 }, { 0, 7, 0 } } }, - { { { 2, 0, 2 }, { 0, 8, 0 } } }, - { { { 3, 0, 1 }, { 0, 9, 1 } } }, - { { { 3, 0, 0 }, { 0, 9, 0 } } }, - { { { 3, 0, 1 }, { 0, 10, 0 } } }, - { { { 3, 0, 2 }, { 0, 11, 0 } } }, - { { { 4, 0, 1 }, { 0, 12, 1 } } }, - { { { 4, 0, 0 }, { 0, 12, 0 } } }, - { { { 4, 0, 1 }, { 0, 13, 0 } } }, - { { { 4, 0, 2 }, { 0, 14, 0 } } }, - { { { 5, 0, 1 }, { 0, 15, 1 } } }, - { { { 5, 0, 0 }, { 0, 15, 0 } } }, - { { { 5, 0, 1 }, { 0, 16, 0 } } }, - { { { 5, 0, 2 }, { 1, 15, 0 } } }, - { { { 6, 0, 1 }, { 0, 17, 0 } } }, - { { { 6, 0, 0 }, { 0, 18, 0 } } }, - { { { 6, 0, 1 }, { 0, 19, 0 } } }, - { { { 6, 0, 2 }, { 3, 14, 0 } } }, - { { { 7, 0, 1 }, { 0, 20, 0 } } }, - { { { 7, 0, 0 }, { 0, 21, 0 } } }, - { { { 7, 0, 1 }, { 0, 22, 0 } } }, - { { { 7, 0, 2 }, { 4, 15, 0 } } }, - { { { 8, 0, 1 }, { 0, 23, 0 } } }, - { { { 8, 0, 0 }, { 0, 24, 0 } } }, - { { { 8, 0, 1 }, { 0, 25, 0 } } }, - { { { 8, 0, 2 }, { 6, 14, 0 } } }, - { { { 9, 0, 1 }, { 0, 26, 0 } } }, - { { { 9, 0, 0 }, { 0, 27, 0 } } }, - { { { 9, 0, 1 }, { 0, 28, 0 } } }, - { { { 9, 0, 2 }, { 7, 15, 0 } } }, - { { { 10, 0, 1 }, { 0, 29, 0 } } }, - { { { 10, 0, 0 }, { 0, 30, 0 } } }, - { { { 10, 0, 1 }, { 0, 31, 0 } } }, - { { { 10, 0, 2 }, { 9, 14, 0 } } }, - { { { 11, 0, 1 }, { 0, 32, 0 } } }, - { { { 11, 0, 0 }, { 0, 33, 0 } } }, - { { { 11, 0, 1 }, { 2, 30, 0 } } }, - { { { 11, 0, 2 }, { 0, 34, 0 } } }, - { { { 12, 0, 1 }, { 0, 35, 0 } } }, - { { { 12, 0, 0 }, { 0, 36, 0 } } }, - { { { 12, 0, 1 }, { 3, 31, 0 } } }, - { { { 12, 0, 2 }, { 0, 37, 0 } } }, - { { { 13, 0, 1 }, { 0, 38, 0 } } }, - { { { 13, 0, 0 }, { 0, 39, 0 } } }, - { { { 13, 0, 1 }, { 5, 30, 0 } } }, - { { { 13, 0, 2 }, { 0, 40, 0 } } }, - { { { 14, 0, 1 }, { 0, 41, 0 } } }, - { { { 14, 0, 0 }, { 0, 42, 0 } } }, - { { { 14, 0, 1 }, { 6, 31, 0 } } }, - { { { 14, 0, 2 }, { 0, 43, 0 } } }, - { { { 15, 0, 1 }, { 0, 44, 0 } } }, - { { { 15, 0, 0 }, { 0, 45, 0 } } }, - { { { 15, 0, 1 }, { 8, 30, 0 } } }, - { { { 15, 0, 2 }, { 0, 46, 0 } } }, - { { { 16, 0, 2 }, { 0, 47, 0 } } }, - { { { 16, 0, 1 }, { 1, 46, 0 } } }, - { { { 16, 0, 0 }, { 0, 48, 0 } } }, - { { { 16, 0, 1 }, { 0, 49, 0 } } }, - { { { 16, 0, 2 }, { 0, 50, 0 } } }, - { { { 17, 0, 1 }, { 2, 47, 0 } } }, - { { { 17, 0, 0 }, { 0, 51, 0 } } }, - { { { 17, 0, 1 }, { 0, 52, 0 } } }, - { { { 17, 0, 2 }, { 0, 53, 0 } } }, - { { { 18, 0, 1 }, { 4, 46, 0 } } }, - { { { 18, 0, 0 }, { 0, 54, 0 } } }, - { { { 18, 0, 1 }, { 0, 55, 0 } } }, - { { { 18, 0, 2 }, { 0, 56, 0 } } }, - { { { 19, 0, 1 }, { 5, 47, 0 } } }, - { { { 19, 0, 0 }, { 0, 57, 0 } } }, - { { { 19, 0, 1 }, { 0, 58, 0 } } }, - { { { 19, 0, 2 }, { 0, 59, 0 } } }, - { { { 20, 0, 1 }, { 7, 46, 0 } } }, - { { { 20, 0, 0 }, { 0, 60, 0 } } }, - { { { 20, 0, 1 }, { 0, 61, 0 } } }, - { { { 20, 0, 2 }, { 0, 62, 0 } } }, - { { { 21, 0, 1 }, { 8, 47, 0 } } }, - { { { 21, 0, 0 }, { 0, 63, 0 } } }, - { { { 21, 0, 1 }, { 1, 62, 0 } } }, - { { { 21, 0, 2 }, { 1, 63, 0 } } }, - { { { 22, 0, 1 }, { 10, 46, 0 } } }, - { { { 22, 0, 0 }, { 2, 62, 0 } } }, - { { { 22, 0, 1 }, { 2, 63, 0 } } }, - { { { 22, 0, 2 }, { 3, 62, 0 } } }, - { { { 23, 0, 1 }, { 11, 47, 0 } } }, - { { { 23, 0, 0 }, { 3, 63, 0 } } }, - { { { 23, 0, 1 }, { 4, 62, 0 } } }, - { { { 23, 0, 2 }, { 4, 63, 0 } } }, - { { { 24, 0, 1 }, { 13, 46, 0 } } }, - { { { 24, 0, 0 }, { 5, 62, 0 } } }, - { { { 24, 0, 1 }, { 5, 63, 0 } } }, - { { { 24, 0, 2 }, { 6, 62, 0 } } }, - { { { 25, 0, 1 }, { 14, 47, 0 } } }, - { { { 25, 0, 0 }, { 6, 63, 0 } } }, - { { { 25, 0, 1 }, { 7, 62, 0 } } }, - { { { 25, 0, 2 }, { 7, 63, 0 } } }, - { { { 26, 0, 1 }, { 16, 45, 0 } } }, - { { { 26, 0, 0 }, { 8, 62, 0 } } }, - { { { 26, 0, 1 }, { 8, 63, 0 } } }, - { { { 26, 0, 2 }, { 9, 62, 0 } } }, - { { { 27, 0, 1 }, { 16, 48, 0 } } }, - { { { 27, 0, 0 }, { 9, 63, 0 } } }, - { { { 27, 0, 1 }, { 10, 62, 0 } } }, - { { { 27, 0, 2 }, { 10, 63, 0 } } }, - { { { 28, 0, 1 }, { 16, 51, 0 } } }, - { { { 28, 0, 0 }, { 11, 62, 0 } } }, - { { { 28, 0, 1 }, { 11, 63, 0 } } }, - { { { 28, 0, 2 }, { 12, 62, 0 } } }, - { { { 29, 0, 1 }, { 16, 54, 0 } } }, - { { { 29, 0, 0 }, { 12, 63, 0 } } }, - { { { 29, 0, 1 }, { 13, 62, 0 } } }, - { { { 29, 0, 2 }, { 13, 63, 0 } } }, - { { { 30, 0, 1 }, { 16, 57, 0 } } }, - { { { 30, 0, 0 }, { 14, 62, 0 } } }, - { { { 30, 0, 1 }, { 14, 63, 0 } } }, - { { { 30, 0, 2 }, { 15, 62, 0 } } }, - { { { 31, 0, 1 }, { 16, 60, 0 } } }, - { { { 31, 0, 0 }, { 15, 63, 0 } } }, - { { { 31, 0, 1 }, { 24, 46, 0 } } }, - { { { 31, 0, 2 }, { 16, 62, 0 } } }, - { { { 32, 0, 2 }, { 16, 63, 0 } } }, - { { { 32, 0, 1 }, { 17, 62, 0 } } }, - { { { 32, 0, 0 }, { 25, 47, 0 } } }, - { { { 32, 0, 1 }, { 17, 63, 0 } } }, - { { { 32, 0, 2 }, { 18, 62, 0 } } }, - { { { 33, 0, 1 }, { 18, 63, 0 } } }, - { { { 33, 0, 0 }, { 27, 46, 0 } } }, - { { { 33, 0, 1 }, { 19, 62, 0 } } }, - { { { 33, 0, 2 }, { 19, 63, 0 } } }, - { { { 34, 0, 1 }, { 20, 62, 0 } } }, - { { { 34, 0, 0 }, { 28, 47, 0 } } }, - { { { 34, 0, 1 }, { 20, 63, 0 } } }, - { { { 34, 0, 2 }, { 21, 62, 0 } } }, - { { { 35, 0, 1 }, { 21, 63, 0 } } }, - { { { 35, 0, 0 }, { 30, 46, 0 } } }, - { { { 35, 0, 1 }, { 22, 62, 0 } } }, - { { { 35, 0, 2 }, { 22, 63, 0 } } }, - { { { 36, 0, 1 }, { 23, 62, 0 } } }, - { { { 36, 0, 0 }, { 31, 47, 0 } } }, - { { { 36, 0, 1 }, { 23, 63, 0 } } }, - { { { 36, 0, 2 }, { 24, 62, 0 } } }, - { { { 37, 0, 1 }, { 24, 63, 0 } } }, - { { { 37, 0, 0 }, { 32, 47, 0 } } }, - { { { 37, 0, 1 }, { 25, 62, 0 } } }, - { { { 37, 0, 2 }, { 25, 63, 0 } } }, - { { { 38, 0, 1 }, { 26, 62, 0 } } }, - { { { 38, 0, 0 }, { 32, 50, 0 } } }, - { { { 38, 0, 1 }, { 26, 63, 0 } } }, - { { { 38, 0, 2 }, { 27, 62, 0 } } }, - { { { 39, 0, 1 }, { 27, 63, 0 } } }, - { { { 39, 0, 0 }, { 32, 53, 0 } } }, - { { { 39, 0, 1 }, { 28, 62, 0 } } }, - { { { 39, 0, 2 }, { 28, 63, 0 } } }, - { { { 40, 0, 1 }, { 29, 62, 0 } } }, - { { { 40, 0, 0 }, { 32, 56, 0 } } }, - { { { 40, 0, 1 }, { 29, 63, 0 } } }, - { { { 40, 0, 2 }, { 30, 62, 0 } } }, - { { { 41, 0, 1 }, { 30, 63, 0 } } }, - { { { 41, 0, 0 }, { 32, 59, 0 } } }, - { { { 41, 0, 1 }, { 31, 62, 0 } } }, - { { { 41, 0, 2 }, { 31, 63, 0 } } }, - { { { 42, 0, 1 }, { 32, 61, 0 } } }, - { { { 42, 0, 0 }, { 32, 62, 0 } } }, - { { { 42, 0, 1 }, { 32, 63, 0 } } }, - { { { 42, 0, 2 }, { 41, 46, 0 } } }, - { { { 43, 0, 1 }, { 33, 62, 0 } } }, - { { { 43, 0, 0 }, { 33, 63, 0 } } }, - { { { 43, 0, 1 }, { 34, 62, 0 } } }, - { { { 43, 0, 2 }, { 42, 47, 0 } } }, - { { { 44, 0, 1 }, { 34, 63, 0 } } }, - { { { 44, 0, 0 }, { 35, 62, 0 } } }, - { { { 44, 0, 1 }, { 35, 63, 0 } } }, - { { { 44, 0, 2 }, { 44, 46, 0 } } }, - { { { 45, 0, 1 }, { 36, 62, 0 } } }, - { { { 45, 0, 0 }, { 36, 63, 0 } } }, - { { { 45, 0, 1 }, { 37, 62, 0 } } }, - { { { 45, 0, 2 }, { 45, 47, 0 } } }, - { { { 46, 0, 1 }, { 37, 63, 0 } } }, - { { { 46, 0, 0 }, { 38, 62, 0 } } }, - { { { 46, 0, 1 }, { 38, 63, 0 } } }, - { { { 46, 0, 2 }, { 47, 46, 0 } } }, - { { { 47, 0, 1 }, { 39, 62, 0 } } }, - { { { 47, 0, 0 }, { 39, 63, 0 } } }, - { { { 47, 0, 1 }, { 40, 62, 0 } } }, - { { { 47, 0, 2 }, { 48, 46, 0 } } }, - { { { 48, 0, 2 }, { 40, 63, 0 } } }, - { { { 48, 0, 1 }, { 41, 62, 0 } } }, - { { { 48, 0, 0 }, { 41, 63, 0 } } }, - { { { 48, 0, 1 }, { 48, 49, 0 } } }, - { { { 48, 0, 2 }, { 42, 62, 0 } } }, - { { { 49, 0, 1 }, { 42, 63, 0 } } }, - { { { 49, 0, 0 }, { 43, 62, 0 } } }, - { { { 49, 0, 1 }, { 48, 52, 0 } } }, - { { { 49, 0, 2 }, { 43, 63, 0 } } }, - { { { 50, 0, 1 }, { 44, 62, 0 } } }, - { { { 50, 0, 0 }, { 44, 63, 0 } } }, - { { { 50, 0, 1 }, { 48, 55, 0 } } }, - { { { 50, 0, 2 }, { 45, 62, 0 } } }, - { { { 51, 0, 1 }, { 45, 63, 0 } } }, - { { { 51, 0, 0 }, { 46, 62, 0 } } }, - { { { 51, 0, 1 }, { 48, 58, 0 } } }, - { { { 51, 0, 2 }, { 46, 63, 0 } } }, - { { { 52, 0, 1 }, { 47, 62, 0 } } }, - { { { 52, 0, 0 }, { 47, 63, 0 } } }, - { { { 52, 0, 1 }, { 48, 61, 0 } } }, - { { { 52, 0, 2 }, { 48, 62, 0 } } }, - { { { 53, 0, 1 }, { 56, 47, 0 } } }, - { { { 53, 0, 0 }, { 48, 63, 0 } } }, - { { { 53, 0, 1 }, { 49, 62, 0 } } }, - { { { 53, 0, 2 }, { 49, 63, 0 } } }, - { { { 54, 0, 1 }, { 58, 46, 0 } } }, - { { { 54, 0, 0 }, { 50, 62, 0 } } }, - { { { 54, 0, 1 }, { 50, 63, 0 } } }, - { { { 54, 0, 2 }, { 51, 62, 0 } } }, - { { { 55, 0, 1 }, { 59, 47, 0 } } }, - { { { 55, 0, 0 }, { 51, 63, 0 } } }, - { { { 55, 0, 1 }, { 52, 62, 0 } } }, - { { { 55, 0, 2 }, { 52, 63, 0 } } }, - { { { 56, 0, 1 }, { 61, 46, 0 } } }, - { { { 56, 0, 0 }, { 53, 62, 0 } } }, - { { { 56, 0, 1 }, { 53, 63, 0 } } }, - { { { 56, 0, 2 }, { 54, 62, 0 } } }, - { { { 57, 0, 1 }, { 62, 47, 0 } } }, - { { { 57, 0, 0 }, { 54, 63, 0 } } }, - { { { 57, 0, 1 }, { 55, 62, 0 } } }, - { { { 57, 0, 2 }, { 55, 63, 0 } } }, - { { { 58, 0, 1 }, { 56, 62, 1 } } }, - { { { 58, 0, 0 }, { 56, 62, 0 } } }, - { { { 58, 0, 1 }, { 56, 63, 0 } } }, - { { { 58, 0, 2 }, { 57, 62, 0 } } }, - { { { 59, 0, 1 }, { 57, 63, 1 } } }, - { { { 59, 0, 0 }, { 57, 63, 0 } } }, - { { { 59, 0, 1 }, { 58, 62, 0 } } }, - { { { 59, 0, 2 }, { 58, 63, 0 } } }, - { { { 60, 0, 1 }, { 59, 62, 1 } } }, - { { { 60, 0, 0 }, { 59, 62, 0 } } }, - { { { 60, 0, 1 }, { 59, 63, 0 } } }, - { { { 60, 0, 2 }, { 60, 62, 0 } } }, - { { { 61, 0, 1 }, { 60, 63, 1 } } }, - { { { 61, 0, 0 }, { 60, 63, 0 } } }, - { { { 61, 0, 1 }, { 61, 62, 0 } } }, - { { { 61, 0, 2 }, { 61, 63, 0 } } }, - { { { 62, 0, 1 }, { 62, 62, 1 } } }, - { { { 62, 0, 0 }, { 62, 62, 0 } } }, - { { { 62, 0, 1 }, { 62, 63, 0 } } }, - { { { 62, 0, 2 }, { 63, 62, 0 } } }, - { { { 63, 0, 1 }, { 63, 63, 1 } } }, - { { { 63, 0, 0 }, { 63, 63, 0 } } } -}; diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp deleted file mode 100644 index 1de1da3e52..0000000000 --- a/thirdparty/squish/squish.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 <string.h> -#include "squish.h" -#include "colourset.h" -#include "maths.h" -#include "rangefit.h" -#include "clusterfit.h" -#include "colourblock.h" -#include "alpha.h" -#include "singlecolourfit.h" - -namespace squish { - -static int FixFlags( int flags ) -{ - // grab the flag bits - int method = flags & ( kDxt1 | kDxt3 | kDxt5 | kBc4 | kBc5 ); - int fit = flags & ( kColourIterativeClusterFit | kColourClusterFit | kColourRangeFit ); - int extra = flags & kWeightColourByAlpha; - - // set defaults - if ( method != kDxt3 - && method != kDxt5 - && method != kBc4 - && method != kBc5 ) - { - method = kDxt1; - } - if( fit != kColourRangeFit && fit != kColourIterativeClusterFit ) - fit = kColourClusterFit; - - // done - return method | fit | extra; -} - -void CompressMasked( u8 const* rgba, int mask, void* block, int flags, float* metric ) -{ - // fix any bad flags - flags = FixFlags( flags ); - - if ( ( flags & ( kBc4 | kBc5 ) ) != 0 ) - { - u8 alpha[16*4]; - for( int i = 0; i < 16; ++i ) - { - alpha[i*4 + 3] = rgba[i*4 + 0]; // copy R to A - } - - u8* rBlock = reinterpret_cast< u8* >( block ); - CompressAlphaDxt5( alpha, mask, rBlock ); - - if ( ( flags & ( kBc5 ) ) != 0 ) - { - for( int i = 0; i < 16; ++i ) - { - alpha[i*4 + 3] = rgba[i*4 + 1]; // copy G to A - } - - u8* gBlock = reinterpret_cast< u8* >( block ) + 8; - CompressAlphaDxt5( alpha, mask, gBlock ); - } - - return; - } - - // get the block locations - void* colourBlock = block; - void* alphaBlock = block; - if( ( flags & ( kDxt3 | kDxt5 ) ) != 0 ) - colourBlock = reinterpret_cast< u8* >( block ) + 8; - - // create the minimal point set - ColourSet colours( rgba, mask, flags ); - - // check the compression type and compress colour - if( colours.GetCount() == 1 ) - { - // always do a single colour fit - SingleColourFit fit( &colours, flags ); - fit.Compress( colourBlock ); - } - else if( ( flags & kColourRangeFit ) != 0 || colours.GetCount() == 0 ) - { - // do a range fit - RangeFit fit( &colours, flags, metric ); - fit.Compress( colourBlock ); - } - else - { - // default to a cluster fit (could be iterative or not) - ClusterFit fit( &colours, flags, metric ); - fit.Compress( colourBlock ); - } - - // compress alpha separately if necessary - if( ( flags & kDxt3 ) != 0 ) - CompressAlphaDxt3( rgba, mask, alphaBlock ); - else if( ( flags & kDxt5 ) != 0 ) - CompressAlphaDxt5( rgba, mask, alphaBlock ); -} - -void Decompress( u8* rgba, void const* block, int flags ) -{ - // fix any bad flags - flags = FixFlags( flags ); - - // get the block locations - void const* colourBlock = block; - void const* alphaBlock = block; - if( ( flags & ( kDxt3 | kDxt5 ) ) != 0 ) - colourBlock = reinterpret_cast< u8 const* >( block ) + 8; - - // decompress colour - // -- GODOT start -- - //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); - if(( flags & ( kBc4 ) ) != 0) - DecompressColourBc4( rgba, colourBlock); - else if(( flags & ( kBc5 ) ) != 0) - DecompressColourBc5( rgba, colourBlock); - else - DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); - // -- GODOT end -- - - // decompress alpha separately if necessary - if( ( flags & kDxt3 ) != 0 ) - DecompressAlphaDxt3( rgba, alphaBlock ); - else if( ( flags & kDxt5 ) != 0 ) - DecompressAlphaDxt5( rgba, alphaBlock ); -} - -int GetStorageRequirements( int width, int height, int flags ) -{ - // fix any bad flags - flags = FixFlags( flags ); - - // compute the storage requirements - int blockcount = ( ( width + 3 )/4 ) * ( ( height + 3 )/4 ); - int blocksize = ( ( flags & ( kDxt1 | kBc4 ) ) != 0 ) ? 8 : 16; - return blockcount*blocksize; -} - -void CopyRGBA( u8 const* source, u8* dest, int flags ) -{ - if (flags & kSourceBGRA) - { - // convert from bgra to rgba - dest[0] = source[2]; - dest[1] = source[1]; - dest[2] = source[0]; - dest[3] = source[3]; - } - else - { - for( int i = 0; i < 4; ++i ) - *dest++ = *source++; - } -} - -void CompressImage( u8 const* rgba, int width, int height, int pitch, void* blocks, int flags, float* metric ) -{ - // fix any bad flags - flags = FixFlags( flags ); - - // loop over blocks -#ifdef SQUISH_USE_OPENMP -# pragma omp parallel for -#endif - for( int y = 0; y < height; y += 4 ) - { - // initialise the block output - u8* targetBlock = reinterpret_cast< u8* >( blocks ); - int bytesPerBlock = ( ( flags & ( kDxt1 | kBc4 ) ) != 0 ) ? 8 : 16; - targetBlock += ( (y / 4) * ( (width + 3) / 4) ) * bytesPerBlock; - - for( int x = 0; x < width; x += 4 ) - { - // build the 4x4 block of pixels - u8 sourceRgba[16*4]; - u8* targetPixel = sourceRgba; - int mask = 0; - for( int py = 0; py < 4; ++py ) - { - for( int px = 0; px < 4; ++px ) - { - // get the source pixel in the image - int sx = x + px; - int sy = y + py; - - // enable if we're in the image - if( sx < width && sy < height ) - { - // copy the rgba value - u8 const* sourcePixel = rgba + pitch*sy + 4*sx; - CopyRGBA(sourcePixel, targetPixel, flags); - // enable this pixel - mask |= ( 1 << ( 4*py + px ) ); - } - - // advance to the next pixel - targetPixel += 4; - } - } - - // compress it into the output - CompressMasked( sourceRgba, mask, targetBlock, flags, metric ); - - // advance - targetBlock += bytesPerBlock; - } - } -} - -void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags, float* metric ) -{ - CompressImage(rgba, width, height, width*4, blocks, flags, metric); -} - -void DecompressImage( u8* rgba, int width, int height, int pitch, void const* blocks, int flags ) -{ - // fix any bad flags - flags = FixFlags( flags ); - - // loop over blocks -#ifdef SQUISH_USE_OPENMP -# pragma omp parallel for -#endif - for( int y = 0; y < height; y += 4 ) - { - // initialise the block input - u8 const* sourceBlock = reinterpret_cast< u8 const* >( blocks ); - int bytesPerBlock = ( ( flags & ( kDxt1 | kBc4 ) ) != 0 ) ? 8 : 16; - sourceBlock += ( (y / 4) * ( (width + 3) / 4) ) * bytesPerBlock; - - for( int x = 0; x < width; x += 4 ) - { - // decompress the block - u8 targetRgba[4*16]; - Decompress( targetRgba, sourceBlock, flags ); - - // write the decompressed pixels to the correct image locations - u8 const* sourcePixel = targetRgba; - for( int py = 0; py < 4; ++py ) - { - for( int px = 0; px < 4; ++px ) - { - // get the target location - int sx = x + px; - int sy = y + py; - - // write if we're in the image - if( sx < width && sy < height ) - { - // copy the rgba value - u8* targetPixel = rgba + pitch*sy + 4*sx; - CopyRGBA(sourcePixel, targetPixel, flags); - } - - // advance to the next pixel - sourcePixel += 4; - } - } - - // advance - sourceBlock += bytesPerBlock; - } - } -} - -void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags ) -{ - DecompressImage( rgba, width, height, width*4, blocks, flags ); -} - -static double ErrorSq(double x, double y) -{ - return (x - y) * (x - y); -} - -static void ComputeBlockWMSE(u8 const *original, u8 const *compressed, unsigned int w, unsigned int h, double &cmse, double &amse) -{ - // Computes the MSE for the block and weights it by the variance of the original block. - // If the variance of the original block is less than 4 (i.e. a standard deviation of 1 per channel) - // then the block is close to being a single colour. Quantisation errors in single colour blocks - // are easier to see than similar errors in blocks that contain more colours, particularly when there - // are many such blocks in a large area (eg a blue sky background) as they cause banding. Given that - // banding is easier to see than small errors in "complex" blocks, we weight the errors by a factor - // of 5. This implies that images with large, single colour areas will have a higher potential WMSE - // than images with lots of detail. - - cmse = amse = 0; - unsigned int sum_p[4]; // per channel sum of pixels - unsigned int sum_p2[4]; // per channel sum of pixels squared - memset(sum_p, 0, sizeof(sum_p)); - memset(sum_p2, 0, sizeof(sum_p2)); - for( unsigned int py = 0; py < 4; ++py ) - { - for( unsigned int px = 0; px < 4; ++px ) - { - if( px < w && py < h ) - { - double pixelCMSE = 0; - for( int i = 0; i < 3; ++i ) - { - pixelCMSE += ErrorSq(original[i], compressed[i]); - sum_p[i] += original[i]; - sum_p2[i] += (unsigned int)original[i]*original[i]; - } - if( original[3] == 0 && compressed[3] == 0 ) - pixelCMSE = 0; // transparent in both, so colour is inconsequential - amse += ErrorSq(original[3], compressed[3]); - cmse += pixelCMSE; - sum_p[3] += original[3]; - sum_p2[3] += (unsigned int)original[3]*original[3]; - } - original += 4; - compressed += 4; - } - } - unsigned int variance = 0; - for( int i = 0; i < 4; ++i ) - variance += w*h*sum_p2[i] - sum_p[i]*sum_p[i]; - if( variance < 4 * w * w * h * h ) - { - amse *= 5; - cmse *= 5; - } -} - -void ComputeMSE( u8 const *rgba, int width, int height, int pitch, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE ) -{ - // fix any bad flags - flags = FixFlags( flags ); - colourMSE = alphaMSE = 0; - - // initialise the block input - squish::u8 const* sourceBlock = dxt; - int bytesPerBlock = ( ( flags & squish::kDxt1 ) != 0 ) ? 8 : 16; - - // loop over blocks - for( int y = 0; y < height; y += 4 ) - { - for( int x = 0; x < width; x += 4 ) - { - // decompress the block - u8 targetRgba[4*16]; - Decompress( targetRgba, sourceBlock, flags ); - u8 const* sourcePixel = targetRgba; - - // copy across to a similar pixel block - u8 originalRgba[4*16]; - u8* originalPixel = originalRgba; - - for( int py = 0; py < 4; ++py ) - { - for( int px = 0; px < 4; ++px ) - { - int sx = x + px; - int sy = y + py; - if( sx < width && sy < height ) - { - u8 const* targetPixel = rgba + pitch*sy + 4*sx; - CopyRGBA(targetPixel, originalPixel, flags); - } - sourcePixel += 4; - originalPixel += 4; - } - } - - // compute the weighted MSE of the block - double blockCMSE, blockAMSE; - ComputeBlockWMSE(originalRgba, targetRgba, std::min(4, width - x), std::min(4, height - y), blockCMSE, blockAMSE); - colourMSE += blockCMSE; - alphaMSE += blockAMSE; - // advance - sourceBlock += bytesPerBlock; - } - } - colourMSE /= (width * height * 3); - alphaMSE /= (width * height); -} - -void ComputeMSE( u8 const *rgba, int width, int height, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE ) -{ - ComputeMSE(rgba, width, height, width*4, dxt, flags, colourMSE, alphaMSE); -} - -} // namespace squish diff --git a/thirdparty/squish/squish.h b/thirdparty/squish/squish.h deleted file mode 100644 index 14c9bb59fb..0000000000 --- a/thirdparty/squish/squish.h +++ /dev/null @@ -1,309 +0,0 @@ -/* ----------------------------------------------------------------------------- - - Copyright (c) 2006 Simon Brown si@sjbrown.co.uk - - 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 SQUISH_H -#define SQUISH_H - -//! All squish API functions live in this namespace. -namespace squish { - -// ----------------------------------------------------------------------------- - -//! Typedef a quantity that is a single unsigned byte. -typedef unsigned char u8; - -// ----------------------------------------------------------------------------- - -enum -{ - //! Use DXT1 compression. - kDxt1 = ( 1 << 0 ), - - //! Use DXT3 compression. - kDxt3 = ( 1 << 1 ), - - //! Use DXT5 compression. - kDxt5 = ( 1 << 2 ), - - //! Use BC4 compression. - kBc4 = ( 1 << 3 ), - - //! Use BC5 compression. - kBc5 = ( 1 << 4 ), - - //! Use a slow but high quality colour compressor (the default). - kColourClusterFit = ( 1 << 5 ), - - //! Use a fast but low quality colour compressor. - kColourRangeFit = ( 1 << 6 ), - - //! Weight the colour by alpha during cluster fit (disabled by default). - kWeightColourByAlpha = ( 1 << 7 ), - - //! Use a very slow but very high quality colour compressor. - kColourIterativeClusterFit = ( 1 << 8 ), - - //! Source is BGRA rather than RGBA - kSourceBGRA = ( 1 << 9 ) -}; - -// ----------------------------------------------------------------------------- - -/*! @brief Compresses a 4x4 block of pixels. - - @param rgba The rgba values of the 16 source pixels. - @param mask The valid pixel mask. - @param block Storage for the compressed DXT block. - @param flags Compression flags. - @param metric An optional perceptual metric. - - The source pixels should be presented as a contiguous array of 16 rgba - values, with each component as 1 byte each. In memory this should be: - - { r1, g1, b1, a1, .... , r16, g16, b16, a16 } - - The mask parameter enables only certain pixels within the block. The lowest - bit enables the first pixel and so on up to the 16th bit. Bits beyond the - 16th bit are ignored. Pixels that are not enabled are allowed to take - arbitrary colours in the output block. An example of how this can be used - is in the CompressImage function to disable pixels outside the bounds of - the image when the width or height is not divisible by 4. - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. When using DXT1 - compression, 8 bytes of storage are required for the compressed DXT block. - DXT3 and DXT5 compression require 16 bytes of storage per block. - - The flags parameter can also specify a preferred colour compressor to use - when fitting the RGB components of the data. Possible colour compressors - are: kColourClusterFit (the default), kColourRangeFit (very fast, low - quality) or kColourIterativeClusterFit (slowest, best quality). - - When using kColourClusterFit or kColourIterativeClusterFit, an additional - flag can be specified to weight the importance of each pixel by its alpha - value. For images that are rendered using alpha blending, this can - significantly increase the perceived quality. - - The metric parameter can be used to weight the relative importance of each - colour channel, or pass NULL to use the default uniform weight of - { 1.0f, 1.0f, 1.0f }. This replaces the previous flag-based control that - allowed either uniform or "perceptual" weights with the fixed values - { 0.2126f, 0.7152f, 0.0722f }. If non-NULL, the metric should point to a - contiguous array of 3 floats. -*/ -void CompressMasked( u8 const* rgba, int mask, void* block, int flags, float* metric = 0 ); - -// ----------------------------------------------------------------------------- - -/*! @brief Compresses a 4x4 block of pixels. - - @param rgba The rgba values of the 16 source pixels. - @param block Storage for the compressed DXT block. - @param flags Compression flags. - @param metric An optional perceptual metric. - - The source pixels should be presented as a contiguous array of 16 rgba - values, with each component as 1 byte each. In memory this should be: - - { r1, g1, b1, a1, .... , r16, g16, b16, a16 } - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. When using DXT1 - compression, 8 bytes of storage are required for the compressed DXT block. - DXT3 and DXT5 compression require 16 bytes of storage per block. - - The flags parameter can also specify a preferred colour compressor to use - when fitting the RGB components of the data. Possible colour compressors - are: kColourClusterFit (the default), kColourRangeFit (very fast, low - quality) or kColourIterativeClusterFit (slowest, best quality). - - When using kColourClusterFit or kColourIterativeClusterFit, an additional - flag can be specified to weight the importance of each pixel by its alpha - value. For images that are rendered using alpha blending, this can - significantly increase the perceived quality. - - The metric parameter can be used to weight the relative importance of each - colour channel, or pass NULL to use the default uniform weight of - { 1.0f, 1.0f, 1.0f }. This replaces the previous flag-based control that - allowed either uniform or "perceptual" weights with the fixed values - { 0.2126f, 0.7152f, 0.0722f }. If non-NULL, the metric should point to a - contiguous array of 3 floats. - - This method is an inline that calls CompressMasked with a mask of 0xffff, - provided for compatibility with older versions of squish. -*/ -inline void Compress( u8 const* rgba, void* block, int flags, float* metric = 0 ) -{ - CompressMasked( rgba, 0xffff, block, flags, metric ); -} - -// ----------------------------------------------------------------------------- - -/*! @brief Decompresses a 4x4 block of pixels. - - @param rgba Storage for the 16 decompressed pixels. - @param block The compressed DXT block. - @param flags Compression flags. - - The decompressed pixels will be written as a contiguous array of 16 rgba - values, with each component as 1 byte each. In memory this is: - - { r1, g1, b1, a1, .... , r16, g16, b16, a16 } - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. All other flags - are ignored. -*/ -void Decompress( u8* rgba, void const* block, int flags ); - -// ----------------------------------------------------------------------------- - -/*! @brief Computes the amount of compressed storage required. - - @param width The width of the image. - @param height The height of the image. - @param flags Compression flags. - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. All other flags - are ignored. - - Most DXT images will be a multiple of 4 in each dimension, but this - function supports arbitrary size images by allowing the outer blocks to - be only partially used. -*/ -int GetStorageRequirements( int width, int height, int flags ); - -// ----------------------------------------------------------------------------- - -/*! @brief Compresses an image in memory. - - @param rgba The pixels of the source. - @param width The width of the source image. - @param height The height of the source image. - @param pitch The pitch of the source image. - @param blocks Storage for the compressed output. - @param flags Compression flags. - @param metric An optional perceptual metric. - - The source pixels should be presented as a contiguous array of width*height - rgba values, with each component as 1 byte each. In memory this should be: - - { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. When using DXT1 - compression, 8 bytes of storage are required for each compressed DXT block. - DXT3 and DXT5 compression require 16 bytes of storage per block. - - The flags parameter can also specify a preferred colour compressor to use - when fitting the RGB components of the data. Possible colour compressors - are: kColourClusterFit (the default), kColourRangeFit (very fast, low - quality) or kColourIterativeClusterFit (slowest, best quality). - - When using kColourClusterFit or kColourIterativeClusterFit, an additional - flag can be specified to weight the importance of each pixel by its alpha - value. For images that are rendered using alpha blending, this can - significantly increase the perceived quality. - - The metric parameter can be used to weight the relative importance of each - colour channel, or pass NULL to use the default uniform weight of - { 1.0f, 1.0f, 1.0f }. This replaces the previous flag-based control that - allowed either uniform or "perceptual" weights with the fixed values - { 0.2126f, 0.7152f, 0.0722f }. If non-NULL, the metric should point to a - contiguous array of 3 floats. - - Internally this function calls squish::CompressMasked for each block, which - allows for pixels outside the image to take arbitrary values. The function - squish::GetStorageRequirements can be called to compute the amount of memory - to allocate for the compressed output. - - Note on compression quality: When compressing textures with - libsquish it is recommended to apply a gamma-correction - beforehand. This will reduce the blockiness in dark areas. The - level of necessary gamma-correction is platform dependent. For - example, a gamma correction with gamma = 0.5 before compression - and gamma = 2.0 after decompression yields good results on the - Windows platform but for other platforms like MacOS X a different - gamma value may be more suitable. -*/ -void CompressImage( u8 const* rgba, int width, int height, int pitch, void* blocks, int flags, float* metric = 0 ); -void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags, float* metric = 0 ); - -// ----------------------------------------------------------------------------- - -/*! @brief Decompresses an image in memory. - - @param rgba Storage for the decompressed pixels. - @param width The width of the source image. - @param height The height of the source image. - @param pitch The pitch of the decompressed pixels. - @param blocks The compressed DXT blocks. - @param flags Compression flags. - - The decompressed pixels will be written as a contiguous array of width*height - 16 rgba values, with each component as 1 byte each. In memory this is: - - { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. All other flags - are ignored. - - Internally this function calls squish::Decompress for each block. -*/ -void DecompressImage( u8* rgba, int width, int height, int pitch, void const* blocks, int flags ); -void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags ); - -// ----------------------------------------------------------------------------- - -/*! @brief Computes MSE of an compressed image in memory. - - @param rgba The original image pixels. - @param width The width of the source image. - @param height The height of the source image. - @param pitch The pitch of the source image. - @param dxt The compressed dxt blocks - @param flags Compression flags. - @param colourMSE The MSE of the colour values. - @param alphaMSE The MSE of the alpha values. - - The colour MSE and alpha MSE are computed across all pixels. The colour MSE is - averaged across all rgb values (i.e. colourMSE = sum sum_k ||dxt.k - rgba.k||/3) - - The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, - however, DXT1 will be used by default if none is specified. All other flags - are ignored. - - Internally this function calls squish::Decompress for each block. -*/ -void ComputeMSE(u8 const *rgba, int width, int height, int pitch, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE); -void ComputeMSE(u8 const *rgba, int width, int height, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE); - -// ----------------------------------------------------------------------------- - -} // namespace squish - -#endif // ndef SQUISH_H |