Files
Chris Babcock edb4242cb2 Copying //UE4/Dev-Mobile to //UE4/Dev-Main (Source: //UE4/Dev-Mobile @ 3771565)
#lockdown Nick.Penwarden
#rb none

============================
  MAJOR FEATURES & CHANGES
============================

Change 3627858 by Sorin.Gradinaru

	#jira UE-48948 Crash when pressing backspace on empty line

	Fixed:
	UE-48948 Backspace on empty line crashes app (virtual keyboard)
	UE-49112 Virtual keyboard text field isn't visible after rotating from landscape to portrait
	UE-49117 Chinese and Korean virtual keyboards don't allow native characters
	UE-49120 Virtual keyboard number pad "kicks" user back to regular keyboard
	UE-49121 Gboard and Swift swipe entry are not supported by Virtual keyboard
	UE-49124 Cursor in virtual keyboard and UMG don't match
	UE-49128 Virtual Keyboard text field doesn't appear if there is too much text
	UE-49141 Virtual keyboard is unresponsive with repeated tapping in control (some devices)
	UE-49139 Tapping in the same text box doesn't make the virtual keyboard disappear

Change 3630732 by Sorin.Gradinaru

	#jira UE-43488 GitHub 3440 : Fixes exposure with planar reflections.

	#3440
	Cancelled the applied exposure scale for non-hdr mobile

Change 3631436 by Nick.Shin

	HTML5

	recommended fix for "RuntimeError: integer result unrepresentable" from the emscripten makers

	#jira UE-49059  HTML5 - Unable to launch project onto HTML 5 from editor

Change 3632689 by Sorin.Gradinaru

	#jira UE - 49301 Text in UMG controls flickers during update from Virtual Keyboard

	Full refresh of the Slate control for Android experimental VK - the control has focus, but the cursor was removed

Change 3632769 by Adrian.Chelu

	#jira UEMOB-403 Improvements to "Device Mobile Preview" feature

Change 3633305 by Allan.Bentham

	Print out the callstack when a fatal error occurs.

Change 3633510 by Chris.Babcock

	Remove unneeded logging
	#jira none

Change 3634827 by Adrian.Chelu

	#fixed build editor buildsystem linux

Change 3640610 by Adrian.Chelu

	#fixed Cook Win64 warnings
	#fixed UE4Editor Static Analysis Win64 warnings

Change 3663057 by Sorin.Gradinaru

	UE-49301 Text in UMG controls flickers during update from Virtual Keyboard
	#jira UE-49301
	#ue4
	#android

	On some Android devices TextWatcher.onTextChanged gets called multiple times when typing/deleting the content of a EditText (internally, the first call resets the entire content, the second fills it with the new value)
	The workaround is to delays sending "empty string" to the Slate, waiting for 100ms to see if there is a second call (the "real" string to update)

	The CL contains a fix for a 5/5 crash : select some/all the text from the native edittext, press delete.

Change 3663630 by Jack.Porter

	Fix shader compile error on Galaxy S6

Change 3663972 by Allan.Bentham

	add ES3.1 framebuffer fetch.
	#jira UE-46251

Change 3671843 by Nick.Shin

	HTML5 - silence CIS warnings (changed to INFO message type)

	#jira UE-50415  ( Pri:1 - 4.18 )  //UE4/Release-4.18: Step "Package ShooterClient HTML5" has completed with 1 Warning: "File packager is creating an asset bundle of 815 MB. This is very large"

Change 3677675 by Sorin.Gradinaru

	Android Experimental Virtual Keyboard 4.18 issues
	#jira UE-49124 Cursor in virtual keyboard and UMG don't match
	#jira UE-49139 Tapping in the same text box doesn't make the virtual keyboard disappear
	#jira UE-49141 Virtual keyboard is unresponsive with repeated tapping in control (some devices)
	#ue4
	#android

	UE-49124 Cursor in virtual keyboard and UMG don't match - change in SlateTextLayout.cpp  - OnPaint() don't display the cursor

	Changed the show/hide vk routines (Game activity.java) to solve low-repro, Android O issues related to multiple click events.
	Should also be tested with multiple text boxes (fast click in/out different types of TextBox controls)

Change 3681555 by Adrian.Chelu

	UEMOB-403 Improvements to "Device Mobile Preview" feature

Change 3692020 by Sorin.Gradinaru

	#jira UE-50645 Carriage returns can be pasted into single line UMG fields on Android
	#ue4
	#4.19
	#android

Change 3692741 by Sorin.Gradinaru

	Andoid 3D WebBrowser
	#jira UE-32740 Web Browser on a Widget Component appears to be 2D when launching on to Android
	#ue4
	#android

Change 3695475 by Chris.Babcock

	Per project Android NDK/SDK API settings
	#jira UEMOB-394
	#ue4
	#android

Change 3701364 by Dmitriy.Dyomin

	Fixed: WEX - Android - Log spammed with "LogRHI: Error: Unsupported EPixelFormat 28"
	#jira UE-50714

Change 3701664 by Jack.Porter

	Fix typo

Change 3702355 by Cosmin.Sulea

	UEMOB-393 - Support "ETC 1.5" packaging
	#jira UEMOB-393

Change 3704950 by Chris.Babcock

	Add verification of support for cooked texture format(s) on device at runtime (optional with Validate texture formats checkbox in Android project settings) and skipped for cook on the fly
	#jira UE-50837
	#ue4
	#android

Change 3709817 by Nick.Shin

	HTML5 - silence CIS warnings (changed to INFO message type)

	finally have a repo case to test this proper fix

	#jira UE-50415  ( Pri:1 - 4.18 )  "Package ShooterClient HTML5" has completed with 1 Warning: "File packager is creating an asset bundle of 815 MB. This is very large"

Change 3717598 by Chris.Babcock

	Fix Android icon paths
	#jira UE-51585
	#ue4
	#android

Change 3718456 by Adrian.Chelu

	#fixed spelling in category localized name

Change 3719643 by Nick.Shin

	nuke PLATFORM_HTML5_WIN32

	more "old" code to remove

	#jira UEMOB-433  Remove Win32 SDL "HTML5 Simulator" code

Change 3720342 by Nick.Shin

	HTML5 redirect logs to console window

	#jira UE-50747  HTML5 log is not easily accessible to users

Change 3720652 by Sorin.Gradinaru

	UE-50382 Xcode Address Sanitizer feature does not work on iOS
	#jira 50382
	#iOS
	#ue4

	Address sanitizer dylib loader depends on the default SDKROOT parameter (<scheme> => Build Settings => Base SDK => <Build Configuration>)
	For macosx or missing (also translated as macosx), the path is incorrect for iphone/appletv.

Change 3720654 by Sorin.Gradinaru

	UE-48499 Android Voice Module has a few issues
	#jira 48499
	#Android
	#ue4

	1.Circular Buffer:  Does the engine already have an implementation? Do we want this into core libraries?
	R: There is an generic template class TCircularBuffer, but it lacks functionality like write/read checks, reading/writing data chunks.
	Plus the code from VoiceModuleAndroid is optimized for circular byte array. I suggest to keep it.

	2. Possible memory leaks: void free_circular_buffer (circular_buffer *p) is implemented, but not used. Presumably a memory leak on the variable inrb. Does CreateAudioRecorder need to be paired with any kind of destroy on shutdown?
	R: Fixed. Using an array ActiveVoiceCaptures to store VoiceCapture references (same as on Windows)

	3. Init() There are 4 calls to setup/init things that store the result in "result" but only the last call is checked against success. Should more checks against the values be made at each stage with informative log messaging in the event of failure?
	R: Fixed.

	4. GetVoiceData()
	// Workaround for dealing with noise after stand-by
	while(bytes<InVoiceBufferSize)
	{
		OutVoiceBuffer[bytes++]=0;
	}
	Isn't this just a memzero?
	R: Fixed.

	5. Missing features. Need to implement GetBufferSize and DumpState
	R: Added GetBufferSize. Can be used like in TestVoice.cpp
	DumpState is never used (same on Mac, iOS), plus the OpenSL objects do not expose internal properties.

Change 3722554 by Cosmin.Sulea

	UE-44224 - iOS - Remote Build - rsync error: files not transferred
	#jira UE-44224

Change 3723265 by Allan.Bentham

	Assign a texture format priority for ETC1a.
	prevents launch on from using ETC1a all the time..

Change 3729764 by Dmitriy.Dyomin

	Removed deprecated LightmapUVBias, ShadowmapUVBias from instanced static mesh component per-instance data (80 -> 64 bytes)

Change 3729899 by Dmitriy.Dyomin

	Fixed tiled landcape re-import

Change 3730895 by Bogdan.Vasilache

	UEMOB-442 --> [ Support texture streaming on Android ES 3.1 ]
	#jira UEMOB-442

Change 3733463 by Chris.Babcock

	Return error for external texture if not used in pixel shader
	#jira UE-51763
	#ue4

Change 3736226 by Chris.Babcock

	Change ExposureScale to PreExposure
	#jira UE-52007
	#jira UE-51691
	#ue4
	#android

Change 3740509 by Allan.Bentham

	Add LQ (direct lighting from stationary spot/point lights) to volumetric lightmaps.
	#jira UE-50551

Change 3740586 by Cosmin.Sulea

	UE-51747 - GitHub 4174 : [BUG-FIX] Invalid ASTC texture versioning is corrected.
	#jira UE-51747

Change 3741110 by Chris.Babcock

	Fix functional code in checks removed for shipping
	#ue4

Change 3741117 by Chris.Babcock

	Fix checkin error for check -> ensure fix
	#ue4

Change 3741156 by Chris.Babcock

	Swap order of SDK and NDK overrides in menu to match Android SDK settings
	#jira UE-52019
	#ue4
	#android

Change 3741271 by Chris.Babcock

	Use final NDK and SDK levels only in UEBuildSettings.txt and rename the overrides to be clearer
	#jira UE-52058
	#ue4
	#android

Change 3741464 by Chris.Babcock

	Add NDK and SDK platform validation (installed) for Android
	#jira UE-52069
	#ue4
	#android

Change 3744602 by Josh.Adams

	From Meerkat: - Added optional 0 or 1 param to showlayer that will set the visibility instead of toggling it for entire layer

Change 3744603 by Josh.Adams

	From Meerkat: - Fixed a comment about debug view modes on consoles

Change 3744607 by Josh.Adams

	From Meerkat: - Added HWInstances to the PrimitiveStats view in Statistics window

Change 3754890 by Chris.Babcock

	Updated IntelISPCTexComp DLLs to fix crashes with some processors on Windows
	#jira UE-52281
	#ue4

Change 3755147 by Jack.Porter

	Fixed Google Cardboard rendering upside down on iPhone 6S+
	#jira  UE-38555

Change 3755458 by Cosmin.Sulea

	UE-47801 - RSync Error when Generating SSH Key for Remote Mac Building when Mac username contains a space
	#jira UE-47801

Change 3755492 by Jack.Porter

	Fix merge error

Change 3759140 by Bogdan.Vasilache

	UE-52396 --> Assertion in FOpenGLDynamicRHI::CreateOpenGLTexture when launching on Mali Galaxy S III
	#jira UE-52396

Change 3760536 by Sorin.Gradinaru

	UE-51262 values for pinch input produce very different results for same area on android device
	#jira 51262
	#iOS
	#Android
	#ue4

	1. When the pinch goes beyond the viewport boundaries (when zooming out),  the touch that goes off-screen is "released" and the zooming effect is over.
	Solved by remembering last pinch event values

	2. "Hack" the initial distance for the pinch/ rotate, by touching the screen and moving the finger to another position before using the second finger.
	Solved by using the correct values  when the pinch event starts

Change 3761279 by Chris.Babcock

	Flag vertex and fragment shaders belonging to materials with external textures
	#jira UE-52398
	#ue4
	#android

Change 3761494 by Chris.Babcock

	Fix access to FrameUpdateInfo in MediaPlayer14.java and CameraPlayer14.java with Proguard
	#jira UE-52471
	#ue4
	#android

Change 3763146 by Jack.Porter

	Default assets for web browser widget
	#jira UE-51374

Change 3764242 by Chris.Babcock

	Disable Niagara vertex factories for mobile and Switch
	#jira UE-52425
	#ue4
	#mobile
	#switch

Change 3766027 by Allan.Bentham

	Fix crash when no LQ volumetric lightmap data exists
	#jira UE-52508

Change 3766075 by Josh.Adams

	- Updating UDKRemote. Still needs art updated, and some some unneeded assets removed

Change 3766141 by Allan.Bentham

	Show unbuilt lightmap warning when LQ data is missing from volumetric lightmap in mobile shading mode.

Change 3766163 by Josh.Adams

	- Updated icons and added a generator script when we get a new one

Change 3766560 by Allan.Bentham

	Workaround for broken offsets with automation screenshots.

	#jira UE-52491

Change 3767193 by Peter.Sauerbrei

	remove Oculus shader from being cached
	force a metal shader re-compile

	#jira UE-52587

Change 3767604 by Peter.Sauerbrei

	fix the Oculusshader the right way

	#jira UE-52587

Change 3768543 by Sorin.Gradinaru

	Android WebBrowser 3D - webbrowser plugin contins the assets, 2D behaviour restored

	#Android
	#UE4
	#4.19
	#jira UE-51374 Web Browser widget is not working on Android
	#jira UE-52399 Android web browser does not accept input


Change 3663915 by Jack.Porter

	Prevent FTcpListener from busy polling while waiting for connections
	#jira UE-50125

Change 3709224 by Allan.Bentham

	Add android target device to gauntlet.
	Automation screenshot uses high res screenshot api for mobile.

	#jira UEMOB-360

Change 3741453 by Chris.Babcock

	Match the 4.18.1 fixes for shipping checks removing code (from CL3741091)
	#ue4

Change 3769301 by Peter.Sauerbrei

	fix for missing ue4_stdmetal.lib, courtesty of MarkS
	#jira UE-52587

Change 3770597 by Sorin.Gradinaru

	Android WebBrowser - remove the WebBrowser plugin reference from the Engine
	Load the default material directly from the resources.

	#Android
	#UE4
	#jira UE-51374 Web Browser widget is not working on Android
	#jira UE-52399 Android web browser does not accept input

[CL 3771573 by Chris Babcock in Main branch]
2017-11-22 16:42:04 -05:00

3537 lines
138 KiB
C++

