summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS5
-rw-r--r--.github/workflows/runner.yml2
-rw-r--r--SConstruct75
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/object/object.h1
-rw-r--r--doc/classes/@GlobalScope.xml10
-rw-r--r--doc/classes/CameraFeed.xml28
-rw-r--r--doc/classes/GraphEdit.xml5
-rw-r--r--doc/classes/ProjectSettings.xml5
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp3
-rw-r--r--drivers/gles3/shaders/scene.glsl289
-rw-r--r--drivers/gles3/storage/config.cpp2
-rw-r--r--drivers/gles3/storage/material_storage.cpp4
-rw-r--r--editor/plugins/tool_button_editor_plugin.cpp82
-rw-r--r--editor/plugins/tool_button_editor_plugin.h (renamed from modules/squish/image_decompress_squish.cpp)79
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp1
-rw-r--r--editor/register_editor_types.cpp2
-rw-r--r--editor/renames_map_3_to_4.cpp2
-rw-r--r--methods.py21
-rw-r--r--modules/bcdec/SCsub10
-rw-r--r--modules/bcdec/config.py (renamed from modules/squish/config.py)0
-rw-r--r--modules/bcdec/image_decompress_bcdec.cpp181
-rw-r--r--modules/bcdec/image_decompress_bcdec.h (renamed from modules/squish/image_decompress_squish.h)21
-rw-r--r--modules/bcdec/register_types.cpp (renamed from modules/squish/register_types.cpp)9
-rw-r--r--modules/bcdec/register_types.h (renamed from modules/squish/register_types.h)10
-rw-r--r--modules/camera/buffer_decoder.cpp10
-rw-r--r--modules/camera/camera_macos.mm2
-rw-r--r--modules/cvtt/register_types.cpp1
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml35
-rw-r--r--modules/gdscript/gdscript_parser.cpp63
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/export_tool_button_requires_tool_mode.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.out4
-rw-r--r--modules/gdscript/tests/scripts/utils.notest.gd3
-rw-r--r--modules/squish/SCsub45
-rw-r--r--platform/linuxbsd/detect.py4
-rw-r--r--scene/gui/graph_edit.cpp4
-rw-r--r--servers/camera/camera_feed.cpp17
-rw-r--r--servers/camera/camera_feed.h6
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp9
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp5
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp7
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp164
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h43
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl10
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl190
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl326
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl82
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp97
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h27
-rw-r--r--servers/rendering_server.cpp3
-rw-r--r--thirdparty/README.md21
-rw-r--r--thirdparty/misc/bcdec.h1329
-rw-r--r--thirdparty/squish/LICENSE.txt20
-rw-r--r--thirdparty/squish/alpha.cpp350
-rw-r--r--thirdparty/squish/alpha.h41
-rw-r--r--thirdparty/squish/clusterfit.cpp392
-rw-r--r--thirdparty/squish/clusterfit.h61
-rw-r--r--thirdparty/squish/colourblock.cpp247
-rw-r--r--thirdparty/squish/colourblock.h45
-rw-r--r--thirdparty/squish/colourfit.cpp54
-rw-r--r--thirdparty/squish/colourfit.h56
-rw-r--r--thirdparty/squish/colourset.cpp121
-rw-r--r--thirdparty/squish/colourset.h58
-rw-r--r--thirdparty/squish/config.h69
-rw-r--r--thirdparty/squish/maths.cpp259
-rw-r--r--thirdparty/squish/maths.h233
-rw-r--r--thirdparty/squish/patches/config_sse.patch31
-rw-r--r--thirdparty/squish/patches/decompress_bc4_bc5.patch85
-rw-r--r--thirdparty/squish/rangefit.cpp201
-rw-r--r--thirdparty/squish/rangefit.h54
-rw-r--r--thirdparty/squish/simd.h40
-rw-r--r--thirdparty/squish/simd_float.h183
-rw-r--r--thirdparty/squish/simd_sse.h180
-rw-r--r--thirdparty/squish/simd_ve.h166
-rw-r--r--thirdparty/squish/singlecolourfit.cpp172
-rw-r--r--thirdparty/squish/singlecolourfit.h58
-rw-r--r--thirdparty/squish/singlecolourlookup.inl1064
-rw-r--r--thirdparty/squish/squish.cpp411
-rw-r--r--thirdparty/squish/squish.h309
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="&quot;&quot;" />
+ <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, &amp;"self_modulate", Color(randf(), randf(), randf()))
+ undo_redo.add_undo_property(self, &amp;"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(&amp;"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