Merge branch 'master' of github.com:MarcusPaulsson/godot
This commit is contained in:
commit
6856f75ebe
|
@ -169,10 +169,12 @@
|
||||||
/modules/gridmap/icons/ @godotengine/3d-nodes @godotengine/usability
|
/modules/gridmap/icons/ @godotengine/3d-nodes @godotengine/usability
|
||||||
/modules/noise/ @godotengine/core
|
/modules/noise/ @godotengine/core
|
||||||
/modules/noise/doc_classes/ @godotengine/core @godotengine/documentation
|
/modules/noise/doc_classes/ @godotengine/core @godotengine/documentation
|
||||||
|
/modules/noise/icons/ @godotengine/core @godotengine/usability
|
||||||
/modules/noise/tests/ @godotengine/core @godotengine/tests
|
/modules/noise/tests/ @godotengine/core @godotengine/tests
|
||||||
/modules/regex/ @godotengine/core
|
/modules/regex/ @godotengine/core
|
||||||
/modules/regex/doc_classes/ @godotengine/core @godotengine/documentation
|
/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/ @godotengine/core
|
||||||
/modules/zip/doc_classes/ @godotengine/core @godotengine/documentation
|
/modules/zip/doc_classes/ @godotengine/core @godotengine/documentation
|
||||||
|
|
||||||
|
@ -207,6 +209,7 @@
|
||||||
/scene/resources/text_paragraph.* @godotengine/gui-nodes
|
/scene/resources/text_paragraph.* @godotengine/gui-nodes
|
||||||
/scene/resources/visual_shader*.* @godotengine/shaders
|
/scene/resources/visual_shader*.* @godotengine/shaders
|
||||||
/scene/theme/ @godotengine/gui-nodes
|
/scene/theme/ @godotengine/gui-nodes
|
||||||
|
/scene/theme/icons/ @godotengine/gui-nodes @godotengine/usability
|
||||||
|
|
||||||
# Servers
|
# Servers
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: 🔗 GHA
|
name: 🔗 GHA
|
||||||
on: [push, pull_request]
|
on: [push, pull_request, merge_group]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
|
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
|
||||||
|
|
65
SConstruct
65
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_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_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_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_xatlas", "Use the built-in xatlas library", True))
|
||||||
opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib 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))
|
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).")
|
print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
|
||||||
|
|
||||||
# Enforce our minimal compiler version requirements
|
# Enforce our minimal compiler version requirements
|
||||||
cc_version = methods.get_compiler_version(env) or {
|
cc_version = methods.get_compiler_version(env)
|
||||||
"major": None,
|
cc_version_major = cc_version["major"]
|
||||||
"minor": None,
|
cc_version_minor = cc_version["minor"]
|
||||||
"patch": None,
|
cc_version_metadata1 = cc_version["metadata1"]
|
||||||
"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:
|
||||||
if cc_version_major == -1:
|
|
||||||
print_warning(
|
print_warning(
|
||||||
"Couldn't detect compiler version, skipping version checks. "
|
"Couldn't detect compiler version, skipping version checks. "
|
||||||
"Build may fail if the compiler doesn't support C++17 fully."
|
"Build may fail if the compiler doesn't support C++17 fully."
|
||||||
)
|
)
|
||||||
elif cc_version_major < 9:
|
elif methods.using_gcc(env):
|
||||||
|
if cc_version_major < 9:
|
||||||
print_error(
|
print_error(
|
||||||
"Detected GCC version older than 9, which does not fully support "
|
"Detected GCC version older than 9, which does not fully support "
|
||||||
"C++17, or has bugs when compiling Godot. Supported versions are 9 "
|
"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.")
|
print_warning("GCC < 8 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
|
||||||
env["debug_paths_relative"] = False
|
env["debug_paths_relative"] = False
|
||||||
elif methods.using_clang(env):
|
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
|
# Apple LLVM versions differ from upstream LLVM version \o/, compare
|
||||||
# in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
|
# 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)
|
vanilla = methods.is_vanilla_clang(env)
|
||||||
if vanilla and cc_version_major < 6:
|
if vanilla and cc_version_major < 6:
|
||||||
print_warning(
|
print_error(
|
||||||
"Detected Clang version older than 6, which does not fully support "
|
"Detected Clang version older than 6, which does not fully support "
|
||||||
"C++17. Supported versions are Clang 6 and later."
|
"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:
|
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.")
|
print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
|
||||||
env["debug_paths_relative"] = False
|
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.
|
# Set optimize and debug_symbols flags.
|
||||||
# "custom" means do nothing and let users set their own optimization 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.
|
# This needs to come after `configure`, otherwise we don't have env.msvc.
|
||||||
if not env.msvc:
|
if not env.msvc:
|
||||||
# Specifying GNU extensions support explicitly, which are supported by
|
# 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(CFLAGS=["-std=gnu11"])
|
||||||
env.Prepend(CXXFLAGS=["-std=gnu++17"])
|
env.Prepend(CXXFLAGS=["-std=gnu++17"])
|
||||||
else:
|
else:
|
||||||
# MSVC doesn't have clear C standard support, /std only covers C++.
|
# MSVC started offering C standard support with Visual Studio 2019 16.8, which covers all
|
||||||
# We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
|
# of our supported VS2019 & VS2022 versions; VS2017 will only pass the C++ standard.
|
||||||
env.Prepend(CCFLAGS=["/std:c++17"])
|
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.
|
# 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
|
# Note that this is still not complete conformance, as certain Windows-related headers
|
||||||
# don't compile under complete conformance.
|
# don't compile under complete conformance.
|
||||||
|
|
|
@ -677,6 +677,7 @@ void register_global_constants() {
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
|
||||||
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
|
||||||
|
|
||||||
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
|
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
|
||||||
|
|
|
@ -87,6 +87,7 @@ enum PropertyHint {
|
||||||
PROPERTY_HINT_PASSWORD,
|
PROPERTY_HINT_PASSWORD,
|
||||||
PROPERTY_HINT_LAYERS_AVOIDANCE,
|
PROPERTY_HINT_LAYERS_AVOIDANCE,
|
||||||
PROPERTY_HINT_DICTIONARY_TYPE,
|
PROPERTY_HINT_DICTIONARY_TYPE,
|
||||||
|
PROPERTY_HINT_TOOL_BUTTON,
|
||||||
PROPERTY_HINT_MAX,
|
PROPERTY_HINT_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2933,7 +2933,15 @@
|
||||||
<constant name="PROPERTY_HINT_PASSWORD" value="36" enum="PropertyHint">
|
<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.
|
Hints that a string property is a password, and every character is replaced with the secret character.
|
||||||
</constant>
|
</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.
|
Represents the size of the [enum PropertyHint] enum.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags" is_bitfield="true">
|
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags" is_bitfield="true">
|
||||||
|
|
|
@ -45,6 +45,34 @@
|
||||||
[code]copy[/code] will result in FEED_YCBCR
|
[code]copy[/code] will result in FEED_YCBCR
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="feed_is_active" type="bool" setter="set_active" getter="is_active" default="false">
|
<member name="feed_is_active" type="bool" setter="set_active" getter="is_active" default="false">
|
||||||
|
|
|
@ -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.
|
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>
|
</description>
|
||||||
</signal>
|
</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">
|
<signal name="delete_nodes_request">
|
||||||
<param index="0" name="nodes" type="StringName[]" />
|
<param index="0" name="nodes" type="StringName[]" />
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -2863,11 +2863,6 @@
|
||||||
</member>
|
</member>
|
||||||
<member name="rendering/shading/overrides/force_vertex_shading" type="bool" setter="" getter="" default="false">
|
<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.
|
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>
|
||||||
<member name="rendering/textures/canvas_textures/default_texture_filter" type="int" setter="" getter="" default="1">
|
<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.
|
The default texture filtering mode to use on [CanvasItem]s.
|
||||||
|
|
|
@ -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_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_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";
|
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);
|
material_storage->shaders.scene_shader.initialize(global_defines);
|
||||||
scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
|
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);
|
material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
|
||||||
|
|
|
@ -248,6 +248,175 @@ uniform lowp uint directional_shadow_index;
|
||||||
#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
|
#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
|
||||||
#endif // USE_ADDITIVE_LIGHTING
|
#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
|
#ifdef USE_MULTIVIEW
|
||||||
layout(std140) uniform MultiviewData { // ubo:8
|
layout(std140) uniform MultiviewData { // ubo:8
|
||||||
highp mat4 projection_matrix_view[MAX_VIEWS];
|
highp mat4 projection_matrix_view[MAX_VIEWS];
|
||||||
|
@ -540,8 +709,65 @@ void main() {
|
||||||
gl_Position.z = 0.00001;
|
gl_Position.z = 0.00001;
|
||||||
gl_Position.w = 1.0;
|
gl_Position.w = 1.0;
|
||||||
#endif
|
#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 */
|
/* clang-format off */
|
||||||
#[fragment]
|
#[fragment]
|
||||||
|
|
||||||
|
@ -758,6 +984,16 @@ multiview_data;
|
||||||
#define LIGHT_BAKE_DYNAMIC 2u
|
#define LIGHT_BAKE_DYNAMIC 2u
|
||||||
|
|
||||||
#ifndef MODE_RENDER_DEPTH
|
#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.
|
// Directional light data.
|
||||||
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
|
#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
|
layout(std140) uniform OmniLightData { // ubo:5
|
||||||
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
|
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_indices[MAX_FORWARD_LIGHTS];
|
||||||
uniform uint omni_light_count;
|
uniform uint omni_light_count;
|
||||||
#endif // BASE_PASS
|
#endif // defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING)
|
||||||
#endif // DISABLE_LIGHT_OMNI
|
#endif // !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
|
||||||
|
|
||||||
#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
|
#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
|
||||||
layout(std140) uniform SpotLightData { // ubo:6
|
layout(std140) uniform SpotLightData { // ubo:6
|
||||||
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
|
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_indices[MAX_FORWARD_LIGHTS];
|
||||||
uniform uint spot_light_count;
|
uniform uint spot_light_count;
|
||||||
#endif // BASE_PASS
|
#endif // defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING)
|
||||||
#endif // DISABLE_LIGHT_SPOT
|
#endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
|
||||||
#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
#ifdef USE_ADDITIVE_LIGHTING
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
#ifdef ADDITIVE_OMNI
|
#ifdef ADDITIVE_OMNI
|
||||||
|
@ -985,6 +1221,8 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
|
||||||
return mix(vec3(dielectric), albedo, vec3(metallic));
|
return mix(vec3(dielectric), albedo, vec3(metallic));
|
||||||
}
|
}
|
||||||
#ifndef MODE_RENDER_DEPTH
|
#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)
|
#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) {
|
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_SPOT) || defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
|
||||||
|
#endif // !USE_VERTEX_LIGHTING
|
||||||
|
|
||||||
vec4 fog_process(vec3 vertex) {
|
vec4 fog_process(vec3 vertex) {
|
||||||
vec3 fog_color = scene_data.fog_light_color;
|
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);
|
specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !AMBIENT_LIGHT_DISABLED
|
#endif // !AMBIENT_LIGHT_DISABLED
|
||||||
|
|
||||||
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
|
specular_light += specular_light_interp * f0;
|
||||||
|
diffuse_light += diffuse_light_interp;
|
||||||
|
#else
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
||||||
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
||||||
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
|
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
|
||||||
|
@ -1944,6 +2187,7 @@ void main() {
|
||||||
diffuse_light, specular_light);
|
diffuse_light, specular_light);
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_LIGHT_SPOT
|
#endif // !DISABLE_LIGHT_SPOT
|
||||||
|
#endif // !USE_VERTEX_LIGHTING
|
||||||
#endif // BASE_PASS
|
#endif // BASE_PASS
|
||||||
#endif // !MODE_UNSHADED
|
#endif // !MODE_UNSHADED
|
||||||
|
|
||||||
|
@ -1993,7 +2237,6 @@ void main() {
|
||||||
#else
|
#else
|
||||||
|
|
||||||
diffuse_light *= albedo;
|
diffuse_light *= albedo;
|
||||||
|
|
||||||
diffuse_light *= 1.0 - metallic;
|
diffuse_light *= 1.0 - metallic;
|
||||||
ambient_light *= 1.0 - metallic;
|
ambient_light *= 1.0 - metallic;
|
||||||
|
|
||||||
|
@ -2024,6 +2267,11 @@ void main() {
|
||||||
diffuse_light = vec3(0.0);
|
diffuse_light = vec3(0.0);
|
||||||
specular_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)
|
#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
#ifndef SHADOWS_DISABLED
|
#ifndef SHADOWS_DISABLED
|
||||||
|
@ -2137,6 +2385,8 @@ void main() {
|
||||||
#else
|
#else
|
||||||
float directional_shadow = 1.0f;
|
float directional_shadow = 1.0f;
|
||||||
#endif // SHADOWS_DISABLED
|
#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,
|
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
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -2153,6 +2403,11 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
diffuse_light,
|
diffuse_light,
|
||||||
specular_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)
|
#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
|
||||||
|
|
||||||
#ifdef ADDITIVE_OMNI
|
#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 = 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);
|
omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity);
|
||||||
#endif // SHADOWS_DISABLED
|
#endif // SHADOWS_DISABLED
|
||||||
|
|
||||||
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
|
light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -2177,6 +2434,11 @@ void main() {
|
||||||
binormal, tangent, anisotropy,
|
binormal, tangent, anisotropy,
|
||||||
#endif
|
#endif
|
||||||
diffuse_light, specular_light);
|
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
|
#endif // ADDITIVE_OMNI
|
||||||
|
|
||||||
#ifdef ADDITIVE_SPOT
|
#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 = 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);
|
spot_shadow = mix(1.0, spot_shadow, spot_lights[spot_light_index].shadow_opacity);
|
||||||
#endif // SHADOWS_DISABLED
|
#endif // SHADOWS_DISABLED
|
||||||
|
|
||||||
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
|
light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -2201,6 +2465,11 @@ void main() {
|
||||||
binormal, anisotropy,
|
binormal, anisotropy,
|
||||||
#endif
|
#endif
|
||||||
diffuse_light, specular_light);
|
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
|
#endif // ADDITIVE_SPOT
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ Config::Config() {
|
||||||
}
|
}
|
||||||
#endif
|
#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_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
|
||||||
|
|
||||||
use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
|
use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
|
||||||
|
|
|
@ -1368,6 +1368,10 @@ MaterialStorage::MaterialStorage() {
|
||||||
actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
|
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["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
|
||||||
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\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.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
|
||||||
|
|
||||||
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
|
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* image_decompress_squish.cpp */
|
/* tool_button_editor_plugin.h */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* This file is part of: */
|
/* This file is part of: */
|
||||||
/* GODOT ENGINE */
|
/* GODOT ENGINE */
|
||||||
|
@ -28,69 +28,30 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* 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) {
|
class EditorInspectorToolButtonPlugin : public EditorInspectorPlugin {
|
||||||
int w = p_image->get_width();
|
GDCLASS(EditorInspectorToolButtonPlugin, EditorInspectorPlugin);
|
||||||
int h = p_image->get_height();
|
|
||||||
|
|
||||||
Image::Format source_format = p_image->get_format();
|
void _update_action_icon(Button *p_action_button, const String &p_action_icon);
|
||||||
Image::Format target_format = Image::FORMAT_RGBA8;
|
void _call_action(const Variant &p_object, const StringName &p_property);
|
||||||
|
|
||||||
Vector<uint8_t> data;
|
public:
|
||||||
int64_t target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
|
virtual bool can_handle(Object *p_object) override;
|
||||||
int mm_count = p_image->get_mipmap_count();
|
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;
|
||||||
data.resize(target_size);
|
};
|
||||||
|
|
||||||
const uint8_t *rb = p_image->get_data().ptr();
|
class ToolButtonEditorPlugin : public EditorPlugin {
|
||||||
uint8_t *wb = data.ptrw();
|
GDCLASS(ToolButtonEditorPlugin, EditorPlugin);
|
||||||
|
|
||||||
int squish_flags = 0;
|
public:
|
||||||
|
virtual String get_name() const override { return "ToolButtonEditorPlugin"; }
|
||||||
|
|
||||||
switch (source_format) {
|
ToolButtonEditorPlugin();
|
||||||
case Image::FORMAT_DXT1:
|
};
|
||||||
squish_flags = squish::kDxt1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Image::FORMAT_DXT3:
|
#endif // TOOL_BUTTON_EDITOR_PLUGIN_H
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6300,6 +6300,7 @@ VisualShaderEditor::VisualShaderEditor() {
|
||||||
graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed));
|
graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed));
|
||||||
graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes));
|
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("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("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("delete_nodes_request", callable_mp(this, &VisualShaderEditor::_delete_nodes_request));
|
||||||
graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input));
|
graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input));
|
||||||
|
|
|
@ -127,6 +127,7 @@
|
||||||
#include "editor/plugins/texture_region_editor_plugin.h"
|
#include "editor/plugins/texture_region_editor_plugin.h"
|
||||||
#include "editor/plugins/theme_editor_plugin.h"
|
#include "editor/plugins/theme_editor_plugin.h"
|
||||||
#include "editor/plugins/tiles/tiles_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/version_control_editor_plugin.h"
|
||||||
#include "editor/plugins/visual_shader_editor_plugin.h"
|
#include "editor/plugins/visual_shader_editor_plugin.h"
|
||||||
#include "editor/plugins/voxel_gi_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<TextureLayeredEditorPlugin>();
|
||||||
EditorPlugins::add_by_type<TextureRegionEditorPlugin>();
|
EditorPlugins::add_by_type<TextureRegionEditorPlugin>();
|
||||||
EditorPlugins::add_by_type<ThemeEditorPlugin>();
|
EditorPlugins::add_by_type<ThemeEditorPlugin>();
|
||||||
|
EditorPlugins::add_by_type<ToolButtonEditorPlugin>();
|
||||||
EditorPlugins::add_by_type<VoxelGIEditorPlugin>();
|
EditorPlugins::add_by_type<VoxelGIEditorPlugin>();
|
||||||
|
|
||||||
// 2D
|
// 2D
|
||||||
|
|
|
@ -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", "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_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", "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_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_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" },
|
{ "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", "shading/overrides/force_lambert_over_burley" },
|
||||||
{ "quality/shading/force_lambert_over_burley.mobile", "shading/overrides/force_lambert_over_burley.mobile" },
|
{ "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", "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_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_1_subdiv", "lights_and_shadows/shadow_atlas/quadrant_1_subdiv" },
|
||||||
{ "quality/shadow_atlas/quadrant_2_subdiv", "lights_and_shadows/shadow_atlas/quadrant_2_subdiv" },
|
{ "quality/shadow_atlas/quadrant_2_subdiv", "lights_and_shadows/shadow_atlas/quadrant_2_subdiv" },
|
||||||
|
|
36
methods.py
36
methods.py
|
@ -795,9 +795,9 @@ def get_compiler_version(env):
|
||||||
"major": -1,
|
"major": -1,
|
||||||
"minor": -1,
|
"minor": -1,
|
||||||
"patch": -1,
|
"patch": -1,
|
||||||
"metadata1": None,
|
"metadata1": "",
|
||||||
"metadata2": None,
|
"metadata2": "",
|
||||||
"date": None,
|
"date": "",
|
||||||
"apple_major": -1,
|
"apple_major": -1,
|
||||||
"apple_minor": -1,
|
"apple_minor": -1,
|
||||||
"apple_patch1": -1,
|
"apple_patch1": -1,
|
||||||
|
@ -806,7 +806,35 @@ def get_compiler_version(env):
|
||||||
}
|
}
|
||||||
|
|
||||||
if env.msvc and not using_clang(env):
|
if env.msvc and not using_clang(env):
|
||||||
# TODO: Implement for MSVC
|
try:
|
||||||
|
# FIXME: `-latest` works for most cases, but there are edge-cases where this would
|
||||||
|
# benefit from a more nuanced search.
|
||||||
|
# https://github.com/godotengine/godot/pull/91069#issuecomment-2358956731
|
||||||
|
# https://github.com/godotengine/godot/pull/91069#issuecomment-2380836341
|
||||||
|
args = [
|
||||||
|
env["VSWHERE"],
|
||||||
|
"-latest",
|
||||||
|
"-prerelease",
|
||||||
|
"-products",
|
||||||
|
"*",
|
||||||
|
"-requires",
|
||||||
|
"Microsoft.Component.MSBuild",
|
||||||
|
"-utf8",
|
||||||
|
]
|
||||||
|
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])
|
||||||
|
# Could potentially add section for determining preview version, but
|
||||||
|
# that can wait until metadata is actually used for something.
|
||||||
|
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
|
return ret
|
||||||
|
|
||||||
# Not using -dumpversion as some GCC distros only return major, and
|
# Not using -dumpversion as some GCC distros only return major, and
|
||||||
|
|
|
@ -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")
|
|
@ -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));
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* image_decompress_squish.h */
|
/* image_decompress_bcdec.h */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* This file is part of: */
|
/* This file is part of: */
|
||||||
/* GODOT ENGINE */
|
/* GODOT ENGINE */
|
||||||
|
@ -28,11 +28,22 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#ifndef IMAGE_DECOMPRESS_SQUISH_H
|
#ifndef IMAGE_DECOMPRESS_BCDEC_H
|
||||||
#define IMAGE_DECOMPRESS_SQUISH_H
|
#define IMAGE_DECOMPRESS_BCDEC_H
|
||||||
|
|
||||||
#include "core/io/image.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
|
|
@ -30,17 +30,18 @@
|
||||||
|
|
||||||
#include "register_types.h"
|
#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) {
|
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||||
return;
|
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) {
|
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
|
@ -28,12 +28,12 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#ifndef SQUISH_REGISTER_TYPES_H
|
#ifndef BCDEC_REGISTER_TYPES_H
|
||||||
#define SQUISH_REGISTER_TYPES_H
|
#define BCDEC_REGISTER_TYPES_H
|
||||||
|
|
||||||
#include "modules/register_module_types.h"
|
#include "modules/register_module_types.h"
|
||||||
|
|
||||||
void initialize_squish_module(ModuleInitializationLevel p_level);
|
void initialize_bcdec_module(ModuleInitializationLevel p_level);
|
||||||
void uninitialize_squish_module(ModuleInitializationLevel p_level);
|
void uninitialize_bcdec_module(ModuleInitializationLevel p_level);
|
||||||
|
|
||||||
#endif // SQUISH_REGISTER_TYPES_H
|
#endif // BCDEC_REGISTER_TYPES_H
|
|
@ -105,7 +105,7 @@ void SeparateYuyvBufferDecoder::decode(StreamingBuffer p_buffer) {
|
||||||
cbcr_image.instantiate(width, height, false, Image::FORMAT_RGB8, cbcr_image_data);
|
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) :
|
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);
|
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) :
|
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);
|
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) :
|
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);
|
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) :
|
JpegBufferDecoder::JpegBufferDecoder(CameraFeed *p_camera_feed) :
|
||||||
|
@ -207,6 +207,6 @@ void JpegBufferDecoder::decode(StreamingBuffer p_buffer) {
|
||||||
uint8_t *dst = (uint8_t *)image_data.ptrw();
|
uint8_t *dst = (uint8_t *)image_data.ptrw();
|
||||||
memcpy(dst, p_buffer.start, p_buffer.length);
|
memcpy(dst, p_buffer.start, p_buffer.length);
|
||||||
if (image->load_jpg_from_buffer(image_data) == OK) {
|
if (image->load_jpg_from_buffer(image_data) == OK) {
|
||||||
camera_feed->set_RGB_img(image);
|
camera_feed->set_rgb_image(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,6 +232,7 @@ String CameraFeedLinux::get_device_name() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CameraFeedLinux::activate_feed() {
|
bool CameraFeedLinux::activate_feed() {
|
||||||
|
ERR_FAIL_COND_V_MSG(selected_format == -1, false, "CameraFeed format needs to be set before activating.");
|
||||||
file_descriptor = open(device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
file_descriptor = open(device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
||||||
if (_request_buffers() && _start_capturing()) {
|
if (_request_buffers() && _start_capturing()) {
|
||||||
buffer_decoder = _create_buffer_decoder();
|
buffer_decoder = _create_buffer_decoder();
|
||||||
|
@ -302,16 +303,14 @@ Array CameraFeedLinux::get_formats() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
CameraFeed::FeedFormat CameraFeedLinux::get_format() const {
|
CameraFeed::FeedFormat CameraFeedLinux::get_format() const {
|
||||||
return formats[selected_format];
|
FeedFormat feed_format = {};
|
||||||
|
return selected_format == -1 ? feed_format : formats[selected_format];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CameraFeedLinux::set_format(int p_index, const Dictionary &p_parameters) {
|
bool CameraFeedLinux::set_format(int p_index, const Dictionary &p_parameters) {
|
||||||
ERR_FAIL_COND_V_MSG(active, false, "Feed is active.");
|
ERR_FAIL_COND_V_MSG(active, false, "Feed is active.");
|
||||||
ERR_FAIL_INDEX_V_MSG(p_index, formats.size(), false, "Invalid format index.");
|
ERR_FAIL_INDEX_V_MSG(p_index, formats.size(), false, "Invalid format index.");
|
||||||
|
|
||||||
parameters = p_parameters.duplicate();
|
|
||||||
selected_format = p_index;
|
|
||||||
|
|
||||||
FeedFormat feed_format = formats[p_index];
|
FeedFormat feed_format = formats[p_index];
|
||||||
|
|
||||||
file_descriptor = open(device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
file_descriptor = open(device_name.ascii(), O_RDWR | O_NONBLOCK, 0);
|
||||||
|
@ -344,6 +343,8 @@ bool CameraFeedLinux::set_format(int p_index, const Dictionary &p_parameters) {
|
||||||
}
|
}
|
||||||
close(file_descriptor);
|
close(file_descriptor);
|
||||||
|
|
||||||
|
parameters = p_parameters.duplicate();
|
||||||
|
selected_format = p_index;
|
||||||
emit_signal(SNAME("format_changed"));
|
emit_signal(SNAME("format_changed"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -353,7 +354,6 @@ CameraFeedLinux::CameraFeedLinux(const String &p_device_name) :
|
||||||
CameraFeed() {
|
CameraFeed() {
|
||||||
device_name = p_device_name;
|
device_name = p_device_name;
|
||||||
_query_device(device_name);
|
_query_device(device_name);
|
||||||
set_format(0, Dictionary());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CameraFeedLinux::~CameraFeedLinux() {
|
CameraFeedLinux::~CameraFeedLinux() {
|
||||||
|
|
|
@ -182,7 +182,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// set our texture...
|
// set our texture...
|
||||||
feed->set_YCbCr_imgs(img[0], img[1]);
|
feed->set_ycbcr_images(img[0], img[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// and unlock
|
// and unlock
|
||||||
|
|
|
@ -40,7 +40,6 @@ void initialize_cvtt_module(ModuleInitializationLevel p_level) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::set_compress_bptc_func(image_compress_cvtt);
|
Image::set_compress_bptc_func(image_compress_cvtt);
|
||||||
Image::_image_decompress_bptc = image_decompress_cvtt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninitialize_cvtt_module(ModuleInitializationLevel p_level) {
|
void uninitialize_cvtt_module(ModuleInitializationLevel p_level) {
|
||||||
|
|
|
@ -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.
|
[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>
|
</description>
|
||||||
</annotation>
|
</annotation>
|
||||||
|
<annotation name="@export_tool_button">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="text" type="String" />
|
||||||
|
<param index="1" name="icon" type="String" default="""" />
|
||||||
|
<description>
|
||||||
|
Export a [Callable] property as a clickable button with the label [param text]. When the button is pressed, the callable is called.
|
||||||
|
If [param icon] is specified, it is used to fetch an icon for the button via [method Control.get_theme_icon], from the [code]"EditorIcons"[/code] theme type. If [param icon] is omitted, the default [code]"Callable"[/code] icon is used instead.
|
||||||
|
Consider using the [EditorUndoRedoManager] to allow the action to be reverted safely.
|
||||||
|
See also [constant PROPERTY_HINT_TOOL_BUTTON].
|
||||||
|
[codeblock]
|
||||||
|
@tool
|
||||||
|
extends Sprite2D
|
||||||
|
|
||||||
|
@export_tool_button("Hello") var hello_action = hello
|
||||||
|
@export_tool_button("Randomize the color!", "ColorRect")
|
||||||
|
var randomize_color_action = randomize_color
|
||||||
|
|
||||||
|
func hello():
|
||||||
|
print("Hello world!")
|
||||||
|
|
||||||
|
func randomize_color():
|
||||||
|
var undo_redo = EditorInterface.get_editor_undo_redo()
|
||||||
|
undo_redo.create_action("Randomized Sprite2D Color")
|
||||||
|
undo_redo.add_do_property(self, &"self_modulate", Color(randf(), randf(), randf()))
|
||||||
|
undo_redo.add_undo_property(self, &"self_modulate", self_modulate)
|
||||||
|
undo_redo.commit_action()
|
||||||
|
[/codeblock]
|
||||||
|
[b]Note:[/b] The property is exported without the [constant PROPERTY_USAGE_STORAGE] flag because a [Callable] cannot be properly serialized and stored in a file.
|
||||||
|
[b]Note:[/b] In an exported project neither [EditorInterface] nor [EditorUndoRedoManager] exist, which may cause some scripts to break. To prevent this, you can use [method Engine.get_singleton] and omit the static type from the variable declaration:
|
||||||
|
[codeblock]
|
||||||
|
var undo_redo = Engine.get_singleton(&"EditorInterface").get_editor_undo_redo()
|
||||||
|
[/codeblock]
|
||||||
|
[b]Note:[/b] Avoid storing lambda callables in member variables of [RefCounted]-based classes (e.g. resources), as this can lead to memory leaks. Use only method callables and optionally [method Callable.bind] or [method Callable.unbind].
|
||||||
|
</description>
|
||||||
|
</annotation>
|
||||||
<annotation name="@icon">
|
<annotation name="@icon">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="icon_path" type="String" />
|
<param index="0" name="icon_path" type="String" />
|
||||||
|
|
|
@ -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_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_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_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.
|
// 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_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(""));
|
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,
|
// 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.
|
// 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) {
|
bool GDScriptParser::export_storage_annotation(AnnotationNode *p_annotation, Node *p_target, 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));
|
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) {
|
if (variable->is_static) {
|
||||||
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
|
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
|
||||||
return false;
|
return false;
|
||||||
|
@ -4640,11 +4641,11 @@ bool GDScriptParser::export_storage_annotation(AnnotationNode *p_annotation, Nod
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) {
|
bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node *p_target, 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));
|
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.)");
|
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) {
|
if (variable->is_static) {
|
||||||
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
|
push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
|
||||||
return false;
|
return false;
|
||||||
|
@ -4668,12 +4669,56 @@ bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <PropertyUsageFlags t_usage>
|
bool GDScriptParser::export_tool_button_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
|
||||||
bool GDScriptParser::export_group_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
|
#ifdef TOOLS_ENABLED
|
||||||
if (p_annotation->resolved_arguments.is_empty()) {
|
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;
|
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];
|
p_annotation->export_info.name = p_annotation->resolved_arguments[0];
|
||||||
|
|
||||||
switch (t_usage) {
|
switch (t_usage) {
|
||||||
|
|
|
@ -1507,6 +1507,7 @@ private:
|
||||||
bool export_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
|
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_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_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>
|
template <PropertyUsageFlags t_usage>
|
||||||
bool export_group_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
|
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);
|
bool warning_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
@export_tool_button("Click me!") var action
|
|
@ -0,0 +1,2 @@
|
||||||
|
GDTEST_ANALYZER_ERROR
|
||||||
|
Tool buttons can only be used in tool scripts (add "@tool" to the top of the script).
|
|
@ -1,3 +1,4 @@
|
||||||
|
@tool
|
||||||
class_name ExportVariableTest
|
class_name ExportVariableTest
|
||||||
extends Node
|
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_weak_int = 5
|
||||||
@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_hard_int: int = 6
|
@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():
|
func test():
|
||||||
for property in get_property_list():
|
for property in get_property_list():
|
||||||
if str(property.name).begins_with("test_"):
|
if str(property.name).begins_with("test_"):
|
||||||
|
|
|
@ -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=&""
|
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
|
||||||
var test_export_custom_hard_int: int = 6
|
var test_export_custom_hard_int: int = 6
|
||||||
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
|
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=&""
|
||||||
|
|
|
@ -205,6 +205,9 @@ static func get_property_hint_name(hint: PropertyHint) -> String:
|
||||||
return "PROPERTY_HINT_HIDE_QUATERNION_EDIT"
|
return "PROPERTY_HINT_HIDE_QUATERNION_EDIT"
|
||||||
PROPERTY_HINT_PASSWORD:
|
PROPERTY_HINT_PASSWORD:
|
||||||
return "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.")
|
printerr("Argument `hint` is invalid. Use `PROPERTY_HINT_*` constants.")
|
||||||
return "<invalid hint>"
|
return "<invalid hint>"
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -155,7 +155,6 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::load_from_buffer(const Vect
|
||||||
char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE);
|
char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE);
|
||||||
err = ogg_sync_check(&sync_state);
|
err = ogg_sync_check(&sync_state);
|
||||||
ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err));
|
ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err));
|
||||||
ERR_FAIL_COND_V(cursor > size_t(file_data.size()), Ref<AudioStreamOggVorbis>());
|
|
||||||
size_t copy_size = file_data.size() - cursor;
|
size_t copy_size = file_data.size() - cursor;
|
||||||
if (copy_size > OGG_SYNC_BUFFER_SIZE) {
|
if (copy_size > OGG_SYNC_BUFFER_SIZE) {
|
||||||
copy_size = OGG_SYNC_BUFFER_SIZE;
|
copy_size = OGG_SYNC_BUFFER_SIZE;
|
||||||
|
|
|
@ -256,10 +256,6 @@ def configure(env: "SConsEnvironment"):
|
||||||
if not env["builtin_enet"]:
|
if not env["builtin_enet"]:
|
||||||
env.ParseConfig("pkg-config libenet --cflags --libs")
|
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"]:
|
if not env["builtin_zstd"]:
|
||||||
env.ParseConfig("pkg-config libzstd --cflags --libs")
|
env.ParseConfig("pkg-config libzstd --cflags --libs")
|
||||||
|
|
||||||
|
|
|
@ -1999,6 +1999,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
} else if (p_ev->is_action("ui_copy", true)) {
|
} else if (p_ev->is_action("ui_copy", true)) {
|
||||||
emit_signal(SNAME("copy_nodes_request"));
|
emit_signal(SNAME("copy_nodes_request"));
|
||||||
accept_event();
|
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)) {
|
} else if (p_ev->is_action("ui_paste", true)) {
|
||||||
emit_signal(SNAME("paste_nodes_request"));
|
emit_signal(SNAME("paste_nodes_request"));
|
||||||
accept_event();
|
accept_event();
|
||||||
|
@ -2735,6 +2738,7 @@ void GraphEdit::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("connection_drag_ended"));
|
ADD_SIGNAL(MethodInfo("connection_drag_ended"));
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("copy_nodes_request"));
|
ADD_SIGNAL(MethodInfo("copy_nodes_request"));
|
||||||
|
ADD_SIGNAL(MethodInfo("cut_nodes_request"));
|
||||||
ADD_SIGNAL(MethodInfo("paste_nodes_request"));
|
ADD_SIGNAL(MethodInfo("paste_nodes_request"));
|
||||||
ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
|
ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
|
||||||
ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName")));
|
ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName")));
|
||||||
|
|
|
@ -33,26 +33,23 @@
|
||||||
#include "servers/rendering_server.h"
|
#include "servers/rendering_server.h"
|
||||||
|
|
||||||
void CameraFeed::_bind_methods() {
|
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("get_id"), &CameraFeed::get_id);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("is_active"), &CameraFeed::is_active);
|
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("set_active", "active"), &CameraFeed::set_active);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_name"), &CameraFeed::get_name);
|
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("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)
|
// 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("get_transform"), &CameraFeed::get_transform);
|
||||||
ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CameraFeed::set_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_rgb_image", "rgb_image"), &CameraFeed::set_rgb_image);
|
||||||
ClassDB::bind_method(D_METHOD("_set_YCbCr_img", "ycbcr_img"), &CameraFeed::set_YCbCr_img);
|
ClassDB::bind_method(D_METHOD("set_ycbcr_image", "ycbcr_image"), &CameraFeed::set_ycbcr_image);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_datatype"), &CameraFeed::get_datatype);
|
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]);
|
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());
|
ERR_FAIL_COND(p_rgb_img.is_null());
|
||||||
if (active) {
|
if (active) {
|
||||||
int new_width = p_rgb_img->get_width();
|
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());
|
ERR_FAIL_COND(p_ycbcr_img.is_null());
|
||||||
if (active) {
|
if (active) {
|
||||||
int new_width = p_ycbcr_img->get_width();
|
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_y_img.is_null());
|
||||||
ERR_FAIL_COND(p_cbcr_img.is_null());
|
ERR_FAIL_COND(p_cbcr_img.is_null());
|
||||||
if (active) {
|
if (active) {
|
||||||
|
|
|
@ -110,9 +110,9 @@ public:
|
||||||
virtual ~CameraFeed();
|
virtual ~CameraFeed();
|
||||||
|
|
||||||
FeedDataType get_datatype() const;
|
FeedDataType get_datatype() const;
|
||||||
void set_RGB_img(const Ref<Image> &p_rgb_img);
|
void set_rgb_image(const Ref<Image> &p_rgb_img);
|
||||||
void set_YCbCr_img(const Ref<Image> &p_ycbcr_img);
|
void set_ycbcr_image(const Ref<Image> &p_ycbcr_img);
|
||||||
void set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_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 bool set_format(int p_index, const Dictionary &p_parameters);
|
||||||
virtual Array get_formats() const;
|
virtual Array get_formats() const;
|
||||||
|
|
|
@ -4261,6 +4261,11 @@ RenderForwardClustered::RenderForwardClustered() {
|
||||||
defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
|
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";
|
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
|
//lightmaps
|
||||||
scene_state.max_lightmaps = MAX_LIGHTMAPS;
|
scene_state.max_lightmaps = MAX_LIGHTMAPS;
|
||||||
|
|
|
@ -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["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["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
|
||||||
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\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["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
|
||||||
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
|
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
|
||||||
|
|
||||||
actions.base_texture_binding_index = 1;
|
actions.base_texture_binding_index = 1;
|
||||||
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
|
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
|
||||||
actions.base_uniform_string = "material.";
|
actions.base_uniform_string = "material.";
|
||||||
actions.base_varying_index = 12;
|
actions.base_varying_index = 14;
|
||||||
|
|
||||||
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
|
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
|
||||||
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
|
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
|
||||||
|
|
|
@ -2800,6 +2800,11 @@ RenderForwardMobile::RenderForwardMobile() {
|
||||||
// defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
|
// 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";
|
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
|
//lightmaps
|
||||||
scene_state.max_lightmaps = 2;
|
scene_state.max_lightmaps = 2;
|
||||||
|
|
|
@ -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["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["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
|
||||||
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\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["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
|
||||||
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
|
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
|
||||||
|
|
||||||
|
|
|
@ -1974,6 +1974,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
|
||||||
default_canvas_texture = texture_storage->canvas_texture_allocate();
|
default_canvas_texture = texture_storage->canvas_texture_allocate();
|
||||||
texture_storage->canvas_texture_initialize(default_canvas_texture);
|
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");
|
state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size");
|
||||||
|
|
||||||
//create functions for shader and material
|
//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);
|
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET);
|
||||||
|
|
||||||
Item *current_clip = nullptr;
|
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++) {
|
for (uint32_t i = 0; i <= state.current_batch_index; i++) {
|
||||||
Batch *current_batch = &state.canvas_instance_batches[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->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[0] = r_current_batch->tex_info.texpixel_size.width;
|
||||||
instance_data->color_texture_pixel_size[1] = r_current_batch->tex_texpixel_size.height;
|
instance_data->color_texture_pixel_size[1] = r_current_batch->tex_info.texpixel_size.height;
|
||||||
instance_data->specular_shininess = r_current_batch->tex_specular_shininess;
|
instance_data->specular_shininess = r_current_batch->tex_info.specular_shininess;
|
||||||
|
|
||||||
return instance_data;
|
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);
|
bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF);
|
||||||
TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors);
|
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 = _new_batch(r_batch_broken);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, rect->texture);
|
_prepare_batch_texture_info(r_current_batch, rect->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color modulated = rect->modulate * base_color;
|
Color modulated = rect->modulate * base_color;
|
||||||
|
@ -2399,7 +2405,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
||||||
Rect2 dst_rect;
|
Rect2 dst_rect;
|
||||||
|
|
||||||
if (rect->texture.is_valid()) {
|
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);
|
dst_rect = Rect2(rect->rect.position, rect->rect.size);
|
||||||
|
|
||||||
if (dst_rect.size.width < 0) {
|
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);
|
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 = _new_batch(r_batch_broken);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, np->texture);
|
_prepare_batch_texture_info(r_current_batch, np->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceData *instance_data = new_instance_data();
|
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);
|
src_rect = Rect2(0, 0, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
if (np->source != Rect2()) {
|
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[0] = 1.0 / np->source.size.width;
|
||||||
instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height;
|
instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2553,10 +2559,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
|
||||||
r_current_batch->command = c;
|
r_current_batch->command = c;
|
||||||
|
|
||||||
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
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 = _new_batch(r_batch_broken);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, polygon->texture);
|
_prepare_batch_texture_info(r_current_batch, polygon->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pipeline variant
|
// 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];
|
r_current_batch->pipeline_variant = variant[primitive->point_count - 1];
|
||||||
|
|
||||||
TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
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 = _new_batch(r_batch_broken);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, primitive->texture);
|
_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) {
|
if (c->type == Item::Command::TYPE_MESH) {
|
||||||
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
|
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
|
||||||
TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, m->texture);
|
_prepare_batch_texture_info(r_current_batch, m->texture);
|
||||||
instance_data = new_instance_data();
|
instance_data = new_instance_data();
|
||||||
|
|
||||||
r_current_batch->mesh_instance_count = 1;
|
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);
|
TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, mm->texture);
|
_prepare_batch_texture_info(r_current_batch, mm->texture);
|
||||||
instance_data = new_instance_data();
|
instance_data = new_instance_data();
|
||||||
|
|
||||||
instance_data->flags |= 1; // multimesh, trails disabled
|
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);
|
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
|
||||||
TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors);
|
||||||
r_current_batch->set_tex_state(tex_state);
|
r_current_batch->tex_info.state = tex_state;
|
||||||
_prepare_batch_texture(r_current_batch, pt->texture);
|
_prepare_batch_texture_info(r_current_batch, pt->texture);
|
||||||
|
|
||||||
instance_data = new_instance_data();
|
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);
|
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) {
|
switch (p_batch->command_type) {
|
||||||
case Item::Command::TYPE_RECT:
|
case Item::Command::TYPE_RECT:
|
||||||
|
@ -2810,13 +2829,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
|
||||||
PushConstant push_constant;
|
PushConstant push_constant;
|
||||||
push_constant.base_instance_index = p_batch->start;
|
push_constant.base_instance_index = p_batch->start;
|
||||||
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
|
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_bind_index_array(p_draw_list, shader.quad_index_array);
|
||||||
RD::get_singleton()->draw_list_draw(p_draw_list, true, p_batch->instance_count);
|
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;
|
PushConstant push_constant;
|
||||||
push_constant.base_instance_index = p_batch->start;
|
push_constant.base_instance_index = p_batch->start;
|
||||||
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
|
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);
|
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
|
||||||
if (pb->indices.is_valid()) {
|
if (pb->indices.is_valid()) {
|
||||||
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices);
|
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;
|
PushConstant push_constant;
|
||||||
push_constant.base_instance_index = p_batch->start;
|
push_constant.base_instance_index = p_batch->start;
|
||||||
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
|
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]);
|
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;
|
uint32_t instance_count = p_batch->instance_count;
|
||||||
RD::get_singleton()->draw_list_draw(p_draw_list, true, 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;
|
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);
|
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 };
|
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);
|
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()) {
|
if (p_texture.is_null()) {
|
||||||
p_texture = default_canvas_texture;
|
p_texture = default_canvas_texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color specular_shininess;
|
RendererRD::TextureStorage::CanvasTextureInfo info =
|
||||||
bool use_normal;
|
RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(
|
||||||
bool use_specular;
|
|
||||||
Size2i size;
|
|
||||||
bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(
|
|
||||||
p_texture,
|
p_texture,
|
||||||
p_current_batch->tex_state.texture_filter(),
|
p_current_batch->tex_info.state.texture_filter(),
|
||||||
p_current_batch->tex_state.texture_repeat(),
|
p_current_batch->tex_info.state.texture_repeat(),
|
||||||
shader.default_version_rd_shader,
|
p_current_batch->tex_info.state.linear_colors(),
|
||||||
CANVAS_TEXTURE_UNIFORM_SET,
|
p_current_batch->tex_info.state.texture_is_data());
|
||||||
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());
|
|
||||||
// something odd happened
|
// something odd happened
|
||||||
if (!success) {
|
if (info.is_null()) {
|
||||||
_prepare_batch_texture(p_current_batch, default_canvas_texture);
|
_prepare_batch_texture_info(p_current_batch, default_canvas_texture);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
// cache values to be copied to instance data
|
// cache values to be copied to instance data
|
||||||
if (specular_shininess.a < 0.999) {
|
if (info.specular_color.a < 0.999) {
|
||||||
p_current_batch->tex_flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
|
p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_normal) {
|
if (info.use_normal) {
|
||||||
p_current_batch->tex_flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
|
p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t a = uint8_t(CLAMP(specular_shininess.a * 255.0, 0.0, 255.0));
|
uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0));
|
||||||
uint8_t b = uint8_t(CLAMP(specular_shininess.b * 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(specular_shininess.g * 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(specular_shininess.r * 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_specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
|
p_current_batch->tex_info.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));
|
p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.current_tex_uniform_set = p_uniform_set;
|
|
||||||
|
|
||||||
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, p_uniform_set, CANVAS_TEXTURE_UNIFORM_SET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RendererCanvasRenderRD::~RendererCanvasRenderRD() {
|
RendererCanvasRenderRD::~RendererCanvasRenderRD() {
|
||||||
|
|
|
@ -45,8 +45,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
||||||
BASE_UNIFORM_SET = 0,
|
BASE_UNIFORM_SET = 0,
|
||||||
MATERIAL_UNIFORM_SET = 1,
|
MATERIAL_UNIFORM_SET = 1,
|
||||||
TRANSFORMS_UNIFORM_SET = 2,
|
TRANSFORMS_UNIFORM_SET = 2,
|
||||||
CANVAS_TEXTURE_UNIFORM_SET = 3,
|
BATCH_UNIFORM_SET = 3,
|
||||||
INSTANCE_DATA_UNIFORM_SET = 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const int SAMPLERS_BINDING_FIRST_INDEX = 10;
|
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 {
|
struct Batch {
|
||||||
// Position in the UBO measured in bytes
|
// Position in the UBO measured in bytes
|
||||||
uint32_t start = 0;
|
uint32_t start = 0;
|
||||||
uint32_t instance_count = 0;
|
uint32_t instance_count = 0;
|
||||||
uint32_t instance_buffer_index = 0;
|
uint32_t instance_buffer_index = 0;
|
||||||
|
|
||||||
TextureState tex_state;
|
TextureInfo tex_info;
|
||||||
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;
|
|
||||||
|
|
||||||
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
|
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
@ -462,14 +462,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
||||||
uint32_t mesh_instance_count;
|
uint32_t mesh_instance_count;
|
||||||
};
|
};
|
||||||
bool has_blend = false;
|
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 {
|
struct DataBuffer {
|
||||||
|
@ -509,7 +501,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
||||||
uint32_t max_instances_per_buffer = 16384;
|
uint32_t max_instances_per_buffer = 16384;
|
||||||
uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData);
|
uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData);
|
||||||
|
|
||||||
RID current_tex_uniform_set;
|
RID current_batch_uniform_set;
|
||||||
|
|
||||||
LightUniform *light_uniforms = nullptr;
|
LightUniform *light_uniforms = nullptr;
|
||||||
|
|
||||||
|
@ -532,6 +524,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
||||||
|
|
||||||
Item *items[MAX_RENDER_ITEMS];
|
Item *items[MAX_RENDER_ITEMS];
|
||||||
|
|
||||||
|
TextureInfo default_texture_info;
|
||||||
|
|
||||||
bool using_directional_lights = false;
|
bool using_directional_lights = false;
|
||||||
RID default_canvas_texture;
|
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 _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 _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 _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 _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const;
|
||||||
void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set);
|
|
||||||
[[nodiscard]] Batch *_new_batch(bool &r_batch_broken);
|
[[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 _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch);
|
||||||
void _allocate_instance_buffer();
|
void _allocate_instance_buffer();
|
||||||
|
|
|
@ -54,11 +54,6 @@ struct InstanceData {
|
||||||
uint lights[4];
|
uint lights[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(set = 4, binding = 0, std430) restrict readonly buffer DrawData {
|
|
||||||
InstanceData data[];
|
|
||||||
}
|
|
||||||
instances;
|
|
||||||
|
|
||||||
layout(push_constant, std430) uniform Params {
|
layout(push_constant, std430) uniform Params {
|
||||||
uint base_instance_index; // base index to instance data
|
uint base_instance_index; // base index to instance data
|
||||||
uint pad1;
|
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 = 1) uniform texture2D normal_texture;
|
||||||
layout(set = 3, binding = 2) uniform texture2D specular_texture;
|
layout(set = 3, binding = 2) uniform texture2D specular_texture;
|
||||||
layout(set = 3, binding = 3) uniform sampler texture_sampler;
|
layout(set = 3, binding = 3) uniform sampler texture_sampler;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 4, std430) restrict readonly buffer DrawData {
|
||||||
|
InstanceData data[];
|
||||||
|
}
|
||||||
|
instances;
|
||||||
|
|
|
@ -156,8 +156,30 @@ vec2 multiview_uv(vec2 uv) {
|
||||||
ivec2 multiview_uv(ivec2 uv) {
|
ivec2 multiview_uv(ivec2 uv) {
|
||||||
return uv;
|
return uv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //USE_MULTIVIEW
|
#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;
|
invariant gl_Position;
|
||||||
|
|
||||||
#GLOBALS
|
#GLOBALS
|
||||||
|
@ -488,6 +510,145 @@ void vertex_shader(vec3 vertex_input,
|
||||||
screen_pos = gl_Position;
|
screen_pos = gl_Position;
|
||||||
#endif
|
#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
|
#ifdef MODE_RENDER_DEPTH
|
||||||
if (scene_data.pancake_shadows) {
|
if (scene_data.pancake_shadows) {
|
||||||
if (gl_Position.z >= 0.9999) {
|
if (gl_Position.z >= 0.9999) {
|
||||||
|
@ -791,7 +952,10 @@ ivec2 multiview_uv(ivec2 uv) {
|
||||||
return uv;
|
return uv;
|
||||||
}
|
}
|
||||||
#endif //USE_MULTIVIEW
|
#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
|
//defines to keep compatibility with vertex
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#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 specular_light = vec3(0.0, 0.0, 0.0);
|
||||||
vec3 diffuse_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);
|
vec3 ambient_light = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
#ifndef MODE_UNSHADED
|
#ifndef MODE_UNSHADED
|
||||||
// Used in regular draw pass and when drawing SDFs for SDFGI and materials for VoxelGI.
|
// Used in regular draw pass and when drawing SDFs for SDFGI and materials for VoxelGI.
|
||||||
emission *= scene_data.emissive_exposure_normalization;
|
emission *= scene_data.emissive_exposure_normalization;
|
||||||
|
@ -1836,6 +1999,11 @@ void fragment_shader(in SceneData scene_data) {
|
||||||
// LIGHTING
|
// LIGHTING
|
||||||
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
#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.
|
{ // Directional light.
|
||||||
|
|
||||||
// Do shadow and lighting in two passes to reduce register pressure.
|
// 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 shadow0 = 0;
|
||||||
uint shadow1 = 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++) {
|
for (uint i = 0; i < 8; i++) {
|
||||||
if (i >= scene_data.directional_light_count) {
|
if (i >= scene_data.directional_light_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
|
if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
|
||||||
continue; //not masked
|
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
|
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
|
#undef BIAS_FUNC
|
||||||
} // shadows
|
} // shadows
|
||||||
|
|
||||||
|
@ -2055,6 +2233,8 @@ void fragment_shader(in SceneData scene_data) {
|
||||||
}
|
}
|
||||||
#endif // SHADOWS_DISABLED
|
#endif // SHADOWS_DISABLED
|
||||||
|
|
||||||
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
|
|
||||||
for (uint i = 0; i < 8; i++) {
|
for (uint i = 0; i < 8; i++) {
|
||||||
if (i >= scene_data.directional_light_count) {
|
if (i >= scene_data.directional_light_count) {
|
||||||
break;
|
break;
|
||||||
|
@ -2175,8 +2355,10 @@ void fragment_shader(in SceneData scene_data) {
|
||||||
diffuse_light,
|
diffuse_light,
|
||||||
specular_light);
|
specular_light);
|
||||||
}
|
}
|
||||||
|
#endif // USE_VERTEX_LIGHTING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
{ //omni lights
|
{ //omni lights
|
||||||
|
|
||||||
uint cluster_omni_offset = cluster_offset;
|
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
|
#ifdef USE_SHADOW_TO_OPACITY
|
||||||
#ifndef MODE_RENDER_DEPTH
|
#ifndef MODE_RENDER_DEPTH
|
||||||
|
@ -2334,8 +2518,6 @@ void fragment_shader(in SceneData scene_data) {
|
||||||
#endif // !MODE_RENDER_DEPTH
|
#endif // !MODE_RENDER_DEPTH
|
||||||
#endif // USE_SHADOW_TO_OPACITY
|
#endif // USE_SHADOW_TO_OPACITY
|
||||||
|
|
||||||
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
|
||||||
|
|
||||||
#ifdef MODE_RENDER_DEPTH
|
#ifdef MODE_RENDER_DEPTH
|
||||||
|
|
||||||
#ifdef MODE_RENDER_SDF
|
#ifdef MODE_RENDER_SDF
|
||||||
|
|
|
@ -105,7 +105,16 @@ layout(location = 4) mediump out vec2 uv2_interp;
|
||||||
layout(location = 5) mediump out vec3 tangent_interp;
|
layout(location = 5) mediump out vec3 tangent_interp;
|
||||||
layout(location = 6) mediump out vec3 binormal_interp;
|
layout(location = 6) mediump out vec3 binormal_interp;
|
||||||
#endif
|
#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
|
#ifdef MATERIAL_UNIFORMS_USED
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms {
|
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 model_matrix = instances.data[draw_call.instance_index].transform;
|
||||||
mat4 inv_view_matrix = scene_data.inv_view_matrix;
|
mat4 inv_view_matrix = scene_data.inv_view_matrix;
|
||||||
|
|
||||||
#ifdef USE_DOUBLE_PRECISION
|
#ifdef USE_DOUBLE_PRECISION
|
||||||
vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
|
vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
|
||||||
model_matrix[0][3] = 0.0;
|
model_matrix[0][3] = 0.0;
|
||||||
|
@ -448,6 +458,107 @@ void main() {
|
||||||
binormal_interp = binormal;
|
binormal_interp = binormal;
|
||||||
#endif
|
#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_RENDER_DEPTH
|
||||||
|
|
||||||
#ifdef MODE_DUAL_PARABOLOID
|
#ifdef MODE_DUAL_PARABOLOID
|
||||||
|
@ -564,6 +675,11 @@ layout(location = 5) mediump in vec3 tangent_interp;
|
||||||
layout(location = 6) mediump in vec3 binormal_interp;
|
layout(location = 6) mediump in vec3 binormal_interp;
|
||||||
#endif
|
#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
|
#ifdef MODE_DUAL_PARABOLOID
|
||||||
|
|
||||||
layout(location = 9) highp in float dp_clip;
|
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"
|
#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.
|
// Default to SPECULAR_SCHLICK_GGX.
|
||||||
#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
|
#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"
|
#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
|
#ifndef MODE_RENDER_DEPTH
|
||||||
|
|
||||||
|
@ -1401,6 +1517,10 @@ void main() {
|
||||||
|
|
||||||
// LIGHTING
|
// LIGHTING
|
||||||
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
#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
|
if (!sc_disable_directional_lights) { //directional light
|
||||||
#ifndef SHADOWS_DISABLED
|
#ifndef SHADOWS_DISABLED
|
||||||
|
@ -1408,10 +1528,12 @@ void main() {
|
||||||
uint shadow0 = 0;
|
uint shadow0 = 0;
|
||||||
uint shadow1 = 0;
|
uint shadow1 = 0;
|
||||||
|
|
||||||
for (uint i = 0; i < 8; i++) {
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
if (i >= scene_data.directional_light_count) {
|
// Only process the first light's shadow for vertex lighting.
|
||||||
break;
|
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)) {
|
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
|
||||||
continue; //not masked
|
continue; //not masked
|
||||||
|
@ -1419,164 +1541,6 @@ void main() {
|
||||||
|
|
||||||
float shadow = 1.0;
|
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) {
|
if (directional_lights.data[i].shadow_opacity > 0.001) {
|
||||||
float depth_z = -vertex.z;
|
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
|
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
|
#undef BIAS_FUNC
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1678,13 +1646,8 @@ void main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SHADOWS_DISABLED
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
|
for (uint i = 0; i < scene_data.directional_light_count; i++) {
|
||||||
for (uint i = 0; i < 8; i++) {
|
|
||||||
if (i >= scene_data.directional_light_count) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
|
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
|
||||||
continue; //not masked
|
continue; //not masked
|
||||||
}
|
}
|
||||||
|
@ -1703,8 +1666,8 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
blur_shadow(shadow);
|
blur_shadow(shadow);
|
||||||
|
|
||||||
#ifdef DEBUG_DRAW_PSSM_SPLITS
|
|
||||||
vec3 tint = vec3(1.0);
|
vec3 tint = vec3(1.0);
|
||||||
|
#ifdef DEBUG_DRAW_PSSM_SPLITS
|
||||||
if (-vertex.z < directional_lights.data[i].shadow_split_offsets.x) {
|
if (-vertex.z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||||
tint = vec3(1.0, 0.0, 0.0);
|
tint = vec3(1.0, 0.0, 0.0);
|
||||||
} else if (-vertex.z < directional_lights.data[i].shadow_split_offsets.y) {
|
} else if (-vertex.z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||||
|
@ -1718,12 +1681,10 @@ void main() {
|
||||||
shadow = 1.0;
|
shadow = 1.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0,
|
float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0;
|
||||||
#ifndef DEBUG_DRAW_PSSM_SPLITS
|
|
||||||
directional_lights.data[i].color * directional_lights.data[i].energy,
|
light_compute(normal, directional_lights.data[i].direction, view, size_A,
|
||||||
#else
|
|
||||||
directional_lights.data[i].color * directional_lights.data[i].energy * tint,
|
directional_lights.data[i].color * directional_lights.data[i].energy * tint,
|
||||||
#endif
|
|
||||||
true, shadow, f0, orms, 1.0, albedo, alpha,
|
true, shadow, f0, orms, 1.0, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -1744,15 +1705,14 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
#ifdef LIGHT_ANISOTROPY_USED
|
#ifdef LIGHT_ANISOTROPY_USED
|
||||||
binormal, tangent, anisotropy,
|
binormal, tangent, anisotropy,
|
||||||
#endif
|
|
||||||
#ifdef USE_SOFT_SHADOW
|
|
||||||
directional_lights.data[i].size,
|
|
||||||
#endif
|
#endif
|
||||||
diffuse_light,
|
diffuse_light,
|
||||||
specular_light);
|
specular_light);
|
||||||
}
|
}
|
||||||
|
#endif // USE_VERTEX_LIGHTING
|
||||||
} //directional light
|
} //directional light
|
||||||
|
|
||||||
|
#ifndef USE_VERTEX_LIGHTING
|
||||||
if (!sc_disable_omni_lights) { //omni lights
|
if (!sc_disable_omni_lights) { //omni lights
|
||||||
uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
|
uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
|
||||||
for (uint i = 0; i < 8; i++) {
|
for (uint i = 0; i < 8; i++) {
|
||||||
|
@ -1771,6 +1731,7 @@ void main() {
|
||||||
|
|
||||||
shadow = blur_shadow(shadow);
|
shadow = blur_shadow(shadow);
|
||||||
|
|
||||||
|
// Fragment lighting
|
||||||
light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
|
light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
|
@ -1841,6 +1802,9 @@ void main() {
|
||||||
diffuse_light, specular_light);
|
diffuse_light, specular_light);
|
||||||
}
|
}
|
||||||
} //spot lights
|
} //spot lights
|
||||||
|
#endif // !VERTEX_LIGHTING
|
||||||
|
|
||||||
|
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
||||||
|
|
||||||
#ifdef USE_SHADOW_TO_OPACITY
|
#ifdef USE_SHADOW_TO_OPACITY
|
||||||
#ifndef MODE_RENDER_DEPTH
|
#ifndef MODE_RENDER_DEPTH
|
||||||
|
@ -1855,8 +1819,6 @@ void main() {
|
||||||
#endif // !MODE_RENDER_DEPTH
|
#endif // !MODE_RENDER_DEPTH
|
||||||
#endif // USE_SHADOW_TO_OPACITY
|
#endif // USE_SHADOW_TO_OPACITY
|
||||||
|
|
||||||
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
|
||||||
|
|
||||||
#ifdef MODE_RENDER_DEPTH
|
#ifdef MODE_RENDER_DEPTH
|
||||||
|
|
||||||
#ifdef MODE_RENDER_MATERIAL
|
#ifdef MODE_RENDER_MATERIAL
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -40,25 +40,12 @@ using namespace RendererRD;
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// TextureStorage::CanvasTexture
|
// TextureStorage::CanvasTexture
|
||||||
|
|
||||||
void TextureStorage::CanvasTexture::clear_sets() {
|
void TextureStorage::CanvasTexture::clear_cache() {
|
||||||
if (cleared_cache) {
|
info_cache[0] = CanvasTextureCache();
|
||||||
return;
|
info_cache[1] = CanvasTextureCache();
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureStorage::CanvasTexture::~CanvasTexture() {
|
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;
|
ct->specular = p_texture;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
ct->clear_cache();
|
||||||
ct->clear_sets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
|
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.g = p_specular_color.g;
|
||||||
ct->specular_color.b = p_specular_color.b;
|
ct->specular_color.b = p_specular_color.b;
|
||||||
ct->specular_color.a = p_shininess;
|
ct->specular_color.a = p_shininess;
|
||||||
ct->clear_sets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
|
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);
|
ERR_FAIL_NULL(ct);
|
||||||
|
|
||||||
ct->texture_filter = p_filter;
|
ct->texture_filter = p_filter;
|
||||||
ct->clear_sets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
|
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);
|
ERR_FAIL_NULL(ct);
|
||||||
|
|
||||||
ct->texture_repeat = p_repeat;
|
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();
|
MaterialStorage *material_storage = MaterialStorage::get_singleton();
|
||||||
|
|
||||||
CanvasTexture *ct = nullptr;
|
CanvasTexture *ct = nullptr;
|
||||||
Texture *t = get_texture(p_texture);
|
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) {
|
if (t) {
|
||||||
//regular texture
|
//regular texture
|
||||||
if (!t->canvas_texture) {
|
if (!t->canvas_texture) {
|
||||||
|
@ -667,93 +648,71 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ct) {
|
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;
|
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;
|
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)];
|
CanvasTextureCache &ctc = ct->info_cache[int(p_use_srgb)];
|
||||||
if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
|
if (!RD::get_singleton()->texture_is_valid(ctc.diffuse) ||
|
||||||
//create and update
|
!RD::get_singleton()->texture_is_valid(ctc.normal) ||
|
||||||
Vector<RD::Uniform> uniforms;
|
!RD::get_singleton()->texture_is_valid(ctc.specular)) {
|
||||||
{ //diffuse
|
{ //diffuse
|
||||||
RD::Uniform u;
|
|
||||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
|
||||||
u.binding = 0;
|
|
||||||
|
|
||||||
t = get_texture(ct->diffuse);
|
t = get_texture(ct->diffuse);
|
||||||
if (!t) {
|
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);
|
ct->size_cache = Size2i(1, 1);
|
||||||
} else {
|
} 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);
|
ct->size_cache = Size2i(t->width_2d, t->height_2d);
|
||||||
if (t->render_target) {
|
if (t->render_target) {
|
||||||
t->render_target->was_used = true;
|
t->render_target->was_used = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uniforms.push_back(u);
|
|
||||||
}
|
}
|
||||||
{ //normal
|
{ //normal
|
||||||
RD::Uniform u;
|
|
||||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
|
||||||
u.binding = 1;
|
|
||||||
|
|
||||||
t = get_texture(ct->normal_map);
|
t = get_texture(ct->normal_map);
|
||||||
if (!t) {
|
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;
|
ct->use_normal_cache = false;
|
||||||
} else {
|
} else {
|
||||||
u.append_id(t->rd_texture);
|
ctc.normal = t->rd_texture;
|
||||||
ct->use_normal_cache = true;
|
ct->use_normal_cache = true;
|
||||||
if (t->render_target) {
|
if (t->render_target) {
|
||||||
t->render_target->was_used = true;
|
t->render_target->was_used = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uniforms.push_back(u);
|
|
||||||
}
|
}
|
||||||
{ //specular
|
{ //specular
|
||||||
RD::Uniform u;
|
|
||||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
|
||||||
u.binding = 2;
|
|
||||||
|
|
||||||
t = get_texture(ct->specular);
|
t = get_texture(ct->specular);
|
||||||
if (!t) {
|
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;
|
ct->use_specular_cache = false;
|
||||||
} else {
|
} else {
|
||||||
u.append_id(t->rd_texture);
|
ctc.specular = t->rd_texture;
|
||||||
ct->use_specular_cache = true;
|
ct->use_specular_cache = true;
|
||||||
if (t->render_target) {
|
if (t->render_target) {
|
||||||
t->render_target->was_used = true;
|
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);
|
CanvasTextureInfo res;
|
||||||
ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set;
|
res.diffuse = ctc.diffuse;
|
||||||
ct->cleared_cache = false;
|
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;
|
||||||
|
|
||||||
r_uniform_set = uniform_set;
|
return res;
|
||||||
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;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Texture API */
|
/* Texture API */
|
||||||
|
|
|
@ -76,6 +76,21 @@ public:
|
||||||
TYPE_3D
|
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:
|
private:
|
||||||
friend class LightStorage;
|
friend class LightStorage;
|
||||||
friend class MaterialStorage;
|
friend class MaterialStorage;
|
||||||
|
@ -86,6 +101,12 @@ private:
|
||||||
|
|
||||||
/* Canvas Texture API */
|
/* Canvas Texture API */
|
||||||
|
|
||||||
|
struct CanvasTextureCache {
|
||||||
|
RID diffuse = RID();
|
||||||
|
RID normal = RID();
|
||||||
|
RID specular = RID();
|
||||||
|
};
|
||||||
|
|
||||||
class CanvasTexture {
|
class CanvasTexture {
|
||||||
public:
|
public:
|
||||||
RID diffuse;
|
RID diffuse;
|
||||||
|
@ -96,14 +117,14 @@ private:
|
||||||
|
|
||||||
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
|
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
|
||||||
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_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);
|
Size2i size_cache = Size2i(1, 1);
|
||||||
bool use_normal_cache = false;
|
bool use_normal_cache = false;
|
||||||
bool use_specular_cache = false;
|
bool use_specular_cache = false;
|
||||||
bool cleared_cache = true;
|
bool cleared_cache = true;
|
||||||
|
|
||||||
void clear_sets();
|
void clear_cache();
|
||||||
~CanvasTexture();
|
~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_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
|
||||||
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) 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 */
|
/* Texture API */
|
||||||
|
|
||||||
|
|
|
@ -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(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_RST("rendering/shading/overrides/force_vertex_shading", false);
|
||||||
GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true);
|
|
||||||
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false);
|
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false);
|
||||||
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true);
|
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true);
|
||||||
|
|
||||||
|
|
|
@ -650,6 +650,10 @@ comments and a patch is provided in the `patches` folder.
|
||||||
|
|
||||||
Collection of single-file libraries used in Godot components.
|
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}`
|
- `clipper.{cpp,hpp}`
|
||||||
* Upstream: https://sourceforge.net/projects/polyclipping
|
* Upstream: https://sourceforge.net/projects/polyclipping
|
||||||
* Version: 6.4.2 (2017) + Godot changes (added optional exceptions handling)
|
* 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.
|
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
|
## tinyexr
|
||||||
|
|
||||||
- Upstream: https://github.com/syoyo/tinyexr
|
- Upstream: https://github.com/syoyo/tinyexr
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 )
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
|
@ -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
|
|
Loading…
Reference in New Issue