/*
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "AndroidETC.h"
#include "CoreMinimal.h"
#include "GenericPlatform/GenericPlatformMath.h"
#include "AndroidETC.h"
#include "AndroidETCInternal.h"
#include "RHI.h"
IMPLEMENT_MODULE( Fdetex, detex );
Fdetex::Fdetex()
{
}
Fdetex::~Fdetex()
{
}
void Fdetex::StartupModule()
{
}
void Fdetex::ShutdownModule()
{
}
/* Maximum uncompressed block size in bytes. */
#define DETEX_MAX_BLOCK_SIZE 256
/* Compressed texture format definitions for general texture decompression */
/* functions. */
#define DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(n) ((uint32_t)n << 24)
/* Mode mask flags. */
enum
{
DETEX_MODE_MASK_ETC_INDIVIDUAL = 0x1,
DETEX_MODE_MASK_ETC_DIFFERENTIAL = 0x2,
DETEX_MODE_MASK_ETC_T = 0x4,
DETEX_MODE_MASK_ETC_H = 0x8,
DETEX_MODE_MASK_ETC_PLANAR = 0x10,
DETEX_MODE_MASK_ALL_MODES_ETC1 = 0x3,
DETEX_MODE_MASK_ALL_MODES_ETC2 = 0x1F,
DETEX_MODE_MASK_ALL_MODES_ETC2_PUNCHTHROUGH = 0X1E,
DETEX_MODE_MASK_ALL_MODES_BPTC = 0xFF,
DETEX_MODE_MASK_ALL_MODES_BPTC_FLOAT = 0x3FFF,
DETEX_MODE_MASK_ALL = 0XFFFFFFFF,
};
/* Decompression function flags. */
enum
{
/* Function returns false (invalid block) when the compressed block */
/* is in a format not allowed to be generated by an encoder. */
DETEX_DECOMPRESS_FLAG_ENCODE = 0x1,
/* For compression formats that have opaque and non-opaque modes, */
/* return false (invalid block) when the compressed block is encoded */
/* using a non-opaque mode. */
DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY = 0x2,
/* For compression formats that have opaque and non-opaque modes, */
/* return false (invalid block) when the compressed block is encoded */
/* using an opaque mode. */
DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY = 0x4,
};
enum
{
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_UNCOMPRESSED = 0,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1 = 1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT1 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_S3TC = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT1A = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT3 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT5 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC4_UNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC4_SNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC5_UNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC5_SNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC6H_UF16 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC6H_SF16 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC7 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC1,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_PUNCHTHROUGH,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_EAC,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_R11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_R11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_RG11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_RG11,
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ASTC_4X4,
};
typedef struct
{
uint32_t texture_format;
int ktx_support;
int dds_support;
const char *text1;
const char *text2;
int block_width; // The block width (1 for uncompressed textures).
int block_height; // The block height (1 for uncompressed textures).
int gl_internal_format;
uint32_t gl_format;
uint32_t gl_type;
const char *dx_four_cc;
int dx10_format;
} detexTextureFileInfo;
enum
{
DETEX_TEXTURE_FORMAT_PIXEL_FORMAT_MASK = 0x0000FFFF,
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT = 0x00800000,
DETEX_TEXTURE_FORMAT_BC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1) |
DETEX_PIXEL_FORMAT_RGBX8
),
DETEX_TEXTURE_FORMAT_BC1A = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A) |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_BC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_BC3 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_RGTC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1) |
DETEX_PIXEL_FORMAT_R8
),
DETEX_TEXTURE_FORMAT_SIGNED_RGTC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1) |
DETEX_PIXEL_FORMAT_SIGNED_R16
),
DETEX_TEXTURE_FORMAT_RGTC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RG8
),
DETEX_TEXTURE_FORMAT_SIGNED_RGTC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_SIGNED_RG16
),
DETEX_TEXTURE_FORMAT_BPTC_FLOAT = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_FLOAT_RGBX16
),
DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16
),
DETEX_TEXTURE_FORMAT_BPTC = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_ETC1 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC1) |
DETEX_PIXEL_FORMAT_RGBX8
),
DETEX_TEXTURE_FORMAT_ETC2 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2) |
DETEX_PIXEL_FORMAT_RGBX8
),
DETEX_TEXTURE_FORMAT_ETC2_PUNCHTHROUGH = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_PUNCHTHROUGH) |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_ETC2_EAC = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_EAC) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
DETEX_TEXTURE_FORMAT_EAC_R11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_R11) |
DETEX_PIXEL_FORMAT_R16
),
DETEX_TEXTURE_FORMAT_EAC_SIGNED_R11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_R11) |
DETEX_PIXEL_FORMAT_SIGNED_R16
),
DETEX_TEXTURE_FORMAT_EAC_RG11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_RG11) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RG16
),
DETEX_TEXTURE_FORMAT_EAC_SIGNED_RG11 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_RG11) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_SIGNED_RG16
),
DETEX_TEXTURE_FORMAT_ASTC_4X4 = (
DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(
DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ASTC_4X4) |
DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT |
DETEX_PIXEL_FORMAT_RGBA8
),
};
static const detexTextureFileInfo texture_info[] =
{
// Texture format KTX/DDS Textual representations Block
// support size OpenGL ID in KTX files DDS file IDs
// internalFormat, format, type FourCC, DX10 format
// Compressed formats.
{ DETEX_TEXTURE_FORMAT_BC1, 1, 1, "BC1", "DXT1", 4, 4, 0x83F0, 0, 0, "DXT1", 0 },
{ DETEX_TEXTURE_FORMAT_BC1A, 1, 1, "BC1A", "DXT1A", 4, 4, 0x83F1, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_BC2, 1, 1, "BC2", "DXT3", 4, 4, 0x83F2, 0, 0, "DXT3", 0 },
{ DETEX_TEXTURE_FORMAT_BC3, 1, 1, "BC3", "DXT5", 4, 4, 0x83F3, 0, 0, "DXT5", 0 },
{ DETEX_TEXTURE_FORMAT_RGTC1, 1, 1, "RGTC1", "BC4_UNORM", 4, 4, 0x8DBB, 0, 0, "DX10", 80 },
{ DETEX_TEXTURE_FORMAT_SIGNED_RGTC1, 1, 1, "SIGNED_RGTC1", "BC4_SNORM", 4, 4, 0x8DBC, 0, 0, "DX10", 81 },
{ DETEX_TEXTURE_FORMAT_RGTC2, 1, 1, "RGTC2", "BC5_UNORM", 4, 4, 0x8DBD, 0, 0, "DX10", 83 },
{ DETEX_TEXTURE_FORMAT_SIGNED_RGTC2, 1, 1, "SIGNED_RGTC2", "BC5_SNORM", 4, 4, 0x8DBE, 0, 0, "DX10", 84 },
{ DETEX_TEXTURE_FORMAT_BPTC_FLOAT, 1, 1, "BPTC_FLOAT", "BC6H_UF16", 4, 4, 0x8E8F, 0, 0, "DX10", 95 },
{ DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT, 1, 1, "BPTC_SIGNED_FLOAT", "BC6H_SF16", 4, 4, 0x8E8E, 0, 0, "DX10", 96 },
{ DETEX_TEXTURE_FORMAT_BPTC, 1, 1, "BPTC", "BC7", 4, 4, 0x8E8C, 0, 0, "DX10", 98 },
{ DETEX_TEXTURE_FORMAT_ETC1, 1, 0, "ETC1", "", 4, 4, 0x8D64, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ETC2, 1, 0, "ETC2", "ETC2_RGB8", 4, 4, 0x9274, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ETC2_PUNCHTHROUGH, 1, 0, "ETC2_PUNCHTHROUGH", "", 4, 4, 0x9275, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ETC2_EAC, 1, 0, "ETC2_EAC", "EAC", 4, 4, 0x9278, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_R11, 1, 0, "EAC_R11", "", 4, 4, 0x9270, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_SIGNED_R11, 1, 0, "EAC_SIGNED_R11", "", 4, 4, 0x9271, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_RG11, 1, 0, "EAC_RG11", "", 4, 4, 0x9272, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_EAC_SIGNED_RG11, 1, 0, "EAC_SIGNED_RG11", "", 4, 4, 0x9273, 0, 0, "", 0 },
{ DETEX_TEXTURE_FORMAT_ASTC_4X4, 1, 0, "ASTC_4x4", "", 4, 4, 0x93B0, 0, 0, "DX10", 134 }
};
#define DETEX_NU_TEXTURE_INFO_ENTRIES (sizeof(texture_info) / sizeof(texture_info[0]))
const uint8_t detex_bptc_table_P2[64 * 16] = {
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,
0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,
0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,
0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,
0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,
0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,
0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,
0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1,
0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,
0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0,
0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0,
0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,
0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,
0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,
0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0,
0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,
0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,
0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0,
0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,
0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,
0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,
0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,
0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,
0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0,
0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0,
0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,
0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1,
0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,
0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,
0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,
0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,
0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,
0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0,
0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,
0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1,
0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0,
0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,
0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1,
0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1,
0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,
0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1,
0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1,
0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,
0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,
0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1
};
const uint8_t detex_bptc_table_P3[64 * 16] = {
0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2,
0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1,
0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1,
0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1,
0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2,
0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2,
0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1,
0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1,
0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,
0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,
0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,
0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,
0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2,
0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2,
0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2,
0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0,
0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2,
0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0,
0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2,
0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1,
0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2,
0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1,
0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2,
0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0,
0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0,
0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2,
0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0,
0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1,
0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2,
0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2,
0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1,
0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1,
0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2,
0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1,
0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2,
0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0,
0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0,
0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,
0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0,
0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1,
0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1,
0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2,
0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1,
0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,
0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1,
0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1,
0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1,
0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1,
0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2,
0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1,
0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2,
0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2,
0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2,
0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2,
0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2,
0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2,
0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2,
0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2,
0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2,
0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2,
0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1,
0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,
0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,
0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0,
};
const uint8_t detex_bptc_table_anchor_index_second_subset[64] = {
15, 15,15,15,15,15,15,15,
15, 15,15,15,15,15,15,15,
15, 2, 8, 2, 2, 8, 8,15,
2, 8, 2, 2, 8, 8, 2, 2,
15, 15, 6, 8, 2, 8,15,15,
2, 8, 2, 2, 2,15,15, 6,
6, 2, 6, 8,15,15, 2, 2,
15, 15,15,15,15, 2, 2,15
};
const uint8_t detex_bptc_table_anchor_index_second_subset_of_three[64] = {
3, 3, 15, 15, 8, 3, 15, 15,
8, 8, 6, 6, 6, 5, 3, 3,
3, 3, 8, 15, 3, 3, 6, 10,
5, 8, 8, 6, 8, 5, 15, 15,
8, 15, 3, 5, 6, 10, 8, 15,
15, 3, 15, 5, 15, 15, 15, 15,
3, 15, 5, 5, 5, 8, 5, 10,
5, 10, 8, 13, 15, 12, 3, 3
};
const uint8_t detex_bptc_table_anchor_index_third_subset[64] = {
15, 8, 8, 3,15,15, 3, 8,
15,15,15,15,15,15,15, 8,
15, 8,15, 3,15, 8,15, 8,
3,15, 6,10,15,15,10, 8,
15, 3,15,10,10, 8, 9,10,
6,15, 8,15, 3, 6, 6, 8,
15, 3,15,15,15,15,15,15,
15,15,15,15, 3,15,15, 8
};
const uint16_t detex_bptc_table_aWeight2[4] = { 0, 21, 43, 64 };
const uint16_t detex_bptc_table_aWeight3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 };
const uint16_t detex_bptc_table_aWeight4[16] = {
0, 4, 9, 13, 17, 21, 26, 30,
34, 38, 43, 47, 51, 55, 60, 64
};
static const int8_t map_mode_table[32] = {
0, 1, 2, 10, -1, -1, 3, 11, -1, -1, 4, 12, -1, -1, 5, 13,
-1, -1, 6, -1, -1, -1, 7, -1, -1, -1, 8, -1, -1, -1, 9, -1
};
static const uint8_t bptc_float_EPB[14] = { 10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16 };
static const int complement3bitshifted_table[8] = { 0, 8, 16, 24, -32, -24, -16, -8 };
static const int modifier_table[8][4] = {
{ 2, 8, -2, -8 },
{ 5, 17, -5, -17 },
{ 9, 29, -9, -29 },
{ 13, 42, -13, -42 },
{ 18, 60, -18, -60 },
{ 24, 80, -24, -80 },
{ 33, 106, -33, -106 },
{ 47, 183, -47, -183 }
};
const uint8_t detex_division_by_3_table[768] =
{
0, 0, 0, 1, 1, 1, 2, 2,
2, 3, 3, 3, 4, 4, 4, 5,
5, 5, 6, 6, 6, 7, 7, 7,
8, 8, 8, 9, 9, 9, 10, 10,
10, 11, 11, 11, 12, 12, 12, 13,
13, 13, 14, 14, 14, 15, 15, 15,
16, 16, 16, 17, 17, 17, 18, 18,
18, 19, 19, 19, 20, 20, 20, 21,
21, 21, 22, 22, 22, 23, 23, 23,
24, 24, 24, 25, 25, 25, 26, 26,
26, 27, 27, 27, 28, 28, 28, 29,
29, 29, 30, 30, 30, 31, 31, 31,
32, 32, 32, 33, 33, 33, 34, 34,
34, 35, 35, 35, 36, 36, 36, 37,
37, 37, 38, 38, 38, 39, 39, 39,
40, 40, 40, 41, 41, 41, 42, 42,
42, 43, 43, 43, 44, 44, 44, 45,
45, 45, 46, 46, 46, 47, 47, 47,
48, 48, 48, 49, 49, 49, 50, 50,
50, 51, 51, 51, 52, 52, 52, 53,
53, 53, 54, 54, 54, 55, 55, 55,
56, 56, 56, 57, 57, 57, 58, 58,
58, 59, 59, 59, 60, 60, 60, 61,
61, 61, 62, 62, 62, 63, 63, 63,
64, 64, 64, 65, 65, 65, 66, 66,
66, 67, 67, 67, 68, 68, 68, 69,
69, 69, 70, 70, 70, 71, 71, 71,
72, 72, 72, 73, 73, 73, 74, 74,
74, 75, 75, 75, 76, 76, 76, 77,
77, 77, 78, 78, 78, 79, 79, 79,
80, 80, 80, 81, 81, 81, 82, 82,
82, 83, 83, 83, 84, 84, 84, 85,
85, 85, 86, 86, 86, 87, 87, 87,
88, 88, 88, 89, 89, 89, 90, 90,
90, 91, 91, 91, 92, 92, 92, 93,
93, 93, 94, 94, 94, 95, 95, 95,
96, 96, 96, 97, 97, 97, 98, 98,
98, 99, 99, 99, 100, 100, 100, 101,
101, 101, 102, 102, 102, 103, 103, 103,
104, 104, 104, 105, 105, 105, 106, 106,
106, 107, 107, 107, 108, 108, 108, 109,
109, 109, 110, 110, 110, 111, 111, 111,
112, 112, 112, 113, 113, 113, 114, 114,
114, 115, 115, 115, 116, 116, 116, 117,
117, 117, 118, 118, 118, 119, 119, 119,
120, 120, 120, 121, 121, 121, 122, 122,
122, 123, 123, 123, 124, 124, 124, 125,
125, 125, 126, 126, 126, 127, 127, 127,
128, 128, 128, 129, 129, 129, 130, 130,
130, 131, 131, 131, 132, 132, 132, 133,
133, 133, 134, 134, 134, 135, 135, 135,
136, 136, 136, 137, 137, 137, 138, 138,
138, 139, 139, 139, 140, 140, 140, 141,
141, 141, 142, 142, 142, 143, 143, 143,
144, 144, 144, 145, 145, 145, 146, 146,
146, 147, 147, 147, 148, 148, 148, 149,
149, 149, 150, 150, 150, 151, 151, 151,
152, 152, 152, 153, 153, 153, 154, 154,
154, 155, 155, 155, 156, 156, 156, 157,
157, 157, 158, 158, 158, 159, 159, 159,
160, 160, 160, 161, 161, 161, 162, 162,
162, 163, 163, 163, 164, 164, 164, 165,
165, 165, 166, 166, 166, 167, 167, 167,
168, 168, 168, 169, 169, 169, 170, 170,
170, 171, 171, 171, 172, 172, 172, 173,
173, 173, 174, 174, 174, 175, 175, 175,
176, 176, 176, 177, 177, 177, 178, 178,
178, 179, 179, 179, 180, 180, 180, 181,
181, 181, 182, 182, 182, 183, 183, 183,
184, 184, 184, 185, 185, 185, 186, 186,
186, 187, 187, 187, 188, 188, 188, 189,
189, 189, 190, 190, 190, 191, 191, 191,
192, 192, 192, 193, 193, 193, 194, 194,
194, 195, 195, 195, 196, 196, 196, 197,
197, 197, 198, 198, 198, 199, 199, 199,
200, 200, 200, 201, 201, 201, 202, 202,
202, 203, 203, 203, 204, 204, 204, 205,
205, 205, 206, 206, 206, 207, 207, 207,
208, 208, 208, 209, 209, 209, 210, 210,
210, 211, 211, 211, 212, 212, 212, 213,
213, 213, 214, 214, 214, 215, 215, 215,
216, 216, 216, 217, 217, 217, 218, 218,
218, 219, 219, 219, 220, 220, 220, 221,
221, 221, 222, 222, 222, 223, 223, 223,
224, 224, 224, 225, 225, 225, 226, 226,
226, 227, 227, 227, 228, 228, 228, 229,
229, 229, 230, 230, 230, 231, 231, 231,
232, 232, 232, 233, 233, 233, 234, 234,
234, 235, 235, 235, 236, 236, 236, 237,
237, 237, 238, 238, 238, 239, 239, 239,
240, 240, 240, 241, 241, 241, 242, 242,
242, 243, 243, 243, 244, 244, 244, 245,
245, 245, 246, 246, 246, 247, 247, 247,
248, 248, 248, 249, 249, 249, 250, 250,
250, 251, 251, 251, 252, 252, 252, 253,
253, 253, 254, 254, 254, 255, 255, 255,
};
const uint8_t detex_division_by_7_table[1792] =
{
0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 3, 3, 3,
3, 3, 3, 3, 4, 4, 4, 4,
4, 4, 4, 5, 5, 5, 5, 5,
5, 5, 6, 6, 6, 6, 6, 6,
6, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 9,
9, 9, 9, 9, 9, 9, 10, 10,
10, 10, 10, 10, 10, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12,
12, 12, 12, 13, 13, 13, 13, 13,
13, 13, 14, 14, 14, 14, 14, 14,
14, 15, 15, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18,
18, 18, 18, 18, 18, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20,
20, 20, 20, 21, 21, 21, 21, 21,
21, 21, 22, 22, 22, 22, 22, 22,
22, 23, 23, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 24, 24, 25,
25, 25, 25, 25, 25, 25, 26, 26,
26, 26, 26, 26, 26, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28,
28, 28, 28, 29, 29, 29, 29, 29,
29, 29, 30, 30, 30, 30, 30, 30,
30, 31, 31, 31, 31, 31, 31, 31,
32, 32, 32, 32, 32, 32, 32, 33,
33, 33, 33, 33, 33, 33, 34, 34,
34, 34, 34, 34, 34, 35, 35, 35,
35, 35, 35, 35, 36, 36, 36, 36,
36, 36, 36, 37, 37, 37, 37, 37,
37, 37, 38, 38, 38, 38, 38, 38,
38, 39, 39, 39, 39, 39, 39, 39,
40, 40, 40, 40, 40, 40, 40, 41,
41, 41, 41, 41, 41, 41, 42, 42,
42, 42, 42, 42, 42, 43, 43, 43,
43, 43, 43, 43, 44, 44, 44, 44,
44, 44, 44, 45, 45, 45, 45, 45,
45, 45, 46, 46, 46, 46, 46, 46,
46, 47, 47, 47, 47, 47, 47, 47,
48, 48, 48, 48, 48, 48, 48, 49,
49, 49, 49, 49, 49, 49, 50, 50,
50, 50, 50, 50, 50, 51, 51, 51,
51, 51, 51, 51, 52, 52, 52, 52,
52, 52, 52, 53, 53, 53, 53, 53,
53, 53, 54, 54, 54, 54, 54, 54,
54, 55, 55, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 56, 56, 57,
57, 57, 57, 57, 57, 57, 58, 58,
58, 58, 58, 58, 58, 59, 59, 59,
59, 59, 59, 59, 60, 60, 60, 60,
60, 60, 60, 61, 61, 61, 61, 61,
61, 61, 62, 62, 62, 62, 62, 62,
62, 63, 63, 63, 63, 63, 63, 63,
64, 64, 64, 64, 64, 64, 64, 65,
65, 65, 65, 65, 65, 65, 66, 66,
66, 66, 66, 66, 66, 67, 67, 67,
67, 67, 67, 67, 68, 68, 68, 68,
68, 68, 68, 69, 69, 69, 69, 69,
69, 69, 70, 70, 70, 70, 70, 70,
70, 71, 71, 71, 71, 71, 71, 71,
72, 72, 72, 72, 72, 72, 72, 73,
73, 73, 73, 73, 73, 73, 74, 74,
74, 74, 74, 74, 74, 75, 75, 75,
75, 75, 75, 75, 76, 76, 76, 76,
76, 76, 76, 77, 77, 77, 77, 77,
77, 77, 78, 78, 78, 78, 78, 78,
78, 79, 79, 79, 79, 79, 79, 79,
80, 80, 80, 80, 80, 80, 80, 81,
81, 81, 81, 81, 81, 81, 82, 82,
82, 82, 82, 82, 82, 83, 83, 83,
83, 83, 83, 83, 84, 84, 84, 84,
84, 84, 84, 85, 85, 85, 85, 85,
85, 85, 86, 86, 86, 86, 86, 86,
86, 87, 87, 87, 87, 87, 87, 87,
88, 88, 88, 88, 88, 88, 88, 89,
89, 89, 89, 89, 89, 89, 90, 90,
90, 90, 90, 90, 90, 91, 91, 91,
91, 91, 91, 91, 92, 92, 92, 92,
92, 92, 92, 93, 93, 93, 93, 93,
93, 93, 94, 94, 94, 94, 94, 94,
94, 95, 95, 95, 95, 95, 95, 95,
96, 96, 96, 96, 96, 96, 96, 97,
97, 97, 97, 97, 97, 97, 98, 98,
98, 98, 98, 98, 98, 99, 99, 99,
99, 99, 99, 99, 100, 100, 100, 100,
100, 100, 100, 101, 101, 101, 101, 101,
101, 101, 102, 102, 102, 102, 102, 102,
102, 103, 103, 103, 103, 103, 103, 103,
104, 104, 104, 104, 104, 104, 104, 105,
105, 105, 105, 105, 105, 105, 106, 106,
106, 106, 106, 106, 106, 107, 107, 107,
107, 107, 107, 107, 108, 108, 108, 108,
108, 108, 108, 109, 109, 109, 109, 109,
109, 109, 110, 110, 110, 110, 110, 110,
110, 111, 111, 111, 111, 111, 111, 111,
112, 112, 112, 112, 112, 112, 112, 113,
113, 113, 113, 113, 113, 113, 114, 114,
114, 114, 114, 114, 114, 115, 115, 115,
115, 115, 115, 115, 116, 116, 116, 116,
116, 116, 116, 117, 117, 117, 117, 117,
117, 117, 118, 118, 118, 118, 118, 118,
118, 119, 119, 119, 119, 119, 119, 119,
120, 120, 120, 120, 120, 120, 120, 121,
121, 121, 121, 121, 121, 121, 122, 122,
122, 122, 122, 122, 122, 123, 123, 123,
123, 123, 123, 123, 124, 124, 124, 124,
124, 124, 124, 125, 125, 125, 125, 125,
125, 125, 126, 126, 126, 126, 126, 126,
126, 127, 127, 127, 127, 127, 127, 127,
128, 128, 128, 128, 128, 128, 128, 129,
129, 129, 129, 129, 129, 129, 130, 130,
130, 130, 130, 130, 130, 131, 131, 131,
131, 131, 131, 131, 132, 132, 132, 132,
132, 132, 132, 133, 133, 133, 133, 133,
133, 133, 134, 134, 134, 134, 134, 134,
134, 135, 135, 135, 135, 135, 135, 135,
136, 136, 136, 136, 136, 136, 136, 137,
137, 137, 137, 137, 137, 137, 138, 138,
138, 138, 138, 138, 138, 139, 139, 139,
139, 139, 139, 139, 140, 140, 140, 140,
140, 140, 140, 141, 141, 141, 141, 141,
141, 141, 142, 142, 142, 142, 142, 142,
142, 143, 143, 143, 143, 143, 143, 143,
144, 144, 144, 144, 144, 144, 144, 145,
145, 145, 145, 145, 145, 145, 146, 146,
146, 146, 146, 146, 146, 147, 147, 147,
147, 147, 147, 147, 148, 148, 148, 148,
148, 148, 148, 149, 149, 149, 149, 149,
149, 149, 150, 150, 150, 150, 150, 150,
150, 151, 151, 151, 151, 151, 151, 151,
152, 152, 152, 152, 152, 152, 152, 153,
153, 153, 153, 153, 153, 153, 154, 154,
154, 154, 154, 154, 154, 155, 155, 155,
155, 155, 155, 155, 156, 156, 156, 156,
156, 156, 156, 157, 157, 157, 157, 157,
157, 157, 158, 158, 158, 158, 158, 158,
158, 159, 159, 159, 159, 159, 159, 159,
160, 160, 160, 160, 160, 160, 160, 161,
161, 161, 161, 161, 161, 161, 162, 162,
162, 162, 162, 162, 162, 163, 163, 163,
163, 163, 163, 163, 164, 164, 164, 164,
164, 164, 164, 165, 165, 165, 165, 165,
165, 165, 166, 166, 166, 166, 166, 166,
166, 167, 167, 167, 167, 167, 167, 167,
168, 168, 168, 168, 168, 168, 168, 169,
169, 169, 169, 169, 169, 169, 170, 170,
170, 170, 170, 170, 170, 171, 171, 171,
171, 171, 171, 171, 172, 172, 172, 172,
172, 172, 172, 173, 173, 173, 173, 173,
173, 173, 174, 174, 174, 174, 174, 174,
174, 175, 175, 175, 175, 175, 175, 175,
176, 176, 176, 176, 176, 176, 176, 177,
177, 177, 177, 177, 177, 177, 178, 178,
178, 178, 178, 178, 178, 179, 179, 179,
179, 179, 179, 179, 180, 180, 180, 180,
180, 180, 180, 181, 181, 181, 181, 181,
181, 181, 182, 182, 182, 182, 182, 182,
182, 183, 183, 183, 183, 183, 183, 183,
184, 184, 184, 184, 184, 184, 184, 185,
185, 185, 185, 185, 185, 185, 186, 186,
186, 186, 186, 186, 186, 187, 187, 187,
187, 187, 187, 187, 188, 188, 188, 188,
188, 188, 188, 189, 189, 189, 189, 189,
189, 189, 190, 190, 190, 190, 190, 190,
190, 191, 191, 191, 191, 191, 191, 191,
192, 192, 192, 192, 192, 192, 192, 193,
193, 193, 193, 193, 193, 193, 194, 194,
194, 194, 194, 194, 194, 195, 195, 195,
195, 195, 195, 195, 196, 196, 196, 196,
196, 196, 196, 197, 197, 197, 197, 197,
197, 197, 198, 198, 198, 198, 198, 198,
198, 199, 199, 199, 199, 199, 199, 199,
200, 200, 200, 200, 200, 200, 200, 201,
201, 201, 201, 201, 201, 201, 202, 202,
202, 202, 202, 202, 202, 203, 203, 203,
203, 203, 203, 203, 204, 204, 204, 204,
204, 204, 204, 205, 205, 205, 205, 205,
205, 205, 206, 206, 206, 206, 206, 206,
206, 207, 207, 207, 207, 207, 207, 207,
208, 208, 208, 208, 208, 208, 208, 209,
209, 209, 209, 209, 209, 209, 210, 210,
210, 210, 210, 210, 210, 211, 211, 211,
211, 211, 211, 211, 212, 212, 212, 212,
212, 212, 212, 213, 213, 213, 213, 213,
213, 213, 214, 214, 214, 214, 214, 214,
214, 215, 215, 215, 215, 215, 215, 215,
216, 216, 216, 216, 216, 216, 216, 217,
217, 217, 217, 217, 217, 217, 218, 218,
218, 218, 218, 218, 218, 219, 219, 219,
219, 219, 219, 219, 220, 220, 220, 220,
220, 220, 220, 221, 221, 221, 221, 221,
221, 221, 222, 222, 222, 222, 222, 222,
222, 223, 223, 223, 223, 223, 223, 223,
224, 224, 224, 224, 224, 224, 224, 225,
225, 225, 225, 225, 225, 225, 226, 226,
226, 226, 226, 226, 226, 227, 227, 227,
227, 227, 227, 227, 228, 228, 228, 228,
228, 228, 228, 229, 229, 229, 229, 229,
229, 229, 230, 230, 230, 230, 230, 230,
230, 231, 231, 231, 231, 231, 231, 231,
232, 232, 232, 232, 232, 232, 232, 233,
233, 233, 233, 233, 233, 233, 234, 234,
234, 234, 234, 234, 234, 235, 235, 235,
235, 235, 235, 235, 236, 236, 236, 236,
236, 236, 236, 237, 237, 237, 237, 237,
237, 237, 238, 238, 238, 238, 238, 238,
238, 239, 239, 239, 239, 239, 239, 239,
240, 240, 240, 240, 240, 240, 240, 241,
241, 241, 241, 241, 241, 241, 242, 242,
242, 242, 242, 242, 242, 243, 243, 243,
243, 243, 243, 243, 244, 244, 244, 244,
244, 244, 244, 245, 245, 245, 245, 245,
245, 245, 246, 246, 246, 246, 246, 246,
246, 247, 247, 247, 247, 247, 247, 247,
248, 248, 248, 248, 248, 248, 248, 249,
249, 249, 249, 249, 249, 249, 250, 250,
250, 250, 250, 250, 250, 251, 251, 251,
251, 251, 251, 251, 252, 252, 252, 252,
252, 252, 252, 253, 253, 253, 253, 253,
253, 253, 254, 254, 254, 254, 254, 254,
254, 255, 255, 255, 255, 255, 255, 255,
};
const uint8_t detex_division_by_5_table[1280] =
{
0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 4, 4, 4, 4,
4, 5, 5, 5, 5, 5, 6, 6,
6, 6, 6, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 9, 9, 9,
9, 9, 10, 10, 10, 10, 10, 11,
11, 11, 11, 11, 12, 12, 12, 12,
12, 13, 13, 13, 13, 13, 14, 14,
14, 14, 14, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 17, 17, 17,
17, 17, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 20, 20, 20, 20,
20, 21, 21, 21, 21, 21, 22, 22,
22, 22, 22, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 25, 25, 25,
25, 25, 26, 26, 26, 26, 26, 27,
27, 27, 27, 27, 28, 28, 28, 28,
28, 29, 29, 29, 29, 29, 30, 30,
30, 30, 30, 31, 31, 31, 31, 31,
32, 32, 32, 32, 32, 33, 33, 33,
33, 33, 34, 34, 34, 34, 34, 35,
35, 35, 35, 35, 36, 36, 36, 36,
36, 37, 37, 37, 37, 37, 38, 38,
38, 38, 38, 39, 39, 39, 39, 39,
40, 40, 40, 40, 40, 41, 41, 41,
41, 41, 42, 42, 42, 42, 42, 43,
43, 43, 43, 43, 44, 44, 44, 44,
44, 45, 45, 45, 45, 45, 46, 46,
46, 46, 46, 47, 47, 47, 47, 47,
48, 48, 48, 48, 48, 49, 49, 49,
49, 49, 50, 50, 50, 50, 50, 51,
51, 51, 51, 51, 52, 52, 52, 52,
52, 53, 53, 53, 53, 53, 54, 54,
54, 54, 54, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 57, 57, 57,
57, 57, 58, 58, 58, 58, 58, 59,
59, 59, 59, 59, 60, 60, 60, 60,
60, 61, 61, 61, 61, 61, 62, 62,
62, 62, 62, 63, 63, 63, 63, 63,
64, 64, 64, 64, 64, 65, 65, 65,
65, 65, 66, 66, 66, 66, 66, 67,
67, 67, 67, 67, 68, 68, 68, 68,
68, 69, 69, 69, 69, 69, 70, 70,
70, 70, 70, 71, 71, 71, 71, 71,
72, 72, 72, 72, 72, 73, 73, 73,
73, 73, 74, 74, 74, 74, 74, 75,
75, 75, 75, 75, 76, 76, 76, 76,
76, 77, 77, 77, 77, 77, 78, 78,
78, 78, 78, 79, 79, 79, 79, 79,
80, 80, 80, 80, 80, 81, 81, 81,
81, 81, 82, 82, 82, 82, 82, 83,
83, 83, 83, 83, 84, 84, 84, 84,
84, 85, 85, 85, 85, 85, 86, 86,
86, 86, 86, 87, 87, 87, 87, 87,
88, 88, 88, 88, 88, 89, 89, 89,
89, 89, 90, 90, 90, 90, 90, 91,
91, 91, 91, 91, 92, 92, 92, 92,
92, 93, 93, 93, 93, 93, 94, 94,
94, 94, 94, 95, 95, 95, 95, 95,
96, 96, 96, 96, 96, 97, 97, 97,
97, 97, 98, 98, 98, 98, 98, 99,
99, 99, 99, 99, 100, 100, 100, 100,
100, 101, 101, 101, 101, 101, 102, 102,
102, 102, 102, 103, 103, 103, 103, 103,
104, 104, 104, 104, 104, 105, 105, 105,
105, 105, 106, 106, 106, 106, 106, 107,
107, 107, 107, 107, 108, 108, 108, 108,
108, 109, 109, 109, 109, 109, 110, 110,
110, 110, 110, 111, 111, 111, 111, 111,
112, 112, 112, 112, 112, 113, 113, 113,
113, 113, 114, 114, 114, 114, 114, 115,
115, 115, 115, 115, 116, 116, 116, 116,
116, 117, 117, 117, 117, 117, 118, 118,
118, 118, 118, 119, 119, 119, 119, 119,
120, 120, 120, 120, 120, 121, 121, 121,
121, 121, 122, 122, 122, 122, 122, 123,
123, 123, 123, 123, 124, 124, 124, 124,
124, 125, 125, 125, 125, 125, 126, 126,
126, 126, 126, 127, 127, 127, 127, 127,
128, 128, 128, 128, 128, 129, 129, 129,
129, 129, 130, 130, 130, 130, 130, 131,
131, 131, 131, 131, 132, 132, 132, 132,
132, 133, 133, 133, 133, 133, 134, 134,
134, 134, 134, 135, 135, 135, 135, 135,
136, 136, 136, 136, 136, 137, 137, 137,
137, 137, 138, 138, 138, 138, 138, 139,
139, 139, 139, 139, 140, 140, 140, 140,
140, 141, 141, 141, 141, 141, 142, 142,
142, 142, 142, 143, 143, 143, 143, 143,
144, 144, 144, 144, 144, 145, 145, 145,
145, 145, 146, 146, 146, 146, 146, 147,
147, 147, 147, 147, 148, 148, 148, 148,
148, 149, 149, 149, 149, 149, 150, 150,
150, 150, 150, 151, 151, 151, 151, 151,
152, 152, 152, 152, 152, 153, 153, 153,
153, 153, 154, 154, 154, 154, 154, 155,
155, 155, 155, 155, 156, 156, 156, 156,
156, 157, 157, 157, 157, 157, 158, 158,
158, 158, 158, 159, 159, 159, 159, 159,
160, 160, 160, 160, 160, 161, 161, 161,
161, 161, 162, 162, 162, 162, 162, 163,
163, 163, 163, 163, 164, 164, 164, 164,
164, 165, 165, 165, 165, 165, 166, 166,
166, 166, 166, 167, 167, 167, 167, 167,
168, 168, 168, 168, 168, 169, 169, 169,
169, 169, 170, 170, 170, 170, 170, 171,
171, 171, 171, 171, 172, 172, 172, 172,
172, 173, 173, 173, 173, 173, 174, 174,
174, 174, 174, 175, 175, 175, 175, 175,
176, 176, 176, 176, 176, 177, 177, 177,
177, 177, 178, 178, 178, 178, 178, 179,
179, 179, 179, 179, 180, 180, 180, 180,
180, 181, 181, 181, 181, 181, 182, 182,
182, 182, 182, 183, 183, 183, 183, 183,
184, 184, 184, 184, 184, 185, 185, 185,
185, 185, 186, 186, 186, 186, 186, 187,
187, 187, 187, 187, 188, 188, 188, 188,
188, 189, 189, 189, 189, 189, 190, 190,
190, 190, 190, 191, 191, 191, 191, 191,
192, 192, 192, 192, 192, 193, 193, 193,
193, 193, 194, 194, 194, 194, 194, 195,
195, 195, 195, 195, 196, 196, 196, 196,
196, 197, 197, 197, 197, 197, 198, 198,
198, 198, 198, 199, 199, 199, 199, 199,
200, 200, 200, 200, 200, 201, 201, 201,
201, 201, 202, 202, 202, 202, 202, 203,
203, 203, 203, 203, 204, 204, 204, 204,
204, 205, 205, 205, 205, 205, 206, 206,
206, 206, 206, 207, 207, 207, 207, 207,
208, 208, 208, 208, 208, 209, 209, 209,
209, 209, 210, 210, 210, 210, 210, 211,
211, 211, 211, 211, 212, 212, 212, 212,
212, 213, 213, 213, 213, 213, 214, 214,
214, 214, 214, 215, 215, 215, 215, 215,
216, 216, 216, 216, 216, 217, 217, 217,
217, 217, 218, 218, 218, 218, 218, 219,
219, 219, 219, 219, 220, 220, 220, 220,
220, 221, 221, 221, 221, 221, 222, 222,
222, 222, 222, 223, 223, 223, 223, 223,
224, 224, 224, 224, 224, 225, 225, 225,
225, 225, 226, 226, 226, 226, 226, 227,
227, 227, 227, 227, 228, 228, 228, 228,
228, 229, 229, 229, 229, 229, 230, 230,
230, 230, 230, 231, 231, 231, 231, 231,
232, 232, 232, 232, 232, 233, 233, 233,
233, 233, 234, 234, 234, 234, 234, 235,
235, 235, 235, 235, 236, 236, 236, 236,
236, 237, 237, 237, 237, 237, 238, 238,
238, 238, 238, 239, 239, 239, 239, 239,
240, 240, 240, 240, 240, 241, 241, 241,
241, 241, 242, 242, 242, 242, 242, 243,
243, 243, 243, 243, 244, 244, 244, 244,
244, 245, 245, 245, 245, 245, 246, 246,
246, 246, 246, 247, 247, 247, 247, 247,
248, 248, 248, 248, 248, 249, 249, 249,
249, 249, 250, 250, 250, 250, 250, 251,
251, 251, 251, 251, 252, 252, 252, 252,
252, 253, 253, 253, 253, 253, 254, 254,
254, 254, 254, 255, 255, 255, 255, 255,
};
const uint8_t detex_clamp0to255_table[255 + 256 + 256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};
typedef bool (*detexDecompressBlockFuncType)(const uint8_t *bitstring, uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer);
/**
*/
typedef struct
{
uint32_t format;
uint8_t *data;
int width;
int height;
int width_in_blocks;
int height_in_blocks;
} FDetexTexture;
/** Data structure used to extract bits from 128-bit bitstring. */
typedef struct
{
uint64_t data0;
uint64_t data1;
int index;
} FDetexBlock128;
static int detexMatchConversion(uint32_t source_pixel_format, uint32_t target_pixel_format, uint32_t *conversion);
uint32_t detexBlock128ExtractBits(FDetexBlock128 *block, int nu_bits)
{
uint32_t value = 0;
for (int i = 0; i < nu_bits; i++)
{
if (block->index < 64)
{
int shift = block->index - i;
if (shift < 0)
value |= (block->data0 & ((uint64_t)1 << block->index)) << (-shift);
else
value |= (block->data0 & ((uint64_t)1 << block->index)) >> shift;
}
else
{
int shift = ((block->index - 64) - i);
if (shift < 0)
value |= (block->data1 & ((uint64_t)1 << (block->index - 64))) << (-shift);
else
value |= (block->data1 & ((uint64_t)1 << (block->index - 64))) >> shift;
}
block->index++;
}
// if (block->index > 128)
// printf("Block overflow (%d)\n", block->index);
return value;
}
/** Return the compressed texture type index of a texture format. */
static DETEX_INLINE_ONLY uint32_t detexGetCompressedFormat(uint32_t texture_format)
{
return texture_format >> 24;
}
/** Return the block size of a compressed texture format in bytes. */
static DETEX_INLINE_ONLY uint32_t detexGetCompressedBlockSize(uint32_t texture_format)
{
return 8 + ((texture_format & DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT) >> 20);
}
/* Return the pixel format of a texture format. */
static DETEX_INLINE_ONLY uint32_t detexGetPixelFormat(uint32_t texture_format)
{
return texture_format & DETEX_TEXTURE_FORMAT_PIXEL_FORMAT_MASK;
}
/* Integer division using look-up tables, used by BC1/2/3 and RGTC (BC4/5) */
/* decompression. */
static DETEX_INLINE_ONLY uint32_t detexDivide0To767By3(uint32_t value)
{
return detex_division_by_3_table[value];
}
static DETEX_INLINE_ONLY uint32_t detexDivide0To1791By7(uint32_t value)
{
return detex_division_by_7_table[value];
}
static DETEX_INLINE_ONLY int8_t detexSignInt32(int v)
{
return (int8_t)((v >> 31) | -(-v >> 31));
}
static DETEX_INLINE_ONLY int detexDivideMinus895To895By7(int value)
{
return (int8_t)detex_division_by_7_table[abs(value)] * detexSignInt32(value);
}
static DETEX_INLINE_ONLY uint32_t detexDivide0To1279By5(uint32_t value)
{
return detex_division_by_5_table[value];
}
static DETEX_INLINE_ONLY int detexDivideMinus639To639By5(int value)
{
return (int8_t)detex_division_by_5_table[abs(value)] * detexSignInt32(value);
}
/** Return bitfield from bit0 to bit1 from 64-bit bitstring. */
static DETEX_INLINE_ONLY uint32_t detexGetBits64(uint64_t data, int bit0, int bit1)
{
return (data & (((uint64_t)1 << (bit1 + 1)) - 1)) >> bit0;
}
/** Return reversed bitfield (bit1 to bit0) from 64-bit bitstring. */
static DETEX_INLINE_ONLY uint32_t detexGetBits64Reversed(uint64_t data, int bit0, int bit1)
{
// Assumes bit0 > bit1.
// Reverse the bits.
uint32_t val = 0;
for (int i = 0; i <= bit0 - bit1; i++)
{
int shift_right = bit0 - 2 * i;
if (shift_right >= 0)
val |= (data & ((uint64_t)1 << (bit0 - i))) >> shift_right;
else
val |= (data & ((uint64_t)1 << (bit0 - i))) << (-shift_right);
}
return val;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC1 format. */
bool detexDecompressBlockBC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[0];
#else
uint32_t colors = ((uint32_t)bitstring[0] << 24) |
((uint32_t)bitstring[1] << 16) |
((uint32_t)bitstring[2] << 8) | bitstring[3];
#endif
// Decode the two 5-6-5 RGB colors.
int color_r[4], color_g[4], color_b[4];
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16))
{
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
}
else
{
color_r[2] = (color_r[0] + color_r[1]) / 2;
color_g[2] = (color_g[0] + color_g[1]) / 2;
color_b[2] = (color_b[0] + color_b[1]) / 2;
color_r[3] = color_g[3] = color_b[3] = 0;
}
uint32_t pixels = *(uint32_t *)&bitstring[4];
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGB8Alpha0xFF(color_r[pixel], color_g[pixel], color_b[pixel]);
}
return true;
}
uint32_t detexGetModeBC1(const uint8_t *bitstring)
{
uint32_t colors = *(uint32_t *)bitstring;
if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16))
return 0;
else
return 1;
}
void detexSetModeBC1(uint8_t *bitstring, uint32_t mode, uint32_t flags, uint32_t *colors)
{
uint32_t colorbits = *(uint32_t *)bitstring;
uint32_t current_mode;
if ((colorbits & 0xFFFF) > ((colorbits & 0xFFFF0000) >> 16))
current_mode = 0;
else
current_mode = 1;
if (current_mode != mode)
{
colorbits = ((colorbits & 0xFFFF) << 16) | (colorbits >> 16);
*(uint32_t *)bitstring = colorbits;
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC1A format. */
bool detexDecompressBlockBC1A(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[0];
#else
uint32_t colors = ((uint32_t)bitstring[0] << 24) |
((uint32_t)bitstring[1] << 16) |
((uint32_t)bitstring[2] << 8) | bitstring[3];
#endif
bool opaque = ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16));
if (opaque && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY))
return false;
if (!opaque && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return false;
// Decode the two 5-6-5 RGB colors.
int color_r[4], color_g[4], color_b[4], color_a[4];
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
color_a[0] = color_a[1] = color_a[2] = color_a[3] = 0xFF;
if (opaque)
{
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
}
else
{
color_r[2] = (color_r[0] + color_r[1]) / 2;
color_g[2] = (color_g[0] + color_g[1]) / 2;
color_b[2] = (color_b[0] + color_b[1]) / 2;
color_r[3] = color_g[3] = color_b[3] = color_a[3] = 0;
}
uint32_t pixels = *(uint32_t *)&bitstring[4];
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8(color_r[pixel], color_g[pixel], color_b[pixel], color_a[pixel]);
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC2 format. */
bool detexDecompressBlockBC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[8];
#else
uint32_t colors = ((uint32_t)bitstring[8] << 24) |
((uint32_t)bitstring[9] << 16) |
((uint32_t)bitstring[10] << 8) | bitstring[11];
#endif
if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) &&
(flags & DETEX_DECOMPRESS_FLAG_ENCODE))
// GeForce 6 and 7 series produce wrong result in this case.
return false;
int color_r[4], color_g[4], color_b[4];
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
uint32_t pixels = *(uint32_t *)&bitstring[12];
uint64_t alpha_pixels = *(uint64_t *)&bitstring[0];
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
int alpha = ((alpha_pixels >> (i * 4)) & 0xF) * 255 / 15;
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8(color_r[pixel], color_g[pixel], color_b[pixel], alpha);
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the BC3 format. */
bool detexDecompressBlockBC3(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int alpha0 = bitstring[0];
int alpha1 = bitstring[1];
if (alpha0 > alpha1 && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return false;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__)
uint32_t colors = *(uint32_t *)&bitstring[8];
#else
uint32_t colors = ((uint32_t)bitstring[8] << 24) |
((uint32_t)bitstring[9] << 16) |
((uint32_t)bitstring[10] << 8) | bitstring[11];
#endif
if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) &&
(flags & DETEX_DECOMPRESS_FLAG_ENCODE))
// GeForce 6 and 7 series produce wrong result in this case.
return false;
int color_r[4], color_g[4], color_b[4];
// color_x[] has a value between 0 and 248 with the lower three bits zero.
color_b[0] = (colors & 0x0000001F) << 3;
color_g[0] = (colors & 0x000007E0) >> (5 - 2);
color_r[0] = (colors & 0x0000F800) >> (11 - 3);
color_b[1] = (colors & 0x001F0000) >> (16 - 3);
color_g[1] = (colors & 0x07E00000) >> (21 - 2);
color_r[1] = (colors & 0xF8000000) >> (27 - 3);
color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]);
color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]);
color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]);
color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]);
color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]);
color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]);
uint32_t pixels = *(uint32_t *)&bitstring[12];
uint64_t alpha_bits = (uint32_t)bitstring[2] | ((uint32_t)bitstring[3] << 8) | ((uint64_t)*(uint32_t *)&bitstring[4] << 16);
for (int i = 0; i < 16; i++)
{
int pixel = (pixels >> (i * 2)) & 0x3;
int code = (alpha_bits >> (i * 3)) & 0x7;
int alpha;
if (alpha0 > alpha1)
{
switch (code)
{
case 0 : alpha = alpha0; break;
case 1 : alpha = alpha1; break;
case 2 : alpha = detexDivide0To1791By7(6 * alpha0 + 1 * alpha1); break;
case 3 : alpha = detexDivide0To1791By7(5 * alpha0 + 2 * alpha1); break;
case 4 : alpha = detexDivide0To1791By7(4 * alpha0 + 3 * alpha1); break;
case 5 : alpha = detexDivide0To1791By7(3 * alpha0 + 4 * alpha1); break;
case 6 : alpha = detexDivide0To1791By7(2 * alpha0 + 5 * alpha1); break;
case 7 : alpha = detexDivide0To1791By7(1 * alpha0 + 6 * alpha1); break;
}
}
else
{
switch (code)
{
case 0 : alpha = alpha0; break;
case 1 : alpha = alpha1; break;
case 2 : alpha = detexDivide0To1279By5(4 * alpha0 + 1 * alpha1); break;
case 3 : alpha = detexDivide0To1279By5(3 * alpha0 + 2 * alpha1); break;
case 4 : alpha = detexDivide0To1279By5(2 * alpha0 + 3 * alpha1); break;
case 5 : alpha = detexDivide0To1279By5(1 * alpha0 + 4 * alpha1); break;
case 6 : alpha = 0; break;
case 7 : alpha = 0xFF; break;
}
}
*(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8(color_r[pixel], color_g[pixel], color_b[pixel], alpha);
}
return true;
}
/**
For each pixel, decode an 8-bit integer and store as follows:
If shift and offset are zero, store each value in consecutive 8 bit values in pixel_buffer.
If shift is one, store each value in consecutive 16-bit words in pixel_buffer; if offset
is zero, store it in the first 8 bits, if offset is one store it in the last 8 bits of each
16-bit word.
*/
static DETEX_INLINE_ONLY void DecodeBlockRGTC(const uint8_t * DETEX_RESTRICT bitstring, int shift, int offset, uint8_t * DETEX_RESTRICT pixel_buffer)
{
// LSBFirst byte order only.
uint64_t bits = (*(uint64_t *)&bitstring[0]) >> 16;
int lum0 = bitstring[0];
int lum1 = bitstring[1];
for (int i = 0; i < 16; i++)
{
int control_code = bits & 0x7;
uint8_t output;
if (lum0 > lum1)
{
switch (control_code)
{
case 0 : output = lum0; break;
case 1 : output = lum1; break;
case 2 : output = detexDivide0To1791By7(6 * lum0 + lum1); break;
case 3 : output = detexDivide0To1791By7(5 * lum0 + 2 * lum1); break;
case 4 : output = detexDivide0To1791By7(4 * lum0 + 3 * lum1); break;
case 5 : output = detexDivide0To1791By7(3 * lum0 + 4 * lum1); break;
case 6 : output = detexDivide0To1791By7(2 * lum0 + 5 * lum1); break;
case 7 : output = detexDivide0To1791By7(lum0 + 6 * lum1); break;
}
}
else
{
switch (control_code)
{
case 0 : output = lum0; break;
case 1 : output = lum1; break;
case 2 : output = detexDivide0To1279By5(4 * lum0 + lum1); break;
case 3 : output = detexDivide0To1279By5(3 * lum0 + 2 * lum1); break;
case 4 : output = detexDivide0To1279By5(2 * lum0 + 3 * lum1); break;
case 5 : output = detexDivide0To1279By5(lum0 + 4 * lum1); break;
case 6 : output = 0; break;
case 7 : output = 0xFF; break;
}
}
pixel_buffer[(i << shift) + offset] = output;
bits >>= 3;
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the unsigned RGTC1 (BC4) format. */
bool detexDecompressBlockRGTC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
DecodeBlockRGTC(bitstring, 0, 0, pixel_buffer);
return true;
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the unsigned RGTC2 (BC5) format. */
bool detexDecompressBlockRGTC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
DecodeBlockRGTC(bitstring, 1, 0, pixel_buffer);
DecodeBlockRGTC(&bitstring[8], 1, 1, pixel_buffer);
return true;
}
/**
For each pixel, decode an 16-bit integer and store as follows:
If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer.
If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset
is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each
32-bit word. Returns true if the compressed block is valid.
*/
static DETEX_INLINE_ONLY bool DecodeBlockSignedRGTC(const uint8_t * DETEX_RESTRICT bitstring, int shift, int offset, uint8_t * DETEX_RESTRICT pixel_buffer)
{
// LSBFirst byte order only.
uint64_t bits = (*(uint64_t *)&bitstring[0]) >> 16;
int lum0 = (int8_t)bitstring[0];
int lum1 = (int8_t)bitstring[1];
if (lum0 == - 127 && lum1 == - 128)
// Not allowed.
return false;
if (lum0 == - 128)
lum0 = - 127;
if (lum1 == - 128)
lum1 = - 127;
// Note: values are mapped to a red value of -127 to 127.
uint16_t *pixel16_buffer = (uint16_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int control_code = bits & 0x7;
int32_t result;
if (lum0 > lum1)
{
switch (control_code)
{
case 0 : result = lum0; break;
case 1 : result = lum1; break;
case 2 : result = detexDivideMinus895To895By7(6 * lum0 + lum1); break;
case 3 : result = detexDivideMinus895To895By7(5 * lum0 + 2 * lum1); break;
case 4 : result = detexDivideMinus895To895By7(4 * lum0 + 3 * lum1); break;
case 5 : result = detexDivideMinus895To895By7(3 * lum0 + 4 * lum1); break;
case 6 : result = detexDivideMinus895To895By7(2 * lum0 + 5 * lum1); break;
case 7 : result = detexDivideMinus895To895By7(lum0 + 6 * lum1); break;
}
}
else
{
switch (control_code)
{
case 0 : result = lum0; break;
case 1 : result = lum1; break;
case 2 : result = detexDivideMinus639To639By5(4 * lum0 + lum1); break;
case 3 : result = detexDivideMinus639To639By5(3 * lum0 + 2 * lum1); break;
case 4 : result = detexDivideMinus639To639By5(2 * lum0 + 3 * lum1); break;
case 5 : result = detexDivideMinus639To639By5(lum0 + 4 * lum1); break;
case 6 : result = - 127; break;
case 7 : result = 127; break;
}
}
// Map from [-127, 127] to [-32768, 32767].
pixel16_buffer[(i << shift) + offset] = (uint16_t)(int16_t)
((result + 127) * 65535 / 254 - 32768);
bits >>= 3;
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the signed RGTC1 (signed BC4) format. */
bool detexDecompressBlockSIGNED_RGTC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
return DecodeBlockSignedRGTC(bitstring, 0, 0, pixel_buffer);
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the signed RGTC2 (signed BC5) format. */
bool detexDecompressBlockSIGNED_RGTC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
bool r = DecodeBlockSignedRGTC(bitstring, 1, 0, pixel_buffer);
if (!r)
return false;
return DecodeBlockSignedRGTC(&bitstring[8], 1, 1, pixel_buffer);
}
////////////////////////////////////////////////////////////////////////////////////////////////
static int ExtractMode(FDetexBlock128 *block)
{
uint32_t mode = detexBlock128ExtractBits(block, 2);
if (mode < 2)
return mode;
return map_mode_table[mode | (detexBlock128ExtractBits(block, 3) << 2)];
}
static int GetPartitionIndex(int nu_subsets, int partition_set_id, int i)
{
if (nu_subsets == 1)
return 0;
// nu_subset == 2
return detex_bptc_table_P2[partition_set_id * 16 + i];
}
static DETEX_INLINE_ONLY int GetAnchorIndex(int partition_set_id, int partition, int nu_subsets)
{
if (partition == 0)
return 0;
// nu_subsets = 2, partition = 1.
return detex_bptc_table_anchor_index_second_subset[partition_set_id];
}
static uint32_t Unquantize(uint16_t x, int mode)
{
int32_t unq;
if (mode == 13)
unq = x;
else if (x == 0)
unq = 0;
else if (x == (((int32_t)1 << bptc_float_EPB[mode]) - 1))
unq = 0xFFFF;
else
unq = (((int32_t)x << 15) + 0x4000) >> (bptc_float_EPB[mode] - 1);
return unq;
}
static int32_t UnquantizeSigned(int16_t x, int mode)
{
int s = 0;
int32_t unq;
if (bptc_float_EPB[mode] >= 16)
unq = x;
else
{
if (x < 0) {
s = 1;
x = -x;
}
if (x == 0)
unq = 0;
else
if (x >= (((int32_t)1 << (bptc_float_EPB[mode] - 1)) - 1))
unq = 0x7FFF;
else
unq = (((int32_t)x << 15) + 0x4000) >> (bptc_float_EPB[mode] - 1);
if (s)
unq = -unq;
}
return unq;
}
static int SignExtend(int value, int source_nu_bits, int target_nu_bits)
{
uint32_t sign_bit = value & (1 << (source_nu_bits - 1));
if (!sign_bit)
return value;
uint32_t sign_extend_bits = 0xFFFFFFFF ^ ((1 << source_nu_bits) - 1);
sign_extend_bits &= ((uint64_t)1 << target_nu_bits) - 1;
return value | sign_extend_bits;
}
static int32_t InterpolateFloat(int32_t e0, int32_t e1, int16_t index, uint8_t indexprecision)
{
if (indexprecision == 2)
return (((64 - detex_bptc_table_aWeight2[index]) * e0 + detex_bptc_table_aWeight2[index] * e1 + 32) >> 6);
else if (indexprecision == 3)
return (((64 - detex_bptc_table_aWeight3[index]) * e0 + detex_bptc_table_aWeight3[index] * e1 + 32) >> 6);
else // indexprecision == 4
return (((64 - detex_bptc_table_aWeight4[index]) * e0 + detex_bptc_table_aWeight4[index] * e1 + 32) >> 6);
}
static bool DecompressBlockBPTCFloatShared(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, bool signed_flag, const uint8_t * DETEX_RESTRICT pixel_buffer)
{
FDetexBlock128 block;
block.data0 = *(uint64_t *)&bitstring[0];
block.data1 = *(uint64_t *)&bitstring[8];
block.index = 0;
uint32_t mode = ExtractMode(&block);
if (mode == - 1)
return false;
// Allow compression tied to specific modes (according to mode_mask).
if (!(mode_mask & ((int)1 << mode)))
return false;
int32_t r[4], g[4], b[4];
int partition_set_id = 0;
int delta_bits_r, delta_bits_g, delta_bits_b;
uint64_t data0 = block.data0;
uint64_t data1 = block.data1;
switch (mode)
{
case 0 :
// m[1:0],g2[4],b2[4],b3[4],r0[9:0],g0[9:0],b0[9:0],r1[4:0],g3[4],g2[3:0],
// g1[4:0],b3[0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[4:0],b3[2],r3[4:0],b3[3]
g[2] = detexGetBits64(data0, 2, 2) << 4;
b[2] = detexGetBits64(data0, 3, 3) << 4;
b[3] = detexGetBits64(data0, 4, 4) << 4;
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 39);
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = delta_bits_b = 5;
break;
case 1 :
// m[1:0],g2[5],g3[4],g3[5],r0[6:0],b3[0],b3[1],b2[4],g0[6:0],b2[5],b3[2],
// g2[4],b0[6:0],b3[3],b3[5],b3[4],r1[5:0],g2[3:0],g1[5:0],g3[3:0],b1[5:0],
// b2[3:0],r2[5:0],r3[5:0]
g[2] = detexGetBits64(data0, 2, 2) << 5;
g[3] = detexGetBits64(data0, 3, 3) << 4;
g[3] |= detexGetBits64(data0, 4, 4) << 5;
r[0] = detexGetBits64(data0, 5, 11);
b[3] = detexGetBits64(data0, 12, 12);
b[3] |= detexGetBits64(data0, 13, 13) << 1;
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 21);
b[2] |= detexGetBits64(data0, 22, 22) << 5;
b[3] |= detexGetBits64(data0, 23, 23) << 2;
g[2] |= detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 31);
b[3] |= detexGetBits64(data0, 32, 32) << 3;
b[3] |= detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 40);
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 60);
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 6);
r[3] = detexGetBits64(data1, 7, 12);
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = delta_bits_b = 6;
break;
case 2 :
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[4:0],r0[10],g2[3:0],g1[3:0],g0[10],
// b3[0],g3[3:0],b1[3:0],b0[10],b3[1],b2[3:0],r2[4:0],b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 39);
r[0] |= detexGetBits64(data0, 40, 40) << 10;
g[2] = detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 48);
g[0] |= detexGetBits64(data0, 49, 49) << 10;
b[3] = detexGetBits64(data0, 50, 50);
g[3] = detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 58);
b[0] |= detexGetBits64(data0, 59, 59) << 10;
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] = detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = 5;
delta_bits_g = delta_bits_b = 4;
break;
case 3 : // Original mode 6.
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[3:0],r0[10],g3[4],g2[3:0],g1[4:0],
// g0[10],g3[3:0],b1[3:0],b0[10],b3[1],b2[3:0],r2[3:0],b3[0],b3[2],r3[3:0],
// g2[4],b3[3]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 38);
r[0] |= detexGetBits64(data0, 39, 39) << 10;
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] = detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
g[0] |= detexGetBits64(data0, 50, 50) << 10;
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 58);
b[0] |= detexGetBits64(data0, 59, 59) << 10;
b[3] = detexGetBits64(data0, 60, 60) << 1;
b[2] = detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 4);
b[3] |= detexGetBits64(data1, 5, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 10);
g[2] |= detexGetBits64(data1, 11, 11) << 4;
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_b = 4;
delta_bits_g = 5;
break;
case 4 : // Original mode 10.
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[3:0],r0[10],b2[4],g2[3:0],g1[3:0],
// g0[10],b3[0],g3[3:0],b1[4:0],b0[10],b2[3:0],r2[3:0],b3[1],b3[2],r3[3:0],
// b3[4],b3[3]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 38);
r[0] |= detexGetBits64(data0, 39, 39) << 10;
b[2] = detexGetBits64(data0, 40, 40) << 4;
g[2] = detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 48);
g[0] |= detexGetBits64(data0, 49, 49) << 10;
b[3] = detexGetBits64(data0, 50, 50);
g[3] = detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[0] |= detexGetBits64(data0, 60, 60) << 10;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 4);
b[3] |= detexGetBits64(data1, 5, 5) << 1;
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 10);
b[3] |= detexGetBits64(data1, 11, 11) << 4;
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = 4;
delta_bits_b = 5;
break;
case 5 : // Original mode 14
// m[4:0],r0[8:0],b2[4],g0[8:0],g2[4],b0[8:0],b3[4],r1[4:0],g3[4],g2[3:0],
// g1[4:0],b3[0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[4:0],b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 13);
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 23);
g[2] = detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 33);
b[3] = detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 39);
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = delta_bits_b = 5;
break;
case 6 : // Original mode 18
// m[4:0],r0[7:0],g3[4],b2[4],g0[7:0],b3[2],g2[4],b0[7:0],b3[3],b3[4],
// r1[5:0],g2[3:0],g1[4:0],b3[0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[5:0],r3[5:0]
r[0] = detexGetBits64(data0, 5, 12);
g[3] = detexGetBits64(data0, 13, 13) << 4;
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 22);
b[3] = detexGetBits64(data0, 23, 23) << 2;
g[2] = detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 32);
b[3] |= detexGetBits64(data0, 33, 33) << 3;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 40);
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 6);
r[3] = detexGetBits64(data1, 7, 12);
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = 6;
delta_bits_g = delta_bits_b = 5;
break;
case 7 : // Original mode 22
// m[4:0],r0[7:0],b3[0],b2[4],g0[7:0],g2[5],g2[4],b0[7:0],g3[5],b3[4],
// r1[4:0],g3[4],g2[3:0],g1[5:0],g3[3:0],b1[4:0],b3[1],b2[3:0],r2[4:0],
// b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 12);
b[3] = detexGetBits64(data0, 13, 13);
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 22);
g[2] = detexGetBits64(data0, 23, 23) << 5;
g[2] |= detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 32);
g[3] = detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 39);
g[3] |= detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 59);
b[3] |= detexGetBits64(data0, 60, 60) << 1;
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_b = 5;
delta_bits_g = 6;
break;
case 8 : // Original mode 26
// m[4:0],r0[7:0],b3[1],b2[4],g0[7:0],b2[5],g2[4],b0[7:0],b3[5],b3[4],
// r1[4:0],g3[4],g2[3:0],g1[4:0],b3[0],g3[3:0],b1[5:0],b2[3:0],r2[4:0],
// b3[2],r3[4:0],b3[3]
r[0] = detexGetBits64(data0, 5, 12);
b[3] = detexGetBits64(data0, 13, 13) << 1;
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 22);
b[2] |= detexGetBits64(data0, 23, 23) << 5;
g[2] = detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 32);
b[3] |= detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 39);
g[3] = detexGetBits64(data0, 40, 40) << 4;
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 49);
b[3] |= detexGetBits64(data0, 50, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 60);
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 5);
b[3] |= detexGetBits64(data1, 6, 6) << 2;
r[3] = detexGetBits64(data1, 7, 11);
b[3] |= detexGetBits64(data1, 12, 12) << 3;
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
delta_bits_r = delta_bits_g = 5;
delta_bits_b = 6;
break;
case 9 : // Original mode 30
// m[4:0],r0[5:0],g3[4],b3[0],b3[1],b2[4],g0[5:0],g2[5],b2[5],b3[2],
// g2[4],b0[5:0],g3[5],b3[3],b3[5],b3[4],r1[5:0],g2[3:0],g1[5:0],g3[3:0],
// b1[5:0],b2[3:0],r2[5:0],r3[5:0]
r[0] = detexGetBits64(data0, 5, 10);
g[3] = detexGetBits64(data0, 11, 11) << 4;
b[3] = detexGetBits64(data0, 12, 13);
b[2] = detexGetBits64(data0, 14, 14) << 4;
g[0] = detexGetBits64(data0, 15, 20);
g[2] = detexGetBits64(data0, 21, 21) << 5;
b[2] |= detexGetBits64(data0, 22, 22) << 5;
b[3] |= detexGetBits64(data0, 23, 23) << 2;
g[2] |= detexGetBits64(data0, 24, 24) << 4;
b[0] = detexGetBits64(data0, 25, 30);
g[3] |= detexGetBits64(data0, 31, 31) << 5;
b[3] |= detexGetBits64(data0, 32, 32) << 3;
b[3] |= detexGetBits64(data0, 33, 33) << 5;
b[3] |= detexGetBits64(data0, 34, 34) << 4;
r[1] = detexGetBits64(data0, 35, 40);
g[2] |= detexGetBits64(data0, 41, 44);
g[1] = detexGetBits64(data0, 45, 50);
g[3] |= detexGetBits64(data0, 51, 54);
b[1] = detexGetBits64(data0, 55, 60);
b[2] |= detexGetBits64(data0, 61, 63);
b[2] |= detexGetBits64(data1, 0, 0) << 3;
r[2] = detexGetBits64(data1, 1, 6);
r[3] = detexGetBits64(data1, 7, 12);
partition_set_id = detexGetBits64(data1, 13, 17);
block.index = 64 + 18;
// delta_bits_r = delta_bits_g = delta_bits_b = 6;
break;
case 10 : // Original mode 3
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[9:0],g1[9:0],b1[9:0]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 44);
g[1] = detexGetBits64(data0, 45, 54);
b[1] = detexGetBits64(data0, 55, 63);
b[1] |= detexGetBits64(data1, 0, 0) << 9;
partition_set_id = 0;
block.index = 65;
// delta_bits_r = delta_bits_g = delta_bits_b = 10;
break;
case 11 : // Original mode 7
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[8:0],r0[10],g1[8:0],g0[10],b1[8:0],b0[10]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 43);
r[0] |= detexGetBits64(data0, 44, 44) << 10;
g[1] = detexGetBits64(data0, 45, 53);
g[0] |= detexGetBits64(data0, 54, 54) << 10;
b[1] = detexGetBits64(data0, 55, 63);
b[0] |= detexGetBits64(data1, 0, 0) << 10;
partition_set_id = 0;
block.index = 65;
delta_bits_r = delta_bits_g = delta_bits_b = 9;
break;
case 12 : // Original mode 11
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[7:0],r0[10:11],g1[7:0],g0[10:11],
// b1[7:0],b0[10:11]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 42);
r[0] |= detexGetBits64Reversed(data0, 44, 43) << 10; // Reversed.
g[1] = detexGetBits64(data0, 45, 52);
g[0] |= detexGetBits64Reversed(data0, 54, 53) << 10; // Reversed.
b[1] = detexGetBits64(data0, 55, 62);
b[0] |= detexGetBits64(data0, 63, 63) << 11; // MSB
b[0] |= detexGetBits64(data1, 0, 0) << 10; // LSB
partition_set_id = 0;
block.index = 65;
delta_bits_r = delta_bits_g = delta_bits_b = 8;
break;
case 13 : // Original mode 15
// m[4:0],r0[9:0],g0[9:0],b0[9:0],r1[3:0],r0[10:15],g1[3:0],g0[10:15],
// b1[3:0],b0[10:15]
r[0] = detexGetBits64(data0, 5, 14);
g[0] = detexGetBits64(data0, 15, 24);
b[0] = detexGetBits64(data0, 25, 34);
r[1] = detexGetBits64(data0, 35, 38);
r[0] |= detexGetBits64Reversed(data0, 44, 39) << 10; // Reversed.
g[1] = detexGetBits64(data0, 45, 48);
g[0] |= detexGetBits64Reversed(data0, 54, 49) << 10; // Reversed.
b[1] = detexGetBits64(data0, 55, 58);
b[0] |= detexGetBits64Reversed(data0, 63, 59) << 11; // Reversed.
b[0] |= detexGetBits64(data1, 0, 0) << 10;
partition_set_id = 0;
block.index = 65;
delta_bits_r = delta_bits_g = delta_bits_b = 4;
break;
}
int nu_subsets;
if (mode >= 10)
nu_subsets = 1;
else
nu_subsets = 2;
if (signed_flag)
{
r[0] = SignExtend(r[0], bptc_float_EPB[mode], 32);
g[0] = SignExtend(g[0], bptc_float_EPB[mode], 32);
b[0] = SignExtend(b[0], bptc_float_EPB[mode], 32);
}
if (mode != 9 && mode != 10)
{
// Transformed endpoints.
for (int i = 1; i < nu_subsets * 2; i++)
{
r[i] = SignExtend(r[i], delta_bits_r, 32);
r[i] = (r[0] + r[i]) & (((uint32_t)1 << bptc_float_EPB[mode]) - 1);
g[i] = SignExtend(g[i], delta_bits_g, 32);
g[i] = (g[0] + g[i]) & (((uint32_t)1 << bptc_float_EPB[mode]) - 1);
b[i] = SignExtend(b[i], delta_bits_b, 32);
b[i] = (b[0] + b[i]) & (((uint32_t)1 << bptc_float_EPB[mode]) - 1);
if (signed_flag)
{
r[i] = SignExtend(r[i], bptc_float_EPB[mode], 32);
g[i] = SignExtend(g[i], bptc_float_EPB[mode], 32);
b[i] = SignExtend(b[i], bptc_float_EPB[mode], 32);
}
}
}
else // Mode 9 or 10, no transformed endpoints.
{
if (signed_flag)
{
for (int i = 1; i < nu_subsets * 2; i++)
{
r[i] = SignExtend(r[i], bptc_float_EPB[mode], 32);
g[i] = SignExtend(g[i], bptc_float_EPB[mode], 32);
b[i] = SignExtend(b[i], bptc_float_EPB[mode], 32);
}
}
}
// Unquantize endpoints.
if (signed_flag)
{
for (int i = 0; i < 2 * nu_subsets; i++)
{
r[i] = UnquantizeSigned(r[i], mode);
g[i] = UnquantizeSigned(g[i], mode);
b[i] = UnquantizeSigned(b[i], mode);
}
}
else
{
for (int i = 0; i < 2 * nu_subsets; i++)
{
r[i] = Unquantize(r[i], mode);
g[i] = Unquantize(g[i], mode);
b[i] = Unquantize(b[i], mode);
}
}
uint8_t subset_index[16];
for (int i = 0; i < 16; i++)
{
// subset_index[i] is a number from 0 to 1, depending on the number of subsets.
subset_index[i] = GetPartitionIndex(nu_subsets, partition_set_id, i);
}
uint8_t anchor_index[4]; // Only need max. 2 elements
for (int i = 0; i < nu_subsets; i++)
{
anchor_index[i] = GetAnchorIndex(partition_set_id, i, nu_subsets);
}
uint8_t color_index[16];
// Extract index bits.
int color_index_bit_count = 3;
if ((bitstring[0] & 3) == 3) // This defines original modes 3, 7, 11, 15
color_index_bit_count = 4;
// Because the index bits are all in the second 64-bit word, there is no need to use
// block_extract_bits().
data1 >>= (block.index - 64);
uint8_t mask1 = (1 << color_index_bit_count) - 1;
uint8_t mask2 = (1 << (color_index_bit_count - 1)) - 1;
for (int i = 0; i < 16; i++)
{
if (i == anchor_index[subset_index[i]])
{
// Highest bit is zero.
// color_index[i] = block_extract_bits(&block, color_index_bit_count - 1);
color_index[i] = data1 & mask2;
data1 >>= color_index_bit_count - 1;
}
else
{
// color_index[i] = block_extract_bits(&block, color_index_bit_count);
color_index[i] = data1 & mask1;
data1 >>= color_index_bit_count;
}
}
for (int i = 0; i < 16; i++)
{
int32_t endpoint_start_r, endpoint_start_g, endpoint_start_b;
int32_t endpoint_end_r, endpoint_end_g, endpoint_end_b;
endpoint_start_r = r[2 * subset_index[i]];
endpoint_end_r = r[2 * subset_index[i] + 1];
endpoint_start_g = g[2 * subset_index[i]];
endpoint_end_g = g[2 * subset_index[i] + 1];
endpoint_start_b = b[2 * subset_index[i]];
endpoint_end_b = b[2 * subset_index[i] + 1];
uint64_t output;
if (signed_flag)
{
int32_t r16 = InterpolateFloat(endpoint_start_r, endpoint_end_r, color_index[i], color_index_bit_count);
if (r16 < 0)
r16 = - (((- r16) * 31) >> 5);
else
r16 = (r16 * 31) >> 5;
int s = 0;
if (r16 < 0)
{
s = 0x8000;
r16 = - r16;
}
r16 |= s;
int32_t g16 = InterpolateFloat(endpoint_start_g, endpoint_end_g, color_index[i], color_index_bit_count);
if (g16 < 0)
g16 = - (((- g16) * 31) >> 5);
else
g16 = (g16 * 31) >> 5;
s = 0;
if (g16 < 0)
{
s = 0x8000;
g16 = - g16;
}
g16 |= s;
int32_t b16 = InterpolateFloat(endpoint_start_b, endpoint_end_b, color_index[i], color_index_bit_count);
if (b16 < 0)
b16 = - (((- b16) * 31) >> 5);
else
b16 = (b16 * 31) >> 5;
s = 0;
if (b16 < 0)
{
s = 0x8000;
b16 = - b16;
}
b16 |= s;
output = detexPack64RGB16(r16, g16, b16);
}
else
{
output = detexPack64R16(InterpolateFloat(endpoint_start_r, endpoint_end_r, color_index[i], color_index_bit_count) * 31 / 64);
output |= detexPack64G16(InterpolateFloat(endpoint_start_g, endpoint_end_g, color_index[i], color_index_bit_count) * 31 / 64);
output |= detexPack64B16(InterpolateFloat(endpoint_start_b, endpoint_end_b, color_index[i], color_index_bit_count) * 31 / 64);
}
*(uint64_t *)&pixel_buffer[i * 8] = output;
}
return true;
}
static uint8_t Interpolate(uint8_t e0, uint8_t e1, uint8_t index, uint8_t indexprecision)
{
if (indexprecision == 2)
return (uint8_t)(((64 - detex_bptc_table_aWeight2[index]) * (uint16_t)e0 + detex_bptc_table_aWeight2[index] * (uint16_t)e1 + 32) >> 6);
else
if (indexprecision == 3)
return (uint8_t)(((64 - detex_bptc_table_aWeight3[index]) * (uint16_t)e0 + detex_bptc_table_aWeight3[index] * (uint16_t)e1 + 32) >> 6);
else // indexprecision == 4
return (uint8_t)(((64 - detex_bptc_table_aWeight4[index]) * (uint16_t)e0 + detex_bptc_table_aWeight4[index] * (uint16_t)e1 + 32) >> 6);
}
static const uint8_t IB[8] = { 3, 3, 2, 2, 2, 2, 4, 2 };
static const uint8_t IB2[8] = { 0, 0, 0, 0, 3, 2, 0, 0 };
static const uint8_t mode_has_partition_bits[8] = { 1, 1, 1, 1, 0, 0, 0, 1 };
static const uint8_t bptc_color_index_bitcount[8] = { 3, 3, 2, 2, 2, 2, 4, 2 };
static DETEX_INLINE_ONLY int GetColorIndexBitcount(int mode, int index_selection_bit)
{
// If the index selection bit is set for mode 4, return 3, otherwise 2.
return bptc_color_index_bitcount[mode] + index_selection_bit;
}
static uint8_t bptc_alpha_index_bitcount[8] = { 3, 3, 2, 2, 3, 2, 4, 2 };
static DETEX_INLINE_ONLY int GetAlphaIndexBitcount(int mode, int index_selection_bit)
{
// If the index selection bit is set for mode 4, return 2, otherwise 3.
return bptc_alpha_index_bitcount[mode] - index_selection_bit;
}
static const uint8_t bptc_NS[8] = { 3, 2, 3, 2, 1, 1, 1, 2 };
static DETEX_INLINE_ONLY int GetNumberOfSubsets(int mode)
{
return bptc_NS[mode];
}
static const uint8_t PB[8] = { 4, 6, 6, 6, 0, 0, 0, 6 };
static DETEX_INLINE_ONLY int GetNumberOfPartitionBits(int mode)
{
return PB[mode];
}
static const uint8_t RB[8] = { 0, 0, 0, 0, 2, 2, 0, 0 };
static DETEX_INLINE_ONLY int GetNumberOfRotationBits(int mode)
{
return RB[mode];
}
static DETEX_INLINE_ONLY int ExtractPartitionSetID(FDetexBlock128 *block, int mode)
{
return detexBlock128ExtractBits(block, GetNumberOfPartitionBits(mode));
}
static DETEX_INLINE_ONLY int ExtractRotationBits(FDetexBlock128 *block, int mode)
{
return detexBlock128ExtractBits(block, GetNumberOfRotationBits(mode));
}
static const int8_t components_in_qword0_table[8] = { 2, -1, 1, 1, 3, 3, 3, 2 };
static const uint8_t color_precision_table[8] = { 4, 6, 5, 7, 5, 7, 7, 5 };
// Note: precision includes P-bits!
static const uint8_t color_precision_plus_pbit_table[8] = { 5, 7, 5, 8, 5, 7, 8, 6 };
static DETEX_INLINE_ONLY uint8_t GetColorComponentPrecision(int mode)
{
return color_precision_table[mode];
}
static DETEX_INLINE_ONLY uint8_t GetColorComponentPrecisionPlusPbit(int mode)
{
return color_precision_plus_pbit_table[mode];
}
static const int8_t alpha_precision_table[8] = { 0, 0, 0, 0, 6, 8, 7, 5 };
// Note: precision include P-bits!
static const uint8_t alpha_precision_plus_pbit_table[8] = { 0, 0, 0, 0, 6, 8, 8, 6 };
static DETEX_INLINE_ONLY uint8_t GetAlphaComponentPrecision(int mode)
{
return alpha_precision_table[mode];
}
static DETEX_INLINE_ONLY uint8_t GetAlphaComponentPrecisionPlusPbit(int mode)
{
return alpha_precision_plus_pbit_table[mode];
}
/* Extract endpoint colors. */
static void ExtractEndpoints(int mode, int nu_subsets, FDetexBlock128 * DETEX_RESTRICT block, uint8_t * DETEX_RESTRICT endpoint_array)
{
// Optimized version avoiding the use of block_extract_bits().
int components_in_qword0 = components_in_qword0_table[mode];
uint64_t data = block->data0 >> block->index;
uint8_t precision = GetColorComponentPrecision(mode);
uint8_t mask = (1 << precision) - 1;
int total_bits_per_component = nu_subsets * 2 * precision;
for (int i = 0; i < components_in_qword0; i++) // For each color component.
{
for (int j = 0; j < nu_subsets; j++) // For each subset.
{
for (int k = 0; k < 2; k++)
{ // For each endpoint.
endpoint_array[j * 8 + k * 4 + i] = data & mask;
data >>= precision;
}
}
}
block->index += components_in_qword0 * total_bits_per_component;
if (components_in_qword0 < 3)
{
// Handle the color component that crosses the boundary between data0 and data1
data = block->data0 >> block->index;
data |= block->data1 << (64 - block->index);
int i = components_in_qword0;
for (int j = 0; j < nu_subsets; j++) // For each subset.
{
for (int k = 0; k < 2; k++)
{ // For each endpoint.
endpoint_array[j * 8 + k * 4 + i] = data & mask;
data >>= precision;
}
}
block->index += total_bits_per_component;
}
if (components_in_qword0 < 2)
{
// Handle the color component that is wholly in data1.
data = block->data1 >> (block->index - 64);
int i = 2;
for (int j = 0; j < nu_subsets; j++) // For each subset.
{
for (int k = 0; k < 2; k++)
{ // For each endpoint.
endpoint_array[j * 8 + k * 4 + i] = data & mask;
data >>= precision;
}
}
block->index += total_bits_per_component;
}
// Alpha component.
if (GetAlphaComponentPrecision(mode) > 0)
{
// For mode 7, the alpha data is wholly in data1.
// For modes 4 and 6, the alpha data is wholly in data0.
// For mode 5, the alpha data is in data0 and data1.
if (mode == 7)
data = block->data1 >> (block->index - 64);
else if (mode == 5)
data = (block->data0 >> block->index) | ((block->data1 & 0x3) << 14);
else
data = block->data0 >> block->index;
uint8_t alpha_precision = GetAlphaComponentPrecision(mode);
uint8_t amask = (1 << alpha_precision) - 1;
for (int j = 0; j < nu_subsets; j++)
{
for (int k = 0; k < 2; k++)
{ // For each endpoint.
endpoint_array[j * 8 + k * 4 + 3] = data & amask;
data >>= alpha_precision;
}
}
block->index += nu_subsets * 2 * alpha_precision;
}
}
static const uint8_t mode_has_p_bits[8] = { 1, 1, 0, 1, 0, 0, 1, 1 };
static void FullyDecodeEndpoints(uint8_t * DETEX_RESTRICT endpoint_array, int nu_subsets, int mode, FDetexBlock128 * DETEX_RESTRICT block)
{
if (mode_has_p_bits[mode])
{
// Mode 1 (shared P-bits) handled elsewhere.
// Extract end-point P-bits. Take advantage of the fact that they don't cross the
// 64-bit word boundary in any mode.
uint32_t bits;
if (block->index < 64)
bits = block->data0 >> block->index;
else
bits = block->data1 >> (block->index - 64);
for (int i = 0; i < nu_subsets * 2; i++)
{
endpoint_array[i * 4 + 0] <<= 1;
endpoint_array[i * 4 + 1] <<= 1;
endpoint_array[i * 4 + 2] <<= 1;
endpoint_array[i * 4 + 3] <<= 1;
endpoint_array[i * 4 + 0] |= (bits & 1);
endpoint_array[i * 4 + 1] |= (bits & 1);
endpoint_array[i * 4 + 2] |= (bits & 1);
endpoint_array[i * 4 + 3] |= (bits & 1);
bits >>= 1;
}
block->index += nu_subsets * 2;
}
int color_prec = GetColorComponentPrecisionPlusPbit(mode);
int alpha_prec = GetAlphaComponentPrecisionPlusPbit(mode);
for (int i = 0; i < nu_subsets * 2; i++)
{
// Color_component_precision & alpha_component_precision includes pbit
// left shift endpoint components so that their MSB lies in bit 7
endpoint_array[i * 4 + 0] <<= (8 - color_prec);
endpoint_array[i * 4 + 1] <<= (8 - color_prec);
endpoint_array[i * 4 + 2] <<= (8 - color_prec);
endpoint_array[i * 4 + 3] <<= (8 - alpha_prec);
// Replicate each component's MSB into the LSBs revealed by the left-shift operation above.
endpoint_array[i * 4 + 0] |= (endpoint_array[i * 4 + 0] >> color_prec);
endpoint_array[i * 4 + 1] |= (endpoint_array[i * 4 + 1] >> color_prec);
endpoint_array[i * 4 + 2] |= (endpoint_array[i * 4 + 2] >> color_prec);
endpoint_array[i * 4 + 3] |= (endpoint_array[i * 4 + 3] >> alpha_prec);
}
if (mode <= 3)
{
for (int i = 0; i < nu_subsets * 2; i++)
endpoint_array[i * 4 + 3] = 0xFF;
}
}
/* Decompress a 128-bit 4x4 pixel texture block compressed using BPTC mode 1. */
static bool DecompressBlockBPTCMode1(FDetexBlock128 * DETEX_RESTRICT block, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t data0 = block->data0;
uint64_t data1 = block->data1;
int partition_set_id = detexGetBits64(data0, 2, 7);
uint8_t endpoint[2 * 2 * 3]; // 2 subsets.
endpoint[0] = detexGetBits64(data0, 8, 13); // red, subset 0, endpoint 0
endpoint[3] = detexGetBits64(data0, 14, 19); // red, subset 0, endpoint 1
endpoint[6] = detexGetBits64(data0, 20, 25); // red, subset 1, endpoint 0
endpoint[9] = detexGetBits64(data0, 26, 31); // red, subset 1, endpoint 1
endpoint[1] = detexGetBits64(data0, 32, 37); // green, subset 0, endpoint 0
endpoint[4] = detexGetBits64(data0, 38, 43); // green, subset 0, endpoint 1
endpoint[7] = detexGetBits64(data0, 44, 49); // green, subset 1, endpoint 0
endpoint[10] = detexGetBits64(data0, 50, 55); // green, subset 1, endpoint 1
endpoint[2] = detexGetBits64(data0, 56, 61); // blue, subset 0, endpoint 0
endpoint[5] = detexGetBits64(data0, 62, 63) // blue, subset 0, endpoint 1
| (detexGetBits64(data1, 0, 3) << 2);
endpoint[8] = detexGetBits64(data1, 4, 9); // blue, subset 1, endpoint 0
endpoint[11] = detexGetBits64(data1, 10, 15); // blue, subset 1, endpoint 1
// Decode endpoints.
for (int i = 0; i < 2 * 2; i++)
{
//component-wise left-shift
endpoint[i * 3 + 0] <<= 2;
endpoint[i * 3 + 1] <<= 2;
endpoint[i * 3 + 2] <<= 2;
}
// P-bit is shared.
uint8_t pbit_zero = detexGetBits64(data1, 16, 16) << 1;
uint8_t pbit_one = detexGetBits64(data1, 17, 17) << 1;
// RGB only pbits for mode 1, one for each subset.
for (int j = 0; j < 3; j++)
{
endpoint[0 * 3 + j] |= pbit_zero;
endpoint[1 * 3 + j] |= pbit_zero;
endpoint[2 * 3 + j] |= pbit_one;
endpoint[3 * 3 + j] |= pbit_one;
}
for (int i = 0; i < 2 * 2; i++)
{
// Replicate each component's MSB into the LSB.
endpoint[i * 3 + 0] |= endpoint[i * 3 + 0] >> 7;
endpoint[i * 3 + 1] |= endpoint[i * 3 + 1] >> 7;
endpoint[i * 3 + 2] |= endpoint[i * 3 + 2] >> 7;
}
uint8_t subset_index[16];
for (int i = 0; i < 16; i++)
// subset_index[i] is a number from 0 to 1.
subset_index[i] = detex_bptc_table_P2[partition_set_id * 16 + i];
uint8_t anchor_index[2];
anchor_index[0] = 0;
anchor_index[1] = detex_bptc_table_anchor_index_second_subset[partition_set_id];
uint8_t color_index[16];
// Extract primary index bits.
data1 >>= 18;
for (int i = 0; i < 16; i++)
{
if (i == anchor_index[subset_index[i]])
{
// Highest bit is zero.
color_index[i] = data1 & 3; // Get two bits.
data1 >>= 2;
}
else
{
color_index[i] = data1 & 7; // Get three bits.
data1 >>= 3;
}
}
uint32_t *pixel32_buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
uint8_t endpoint_start[3];
uint8_t endpoint_end[3];
for (int j = 0; j < 3; j++)
{
endpoint_start[j] = endpoint[2 * subset_index[i] * 3 + j];
endpoint_end[j] = endpoint[(2 * subset_index[i] + 1) * 3 + j];
}
uint32_t output;
output = detexPack32R8(Interpolate(endpoint_start[0], endpoint_end[0], color_index[i], 3));
output |= detexPack32G8(Interpolate(endpoint_start[1], endpoint_end[1], color_index[i], 3));
output |= detexPack32B8(Interpolate(endpoint_start[2], endpoint_end[2], color_index[i], 3));
output |= detexPack32A8(0xFF);
pixel32_buffer[i] = output;
}
return true;
}
/* Decompress a 128-bit 4x4 pixel texture block compressed using the BPTC */
/* (BC7) format. */
bool detexDecompressBlockBPTC(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
FDetexBlock128 block;
block.data0 = *(uint64_t *)&bitstring[0];
block.data1 = *(uint64_t *)&bitstring[8];
block.index = 0;
int mode = ExtractMode(&block);
if (mode == -1)
return 0;
// Allow compression tied to specific modes (according to mode_mask).
if (!(mode_mask & ((int)1 << mode)))
return 0;
if (mode >= 4 && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return 0;
if (mode < 4 && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY))
return 0;
if (mode == 1)
return DecompressBlockBPTCMode1(&block, pixel_buffer);
int nu_subsets = 1;
int partition_set_id = 0;
if (mode_has_partition_bits[mode])
{
nu_subsets = GetNumberOfSubsets(mode);
partition_set_id = ExtractPartitionSetID(&block, mode);
}
int rotation = ExtractRotationBits(&block, mode);
int index_selection_bit = 0;
if (mode == 4)
index_selection_bit = detexBlock128ExtractBits(&block, 1);
int alpha_index_bitcount = GetAlphaIndexBitcount(mode, index_selection_bit);
int color_index_bitcount = GetColorIndexBitcount(mode, index_selection_bit);
uint8_t endpoint_array[3 * 2 * 4]; // Max. 3 subsets.
ExtractEndpoints(mode, nu_subsets, &block, endpoint_array);
FullyDecodeEndpoints(endpoint_array, nu_subsets, mode, &block);
uint8_t subset_index[16];
for (int i = 0; i < 16; i++)
// subset_index[i] is a number from 0 to 2, or 0 to 1, or 0 depending on the number of subsets.
subset_index[i] = GetPartitionIndex(nu_subsets, partition_set_id, i);
uint8_t anchor_index[4]; // Only need max. 3 elements.
for (int i = 0; i < nu_subsets; i++)
anchor_index[i] = GetAnchorIndex(partition_set_id, i, nu_subsets);
uint8_t color_index[16];
uint8_t alpha_index[16];
// Extract primary index bits.
uint64_t data1;
if (block.index >= 64)
{
// Because the index bits are all in the second 64-bit word, there is no need to use
// block_extract_bits().
// This implies the mode is not 4.
data1 = block.data1 >> (block.index - 64);
uint8_t mask1 = (1 << IB[mode]) - 1;
uint8_t mask2 = (1 << (IB[mode] - 1)) - 1;
for (int i = 0; i < 16; i++)
{
if (i == anchor_index[subset_index[i]])
{
// Highest bit is zero.
color_index[i] = data1 & mask2;
data1 >>= IB[mode] - 1;
alpha_index[i] = color_index[i];
}
else
{
color_index[i] = data1 & mask1;
data1 >>= IB[mode];
alpha_index[i] = color_index[i];
}
}
}
else
{ // Implies mode 4.
// Because the bits cross the 64-bit word boundary, we have to be careful.
// Block index is 50 at this point.
uint64_t data = block.data0 >> 50;
data |= block.data1 << 14;
for (int i = 0; i < 16; i++)
{
if (i == anchor_index[subset_index[i]])
{
// Highest bit is zero.
if (index_selection_bit) { // Implies mode == 4.
alpha_index[i] = data & 0x1;
data >>= 1;
}
else
{
color_index[i] = data & 0x1;
data >>= 1;
}
}
else
{
if (index_selection_bit)
{ // Implies mode == 4.
alpha_index[i] = data & 0x3;
data >>= 2;
}
else
{
color_index[i] = data & 0x3;
data >>= 2;
}
}
// Block index is 81 at this point.
data1 = block.data1 >> (81 - 64);
}
}
// Extract secondary index bits.
if (IB2[mode] > 0)
{
uint8_t mask1 = (1 << IB2[mode]) - 1;
uint8_t mask2 = (1 << (IB2[mode] - 1)) - 1;
for (int i = 0; i < 16; i++)
{
if (i == anchor_index[subset_index[i]])
{
// Highest bit is zero.
if (index_selection_bit)
{
color_index[i] = data1 & 0x3;
data1 >>= 2;
}
else
{
// alpha_index[i] = block_extract_bits(&block, IB2[mode] - 1);
alpha_index[i] = data1 & mask2;
data1 >>= IB2[mode] - 1;
}
}
else
{
if (index_selection_bit)
{
color_index[i] = data1 & 0x7;
data1 >>= 3;
}
else
{
// alpha_index[i] = block_extract_bits(&block, IB2[mode]);
alpha_index[i] = data1 & mask1;
data1 >>= IB2[mode];
}
}
}
}
uint32_t *pixel32_buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
uint8_t endpoint_start[4];
uint8_t endpoint_end[4];
for (int j = 0; j < 4; j++)
{
endpoint_start[j] = endpoint_array[2 * subset_index[i] * 4 + j];
endpoint_end[j] = endpoint_array[(2 * subset_index[i] + 1) * 4 + j];
}
uint32_t output = 0;
output = detexPack32R8(Interpolate(endpoint_start[0], endpoint_end[0], color_index[i], color_index_bitcount));
output |= detexPack32G8(Interpolate(endpoint_start[1], endpoint_end[1], color_index[i], color_index_bitcount));
output |= detexPack32B8(Interpolate(endpoint_start[2], endpoint_end[2], color_index[i], color_index_bitcount));
output |= detexPack32A8(Interpolate(endpoint_start[3], endpoint_end[3], alpha_index[i], alpha_index_bitcount));
if (rotation > 0)
{
if (rotation == 1)
output = detexPack32RGBA8(detexPixel32GetA8(output), detexPixel32GetG8(output), detexPixel32GetB8(output), detexPixel32GetR8(output));
else
{
if (rotation == 2)
output = detexPack32RGBA8(detexPixel32GetR8(output), detexPixel32GetA8(output), detexPixel32GetB8(output), detexPixel32GetG8(output));
else // rotation == 3
output = detexPack32RGBA8(detexPixel32GetR8(output), detexPixel32GetG8(output), detexPixel32GetA8(output), detexPixel32GetB8(output));
}
}
pixel32_buffer[i] = output;
}
return true;
}
/**
Decompress a 128-bit 4x4 pixel texture block compressed using the
BPTC_FLOAT (BC6H) format. The output format is
DETEX_PIXEL_FORMAT_FLOAT_RGBX16.
*/
bool detexDecompressBlockBPTC_FLOAT(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
return DecompressBlockBPTCFloatShared(bitstring, mode_mask, flags, false, pixel_buffer);
}
/**
Decompress a 128-bit 4x4 pixel texture block compressed using the
BPTC_FLOAT (BC6H_FLOAT) format. The output format is
DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16.
*/
bool detexDecompressBlockBPTC_SIGNED_FLOAT(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
return DecompressBlockBPTCFloatShared(bitstring, mode_mask, flags, true, pixel_buffer);
}
//////////////////////////////////////////////////////////////////////////////////
static DETEX_INLINE_ONLY int clamp2047(int x)
{
if (x < 0)
return 0;
if (x > 2047)
return 2047;
return x;
}
static DETEX_INLINE_ONLY int clamp1023_signed(int x)
{
if (x < -1023)
return -1023;
if (x > 1023)
return 1023;
return x;
}
/** Clamp an integer value in the range -255 to 511 to the the range 0 to 255. */
static DETEX_INLINE_ONLY uint8_t detexClamp0To255(int x)
{
return detex_clamp0to255_table[x + 255];
}
// This function calculates the 3-bit complement value in the range -4 to 3 of a three bit
// representation. The result is arithmetically shifted 3 places to the left before returning.
static DETEX_INLINE_ONLY int complement3bitshifted(int x)
{
return complement3bitshifted_table[x];
}
static DETEX_INLINE_ONLY int complement3bitshifted_slow(int x)
{
if (x & 4)
return ((x & 3) - 4) << 3; // Note: shift is arithmetic.
return x << 3;
}
static DETEX_INLINE_ONLY int complement3bit(int x)
{
if (x & 4)
return ((x & 3) - 4);
return x;
}
// Define inline function to speed up ETC1 decoding.
static DETEX_INLINE_ONLY void ProcessPixelETC1(uint8_t i, uint32_t pixel_index_word, uint32_t table_codeword, int * DETEX_RESTRICT base_color_subblock, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r, g, b;
int modifier = modifier_table[table_codeword][pixel_index];
r = detexClamp0To255(base_color_subblock[0] + modifier);
g = detexClamp0To255(base_color_subblock[1] + modifier);
b = detexClamp0To255(base_color_subblock[2] + modifier);
uint32_t *buffer = (uint32_t *)pixel_buffer;
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = detexPack32RGB8Alpha0xFF(r, g, b);
}
/* Decompress a 64-bit 4x4 pixel texture block compressed using the ETC1 */
/* format. */
bool detexDecompressBlockETC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int differential_mode = bitstring[3] & 2;
if (differential_mode)
{
if ((mode_mask & DETEX_MODE_MASK_ETC_DIFFERENTIAL) == 0)
return false;
}
else
{
if ((mode_mask & DETEX_MODE_MASK_ETC_INDIVIDUAL) == 0)
return false;
}
int flipbit = bitstring[3] & 1;
int base_color_subblock1[3];
int base_color_subblock2[3];
if (differential_mode)
{
base_color_subblock1[0] = (bitstring[0] & 0xF8);
base_color_subblock1[0] |= ((base_color_subblock1[0] & 224) >> 5);
base_color_subblock1[1] = (bitstring[1] & 0xF8);
base_color_subblock1[1] |= (base_color_subblock1[1] & 224) >> 5;
base_color_subblock1[2] = (bitstring[2] & 0xF8);
base_color_subblock1[2] |= (base_color_subblock1[2] & 224) >> 5;
base_color_subblock2[0] = (bitstring[0] & 0xF8); // 5 highest order bits.
base_color_subblock2[0] += complement3bitshifted(bitstring[0] & 7); // Add difference.
if (base_color_subblock2[0] & 0xFF07) // Check for overflow.
return false;
base_color_subblock2[0] |= (base_color_subblock2[0] & 224) >> 5; // Replicate.
base_color_subblock2[1] = (bitstring[1] & 0xF8);
base_color_subblock2[1] += complement3bitshifted(bitstring[1] & 7);
if (base_color_subblock2[1] & 0xFF07)
return false;
base_color_subblock2[1] |= (base_color_subblock2[1] & 224) >> 5;
base_color_subblock2[2] = (bitstring[2] & 0xF8);
base_color_subblock2[2] += complement3bitshifted(bitstring[2] & 7);
if (base_color_subblock2[2] & 0xFF07)
return false;
base_color_subblock2[2] |= (base_color_subblock2[2] & 224) >> 5;
}
else
{
base_color_subblock1[0] = (bitstring[0] & 0xF0);
base_color_subblock1[0] |= base_color_subblock1[0] >> 4;
base_color_subblock1[1] = (bitstring[1] & 0xF0);
base_color_subblock1[1] |= base_color_subblock1[1] >> 4;
base_color_subblock1[2] = (bitstring[2] & 0xF0);
base_color_subblock1[2] |= base_color_subblock1[2] >> 4;
base_color_subblock2[0] = (bitstring[0] & 0x0F);
base_color_subblock2[0] |= base_color_subblock2[0] << 4;
base_color_subblock2[1] = (bitstring[1] & 0x0F);
base_color_subblock2[1] |= base_color_subblock2[1] << 4;
base_color_subblock2[2] = (bitstring[2] & 0x0F);
base_color_subblock2[2] |= base_color_subblock2[2] << 4;
}
uint32_t table_codeword1 = (bitstring[3] & 224) >> 5;
uint32_t table_codeword2 = (bitstring[3] & 28) >> 2;
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
if (flipbit == 0)
{
ProcessPixelETC1(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(1, pixel_index_word, table_codeword1,base_color_subblock1, pixel_buffer);
ProcessPixelETC1(2, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(3, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(6, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(7, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(8, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(9, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(12, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(13, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
else
{
ProcessPixelETC1(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(1, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(2, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(3, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(6, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(7, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(8, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(9, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(12, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(13, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC1(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC1(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
return true;
}
static const int etc2_distance_table[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
static void ProcessBlockETC2TOrHMode(const uint8_t * DETEX_RESTRICT bitstring, int mode, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int base_color1_R, base_color1_G, base_color1_B;
int base_color2_R, base_color2_G, base_color2_B;
int paint_color_R[4], paint_color_G[4], paint_color_B[4];
int distance;
if (mode == DETEX_MODE_MASK_ETC_T)
{
// T mode.
base_color1_R = ((bitstring[0] & 0x18) >> 1) | (bitstring[0] & 0x3);
base_color1_R |= base_color1_R << 4;
base_color1_G = bitstring[1] & 0xF0;
base_color1_G |= base_color1_G >> 4;
base_color1_B = bitstring[1] & 0x0F;
base_color1_B |= base_color1_B << 4;
base_color2_R = bitstring[2] & 0xF0;
base_color2_R |= base_color2_R >> 4;
base_color2_G = bitstring[2] & 0x0F;
base_color2_G |= base_color2_G << 4;
base_color2_B = bitstring[3] & 0xF0;
base_color2_B |= base_color2_B >> 4;
// index = (da << 1) | db
distance = etc2_distance_table[((bitstring[3] & 0x0C) >> 1) | (bitstring[3] & 0x1)];
paint_color_R[0] = base_color1_R;
paint_color_G[0] = base_color1_G;
paint_color_B[0] = base_color1_B;
paint_color_R[2] = base_color2_R;
paint_color_G[2] = base_color2_G;
paint_color_B[2] = base_color2_B;
paint_color_R[1] = detexClamp0To255(base_color2_R + distance);
paint_color_G[1] = detexClamp0To255(base_color2_G + distance);
paint_color_B[1] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
else
{
// H mode.
base_color1_R = (bitstring[0] & 0x78) >> 3;
base_color1_R |= base_color1_R << 4;
base_color1_G = ((bitstring[0] & 0x07) << 1) | ((bitstring[1] & 0x10) >> 4);
base_color1_G |= base_color1_G << 4;
base_color1_B = (bitstring[1] & 0x08) | ((bitstring[1] & 0x03) << 1) | ((bitstring[2] & 0x80) >> 7);
base_color1_B |= base_color1_B << 4;
base_color2_R = (bitstring[2] & 0x78) >> 3;
base_color2_R |= base_color2_R << 4;
base_color2_G = ((bitstring[2] & 0x07) << 1) | ((bitstring[3] & 0x80) >> 7);
base_color2_G |= base_color2_G << 4;
base_color2_B = (bitstring[3] & 0x78) >> 3;
base_color2_B |= base_color2_B << 4;
// da is most significant bit, db is middle bit, least significant bit is
// (base_color1 value >= base_color2 value).
int base_color1_value = (base_color1_R << 16) + (base_color1_G << 8) + base_color1_B;
int base_color2_value = (base_color2_R << 16) + (base_color2_G << 8) + base_color2_B;
int bit;
if (base_color1_value >= base_color2_value)
bit = 1;
else
bit = 0;
distance = etc2_distance_table[(bitstring[3] & 0x04) | ((bitstring[3] & 0x01) << 1) | bit];
paint_color_R[0] = detexClamp0To255(base_color1_R + distance);
paint_color_G[0] = detexClamp0To255(base_color1_G + distance);
paint_color_B[0] = detexClamp0To255(base_color1_B + distance);
paint_color_R[1] = detexClamp0To255(base_color1_R - distance);
paint_color_G[1] = detexClamp0To255(base_color1_G - distance);
paint_color_B[1] = detexClamp0To255(base_color1_B - distance);
paint_color_R[2] = detexClamp0To255(base_color2_R + distance);
paint_color_G[2] = detexClamp0To255(base_color2_G + distance);
paint_color_B[2] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
uint32_t *buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r = paint_color_R[pixel_index];
int g = paint_color_G[pixel_index];
int b = paint_color_B[pixel_index];
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = detexPack32RGB8Alpha0xFF(r, g, b);
}
}
static void ProcessBlockETC2PlanarMode(const uint8_t * DETEX_RESTRICT bitstring, uint8_t * DETEX_RESTRICT pixel_buffer)
{
// Each color O, H and V is in 6-7-6 format.
int RO = (bitstring[0] & 0x7E) >> 1;
int GO = ((bitstring[0] & 0x1) << 6) | ((bitstring[1] & 0x7E) >> 1);
int BO = ((bitstring[1] & 0x1) << 5) | (bitstring[2] & 0x18) | ((bitstring[2] & 0x03) << 1) | ((bitstring[3] & 0x80) >> 7);
int RH = ((bitstring[3] & 0x7C) >> 1) | (bitstring[3] & 0x1);
int GH = (bitstring[4] & 0xFE) >> 1;
int BH = ((bitstring[4] & 0x1) << 5) | ((bitstring[5] & 0xF8) >> 3);
int RV = ((bitstring[5] & 0x7) << 3) | ((bitstring[6] & 0xE0) >> 5);
int GV = ((bitstring[6] & 0x1F) << 2) | ((bitstring[7] & 0xC0) >> 6);
int BV = bitstring[7] & 0x3F;
RO = (RO << 2) | ((RO & 0x30) >> 4); // Replicate bits.
GO = (GO << 1) | ((GO & 0x40) >> 6);
BO = (BO << 2) | ((BO & 0x30) >> 4);
RH = (RH << 2) | ((RH & 0x30) >> 4);
GH = (GH << 1) | ((GH & 0x40) >> 6);
BH = (BH << 2) | ((BH & 0x30) >> 4);
RV = (RV << 2) | ((RV & 0x30) >> 4);
GV = (GV << 1) | ((GV & 0x40) >> 6);
BV = (BV << 2) | ((BV & 0x30) >> 4);
uint32_t *buffer = (uint32_t *)pixel_buffer;
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
int r = detexClamp0To255((x * (RH - RO) + y * (RV - RO) + 4 * RO + 2) >> 2);
int g = detexClamp0To255((x * (GH - GO) + y * (GV - GO) + 4 * GO + 2) >> 2);
int b = detexClamp0To255((x * (BH - BO) + y * (BV - BO) + 4 * BO + 2) >> 2);
buffer[y * 4 + x] = detexPack32RGB8Alpha0xFF(r, g, b);
}
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the ETC2 format. */
bool detexDecompressBlockETC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
// Figure out the mode.
if ((bitstring[3] & 2) == 0)
{
// Individual mode.
return detexDecompressBlockETC1(bitstring, mode_mask, flags, pixel_buffer);
}
if ((mode_mask & (~DETEX_MODE_MASK_ETC_INDIVIDUAL)) == 0)
return false;
int R = (bitstring[0] & 0xF8);
R += complement3bitshifted(bitstring[0] & 7);
int G = (bitstring[1] & 0xF8);
G += complement3bitshifted(bitstring[1] & 7);
int B = (bitstring[2] & 0xF8);
B += complement3bitshifted(bitstring[2] & 7);
if (R & 0xFF07)
{
// T mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_T) == 0)
return false;
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_T, pixel_buffer);
return true;
}
else if (G & 0xFF07)
{
// H mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_H) == 0)
return false;
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_H,
pixel_buffer);
return true;
}
else if (B & 0xFF07)
{
// Planar mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_PLANAR) == 0)
return false;
ProcessBlockETC2PlanarMode(bitstring, pixel_buffer);
return true;
}
else
{
// Differential mode.
return detexDecompressBlockETC1(bitstring, mode_mask, flags, pixel_buffer);
}
}
static const int punchthrough_modifier_table[8][4] = {
{ 0, 8, 0, -8 },
{ 0, 17, 0, -17 },
{ 0, 29, 0, -29 },
{ 0, 42, 0, -42 },
{ 0, 60, 0, -60 },
{ 0, 80, 0, -80 },
{ 0, 106, 0, -106 },
{ 0, 183, 0, -183 }
};
static const uint32_t punchthrough_mask_table[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF };
static DETEX_INLINE_ONLY void ProcessPixelETC2Punchthrough(uint8_t i, uint32_t pixel_index_word, uint32_t table_codeword, int * DETEX_RESTRICT base_color_subblock, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r, g, b;
int modifier = punchthrough_modifier_table[table_codeword][pixel_index];
r = detexClamp0To255(base_color_subblock[0] + modifier);
g = detexClamp0To255(base_color_subblock[1] + modifier);
b = detexClamp0To255(base_color_subblock[2] + modifier);
uint32_t mask = punchthrough_mask_table[pixel_index];
uint32_t *buffer = (uint32_t *)pixel_buffer;
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = detexPack32RGB8Alpha0xFF(r, g, b) & mask;
}
void ProcessBlockETC2PunchthroughDifferentialMode(const uint8_t * DETEX_RESTRICT bitstring, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int flipbit = bitstring[3] & 1;
int base_color_subblock1[3];
int base_color_subblock2[3];
base_color_subblock1[0] = (bitstring[0] & 0xF8);
base_color_subblock1[0] |= ((base_color_subblock1[0] & 224) >> 5);
base_color_subblock1[1] = (bitstring[1] & 0xF8);
base_color_subblock1[1] |= (base_color_subblock1[1] & 224) >> 5;
base_color_subblock1[2] = (bitstring[2] & 0xF8);
base_color_subblock1[2] |= (base_color_subblock1[2] & 224) >> 5;
base_color_subblock2[0] = (bitstring[0] & 0xF8); // 5 highest order bits.
base_color_subblock2[0] += complement3bitshifted(bitstring[0] & 7); // Add difference.
base_color_subblock2[0] |= (base_color_subblock2[0] & 224) >> 5; // Replicate.
base_color_subblock2[1] = (bitstring[1] & 0xF8);
base_color_subblock2[1] += complement3bitshifted(bitstring[1] & 7);
base_color_subblock2[1] |= (base_color_subblock2[1] & 224) >> 5;
base_color_subblock2[2] = (bitstring[2] & 0xF8);
base_color_subblock2[2] += complement3bitshifted(bitstring[2] & 7);
base_color_subblock2[2] |= (base_color_subblock2[2] & 224) >> 5;
uint32_t table_codeword1 = (bitstring[3] & 224) >> 5;
uint32_t table_codeword2 = (bitstring[3] & 28) >> 2;
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
if (flipbit == 0)
{
ProcessPixelETC2Punchthrough(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(1, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(2, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(3, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(6, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(7, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(8, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(9, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(12, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(13, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
else
{
ProcessPixelETC2Punchthrough(0, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(1, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(2, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(3, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(4, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(5, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(6, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(7, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(8, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(9, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(10, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(11, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(12, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(13, pixel_index_word, table_codeword1, base_color_subblock1, pixel_buffer);
ProcessPixelETC2Punchthrough(14, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
ProcessPixelETC2Punchthrough(15, pixel_index_word, table_codeword2, base_color_subblock2, pixel_buffer);
}
}
static void ProcessBlockETC2PunchthroughTOrHMode(const uint8_t * DETEX_RESTRICT bitstring, int mode, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int base_color1_R, base_color1_G, base_color1_B;
int base_color2_R, base_color2_G, base_color2_B;
int paint_color_R[4], paint_color_G[4], paint_color_B[4];
int distance;
if (mode == DETEX_MODE_MASK_ETC_T)
{
// T mode.
base_color1_R = ((bitstring[0] & 0x18) >> 1) | (bitstring[0] & 0x3);
base_color1_R |= base_color1_R << 4;
base_color1_G = bitstring[1] & 0xF0;
base_color1_G |= base_color1_G >> 4;
base_color1_B = bitstring[1] & 0x0F;
base_color1_B |= base_color1_B << 4;
base_color2_R = bitstring[2] & 0xF0;
base_color2_R |= base_color2_R >> 4;
base_color2_G = bitstring[2] & 0x0F;
base_color2_G |= base_color2_G << 4;
base_color2_B = bitstring[3] & 0xF0;
base_color2_B |= base_color2_B >> 4;
// index = (da << 1) | db
distance = etc2_distance_table[((bitstring[3] & 0x0C) >> 1) | (bitstring[3] & 0x1)];
paint_color_R[0] = base_color1_R;
paint_color_G[0] = base_color1_G;
paint_color_B[0] = base_color1_B;
paint_color_R[2] = base_color2_R;
paint_color_G[2] = base_color2_G;
paint_color_B[2] = base_color2_B;
paint_color_R[1] = detexClamp0To255(base_color2_R + distance);
paint_color_G[1] = detexClamp0To255(base_color2_G + distance);
paint_color_B[1] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
else
{
// H mode.
base_color1_R = (bitstring[0] & 0x78) >> 3;
base_color1_R |= base_color1_R << 4;
base_color1_G = ((bitstring[0] & 0x07) << 1) | ((bitstring[1] & 0x10) >> 4);
base_color1_G |= base_color1_G << 4;
base_color1_B = (bitstring[1] & 0x08) | ((bitstring[1] & 0x03) << 1) | ((bitstring[2] & 0x80) >> 7);
base_color1_B |= base_color1_B << 4;
base_color2_R = (bitstring[2] & 0x78) >> 3;
base_color2_R |= base_color2_R << 4;
base_color2_G = ((bitstring[2] & 0x07) << 1) | ((bitstring[3] & 0x80) >> 7);
base_color2_G |= base_color2_G << 4;
base_color2_B = (bitstring[3] & 0x78) >> 3;
base_color2_B |= base_color2_B << 4;
// da is most significant bit, db is middle bit, least significant bit is
// (base_color1 value >= base_color2 value).
int base_color1_value = (base_color1_R << 16) + (base_color1_G << 8) + base_color1_B;
int base_color2_value = (base_color2_R << 16) + (base_color2_G << 8) + base_color2_B;
int bit;
if (base_color1_value >= base_color2_value)
bit = 1;
else
bit = 0;
distance = etc2_distance_table[(bitstring[3] & 0x04) | ((bitstring[3] & 0x01) << 1) | bit];
paint_color_R[0] = detexClamp0To255(base_color1_R + distance);
paint_color_G[0] = detexClamp0To255(base_color1_G + distance);
paint_color_B[0] = detexClamp0To255(base_color1_B + distance);
paint_color_R[1] = detexClamp0To255(base_color1_R - distance);
paint_color_G[1] = detexClamp0To255(base_color1_G - distance);
paint_color_B[1] = detexClamp0To255(base_color1_B - distance);
paint_color_R[2] = detexClamp0To255(base_color2_R + distance);
paint_color_G[2] = detexClamp0To255(base_color2_G + distance);
paint_color_B[2] = detexClamp0To255(base_color2_B + distance);
paint_color_R[3] = detexClamp0To255(base_color2_R - distance);
paint_color_G[3] = detexClamp0To255(base_color2_G - distance);
paint_color_B[3] = detexClamp0To255(base_color2_B - distance);
}
uint32_t pixel_index_word = ((uint32_t)bitstring[4] << 24) | ((uint32_t)bitstring[5] << 16) | ((uint32_t)bitstring[6] << 8) | bitstring[7];
uint32_t *buffer = (uint32_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = ((pixel_index_word & (1 << i)) >> i) | ((pixel_index_word & (0x10000 << i)) >> (16 + i - 1));
int r = paint_color_R[pixel_index];
int g = paint_color_G[pixel_index];
int b = paint_color_B[pixel_index];
uint32_t mask = punchthrough_mask_table[pixel_index];
buffer[(i & 3) * 4 + ((i & 12) >> 2)] = (detexPack32RGB8Alpha0xFF(r, g, b)) & mask;
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the ETC2_PUNCHTROUGH format. */
bool detexDecompressBlockETC2_PUNCHTHROUGH(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int R = (bitstring[0] & 0xF8);
R += complement3bitshifted(bitstring[0] & 7);
int G = (bitstring[1] & 0xF8);
G += complement3bitshifted(bitstring[1] & 7);
int B = (bitstring[2] & 0xF8);
B += complement3bitshifted(bitstring[2] & 7);
int opaque = bitstring[3] & 2;
if (opaque && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY))
return false;
if (!opaque && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY))
return false;
if (R & 0xFF07)
{
// T mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_T) == 0)
return false;
if (opaque)
{
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_T, pixel_buffer);
return true;
}
// T mode with punchthrough alpha.
ProcessBlockETC2PunchthroughTOrHMode(bitstring, DETEX_MODE_MASK_ETC_T, pixel_buffer);
return true;
}
else if (G & 0xFF07)
{
// H mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_H) == 0)
return false;
if (opaque)
{
ProcessBlockETC2TOrHMode(bitstring, DETEX_MODE_MASK_ETC_H, pixel_buffer);
return true;
}
// H mode with punchthrough alpha.
ProcessBlockETC2PunchthroughTOrHMode(bitstring, DETEX_MODE_MASK_ETC_H, pixel_buffer);
return true;
}
else if (B & 0xFF07)
{
// Planar mode.
if ((mode_mask & DETEX_MODE_MASK_ETC_PLANAR) == 0)
return false;
// Opaque always set.
if (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY)
return false;
ProcessBlockETC2PlanarMode(bitstring, pixel_buffer);
return true;
}
else
{
// Differential mode.
if (opaque)
return detexDecompressBlockETC1(bitstring, mode_mask, flags, pixel_buffer);
// Differential mode with punchthrough alpha.
if ((mode_mask & DETEX_MODE_MASK_ETC_DIFFERENTIAL) == 0)
return false;
ProcessBlockETC2PunchthroughDifferentialMode(bitstring, pixel_buffer);
return true;
}
}
static const int8_t eac_modifier_table[16][8] = {
{ -3, -6, -9, -15, 2, 5, 8, 14 },
{ -3, -7, -10, -13, 2, 6, 9, 12 },
{ -2, -5, -8, -13, 1, 4, 7, 12 },
{ -2, -4, -6, -13, 1, 3, 5, 12 },
{ -3, -6, -8, -12, 2, 5, 7, 11 },
{ -3, -7, -9, -11, 2, 6, 8, 10 },
{ -4, -7, -8, -11, 3, 6, 7, 10 },
{ -3, -5, -8, -11, 2, 4, 7, 10 },
{ -2, -6, -8, -10, 1, 5, 7, 9 },
{ -2, -5, -8, -10, 1, 4, 7, 9 },
{ -2, -4, -8, -10, 1, 3, 7, 9 },
{ -2, -5, -7, -10, 1, 4, 6, 9 },
{ -3, -4, -7, -10, 2, 3, 6, 9 },
{ -1, -2, -3, -10, 0, 1, 2, 9 },
{ -4, -6, -8, -9, 3, 5, 7, 8 },
{ -3, -5, -7, -9, 2, 4, 6, 8 }
};
static DETEX_INLINE_ONLY int modifier_times_multiplier(int modifier, int multiplier)
{
return modifier * multiplier;
}
static DETEX_INLINE_ONLY void ProcessPixelEAC(uint8_t i, uint64_t pixels, const int8_t * DETEX_RESTRICT _modifier_table, int base_codeword, int multiplier, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int modifier = _modifier_table[(pixels >> (45 - i * 3)) & 7];
pixel_buffer[((i & 3) * 4 + ((i & 12) >> 2)) * 4 + DETEX_PIXEL32_ALPHA_BYTE_OFFSET] = detexClamp0To255(base_codeword + modifier_times_multiplier(modifier, multiplier));
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the ETC2_EAC format. */
bool detexDecompressBlockETC2_EAC(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
bool r = detexDecompressBlockETC2(&bitstring[8], mode_mask, flags, pixel_buffer);
if (!r)
return false;
// Decode the alpha part.
int base_codeword = bitstring[0];
const int8_t *_modifier_table = eac_modifier_table[(bitstring[1] & 0x0F)];
int multiplier = (bitstring[1] & 0xF0) >> 4;
if (multiplier == 0 && (flags & DETEX_DECOMPRESS_FLAG_ENCODE))
// Not allowed in encoding. Decoder should handle it.
return false;
uint64_t pixels = ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
ProcessPixelEAC(0, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(1, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(2, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(3, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(4, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(5, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(6, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(7, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(8, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(9, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(10, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(11, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(12, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(13, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(14, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
ProcessPixelEAC(15, pixels, _modifier_table, base_codeword, multiplier, pixel_buffer);
return true;
}
/**
For each pixel, decode an 11-bit integer and store as follows:
If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer.
If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset
is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each
32-bit word.
*/
static DETEX_INLINE_ONLY void DecodeBlockEAC11Bit(uint64_t qword, int shift, int offset, uint8_t * DETEX_RESTRICT pixel_buffer)
{
int base_codeword_times_8_plus_4 = ((qword & 0xFF00000000000000) >> (56 - 3)) | 0x4;
int modifier_index = (qword & 0x000F000000000000) >> 48;
const int8_t *_modifier_table = eac_modifier_table[modifier_index];
int multiplier_times_8 = (qword & 0x00F0000000000000) >> (52 - 3);
if (multiplier_times_8 == 0)
multiplier_times_8 = 1;
uint16_t *buffer = (uint16_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = (qword & (0x0000E00000000000 >> (i * 3))) >> (45 - i * 3);
int modifier = _modifier_table[pixel_index];
uint32_t value = clamp2047(base_codeword_times_8_plus_4 + modifier * multiplier_times_8);
buffer[(((i & 3) * 4 + ((i & 12) >> 2)) << shift) + offset] = (value << 5) | (value >> 6); // Replicate bits to 16-bit.
}
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using theEAC_R11 format. */
bool detexDecompressBlockEAC_R11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
DecodeBlockEAC11Bit(qword, 0, 0, pixel_buffer);
return true;
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the EAC_RG11 format. */
bool detexDecompressBlockEAC_RG11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t red_qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
DecodeBlockEAC11Bit(red_qword, 1, 0, pixel_buffer);
uint64_t green_qword = ((uint64_t)bitstring[8] << 56) | ((uint64_t)bitstring[9] << 48) | ((uint64_t)bitstring[10] << 40) | ((uint64_t)bitstring[11] << 32) | ((uint64_t)bitstring[12] << 24) | ((uint64_t)bitstring[13] << 16) | ((uint64_t)bitstring[14] << 8) | bitstring[15];
DecodeBlockEAC11Bit(green_qword, 1, 1, pixel_buffer);
return true;
}
static DETEX_INLINE_ONLY uint32_t ReplicateSigned11BitsTo16Bits(int value)
{
if (value >= 0)
return (value << 5) | (value >> 5);
value = - value;
value = (value << 5) | (value >> 5);
return - value;
}
/**
For each pixel, decode an 11-bit signed integer and store as follows:
If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer.
If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset
is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each
32-bit word.
*/
static DETEX_INLINE_ONLY bool DecodeBlockEACSigned11Bit(uint64_t qword, int shift, int offset, uint8_t *pixel_buffer)
{
int base_codeword = (int8_t)((qword & 0xFF00000000000000) >> 56); // Signed 8 bits.
if (base_codeword == - 128)
// Not allowed in encoding. Decoder should handle it but we don't do that yet.
return false;
int base_codeword_times_8 = base_codeword << 3; // Arithmetic shift.
int modifier_index = (qword & 0x000F000000000000) >> 48;
const int8_t *_modifier_table = eac_modifier_table[modifier_index];
int multiplier_times_8 = (qword & 0x00F0000000000000) >> (52 - 3);
if (multiplier_times_8 == 0)
multiplier_times_8 = 1;
uint16_t *buffer = (uint16_t *)pixel_buffer;
for (int i = 0; i < 16; i++)
{
int pixel_index = (qword & (0x0000E00000000000 >> (i * 3))) >> (45 - i * 3);
int modifier = _modifier_table[pixel_index];
int value = clamp1023_signed(base_codeword_times_8 + modifier * multiplier_times_8);
uint32_t bits = ReplicateSigned11BitsTo16Bits(value);
buffer[(((i & 3) * 4 + ((i & 12) >> 2)) << shift) + offset] = bits;
}
return true;
}
/** Decompress a 64-bit 4x4 pixel texture block compressed using the EAC_SIGNED_R11 format. */
bool detexDecompressBlockEAC_SIGNED_R11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
return DecodeBlockEACSigned11Bit(qword, 0, 0, pixel_buffer);
}
/** Decompress a 128-bit 4x4 pixel texture block compressed using the EAC_SIGNED_RG11 format. */
bool detexDecompressBlockEAC_SIGNED_RG11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer)
{
uint64_t red_qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7];
int r = DecodeBlockEACSigned11Bit(red_qword, 1, 0, pixel_buffer);
if (!r)
return false;
uint64_t green_qword = ((uint64_t)bitstring[8] << 56) | ((uint64_t)bitstring[9] << 48) | ((uint64_t)bitstring[10] << 40) | ((uint64_t)bitstring[11] << 32) | ((uint64_t)bitstring[12] << 24) | ((uint64_t)bitstring[13] << 16) | ((uint64_t)bitstring[14] << 8) | bitstring[15];
return DecodeBlockEACSigned11Bit(green_qword, 1, 1, pixel_buffer);
}
static detexDecompressBlockFuncType decompress_function[] =
{
NULL,
detexDecompressBlockBC1,
detexDecompressBlockBC1A,
detexDecompressBlockBC2,
detexDecompressBlockBC3,
detexDecompressBlockRGTC1,
detexDecompressBlockSIGNED_RGTC1,
detexDecompressBlockRGTC2,
detexDecompressBlockSIGNED_RGTC2,
detexDecompressBlockBPTC_FLOAT,
detexDecompressBlockBPTC_SIGNED_FLOAT,
detexDecompressBlockBPTC,
detexDecompressBlockETC1,
detexDecompressBlockETC2,
detexDecompressBlockETC2_PUNCHTHROUGH,
detexDecompressBlockETC2_EAC,
detexDecompressBlockEAC_R11,
detexDecompressBlockEAC_SIGNED_R11,
detexDecompressBlockEAC_RG11,
detexDecompressBlockEAC_SIGNED_RG11,
};
/**
General block decompression function. Block is decompressed using the given
compressed format, and stored in the given pixel format. Returns true if
succesful.
*/
bool detexDecompressBlock(const uint8_t * DETEX_RESTRICT bitstring, uint32_t texture_format, uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer, uint32_t pixel_format)
{
uint8_t block_buffer[DETEX_MAX_BLOCK_SIZE];
uint32_t compressed_format = detexGetCompressedFormat(texture_format);
bool r = decompress_function[compressed_format](bitstring, mode_mask, flags,
block_buffer);
if (!r)
{
detexSetErrorMessage("detexDecompressBlock: Decompress function for format returned error");
return false;
}
/* Convert into desired pixel format. */
return detexConvertPixels(block_buffer, 16, detexGetPixelFormat(texture_format), pixel_buffer, pixel_format);
}
// Look-up texture file info for KTX file format based on GL format parameters.
const detexTextureFileInfo *detexLookupKTXFileInfo(int gl_internal_format)
{
for (int i = 0; i < DETEX_NU_TEXTURE_INFO_ENTRIES; i++)
{
if (texture_info[i].gl_internal_format == gl_internal_format)
{
return &texture_info[i];
}
}
return NULL;
}
/*
* Decode texture function (linear). Decode an entire texture into a single
* image buffer, with pixels stored row-by-row, converting into the given pixel
* format.
*/
bool detexDecompressTextureLinear(const FDetexTexture *texture, uint8_t *pixel_buffer, uint32_t pixel_format)
{
uint8_t block_buffer[DETEX_MAX_BLOCK_SIZE];
const uint8_t *data = texture->data;
int pixel_size = detexGetPixelSize(pixel_format);
bool result = true;
for (int y = 0; y < texture->height_in_blocks; y++)
{
int nu_rows;
if (y * 4 + 3 >= texture->height)
{
nu_rows = texture->height - y * 4;
}
else
{
nu_rows = 4;
}
for (int x = 0; x < texture->width_in_blocks; x++)
{
bool r = detexDecompressBlock(data, texture->format, DETEX_MODE_MASK_ALL, 0, block_buffer, pixel_format);
uint32_t block_size = detexGetPixelSize(pixel_format) * 16;
if (!r)
{
result = false;
memset(block_buffer, 0, block_size);
}
uint8_t *pixelp = pixel_buffer + y * 4 * texture->width * pixel_size + x * 4 * pixel_size;
int nu_columns;
if (x * 4 + 3 >= texture->width)
{
nu_columns = texture->width - x * 4;
}
else
{
nu_columns = 4;
}
for (int row = 0; row < nu_rows; row++)
{
memcpy(pixelp + row * texture->width * pixel_size, block_buffer + row * 4 * pixel_size, nu_columns * pixel_size);
}
data += detexGetCompressedBlockSize(texture->format);
}
}
return result;
}
bool DecompressTexture(uint8_t *data, const uint32_t SizeX, const uint32_t SizeY, uint32_t InternalFormat, uint8_t **decompressedData)
{
FDetexTexture dexTexture;
dexTexture.data = data;
dexTexture.width = SizeX;
dexTexture.height = SizeY;
const int32 BlockSizeX = 4;
const int32 BlockSizeY = 4;
dexTexture.width_in_blocks = FMath::Max(SizeX / BlockSizeX, (uint32_t)1);
dexTexture.height_in_blocks = FMath::Max(SizeY / BlockSizeY, (uint32_t)1);
const detexTextureFileInfo *DetexTFI = detexLookupKTXFileInfo(InternalFormat);
uint32_t pixel_format = detexGetPixelFormat(DetexTFI->texture_format);
dexTexture.format = DetexTFI->texture_format;
uint32_t decompressSize = SizeX * SizeY * detexGetPixelSize(pixel_format);
(*decompressedData) = (uint8_t *)malloc(decompressSize);
return detexDecompressTextureLinear(&dexTexture, *decompressedData, pixel_format);
}