Files
UnrealEngineUWP/Engine/Source/ThirdParty/Android/detex/AndroidETCConvert.cpp
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

1240 lines
50 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "AndroidETC.h"
#include "AndroidETCInternal.h"
//#include "detex.h"
//#include "half-float.h"
//#include "hdr.h"
//#include "misc.h"
// Conversion functions. For conversions where the pixel size is unchanged,
// the conversion is performed in-place and target_pixel_buffer will be NULL.
static void ConvertNoop(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
}
// In-place BGR <-> RGB conversions.
static void ConvertPixel32RGBA8ToPixel32BGRA8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
/* Swap R and B. */
uint32_t pixel = *source_pixel32_buffer;
pixel = detexPack32RGBA8(
detexPixel32GetB8(pixel),
detexPixel32GetG8(pixel),
detexPixel32GetR8(pixel),
detexPixel32GetA8(pixel)
);
*source_pixel32_buffer = pixel;
source_pixel32_buffer++;
}
}
static void ConvertPixel64RGBX16ToPixel64BGRX16(uint8_t * source_pixel_buffer, int nu_pixels, uint8_t * target_pixel_buffer)
{
uint64_t *source_pixel64_buffer = (uint64_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
/* Swap R and B (16-bit). */
uint64_t pixel = *source_pixel64_buffer;
pixel = detexPack64RGBA16(
detexPixel64GetB16(pixel),
detexPixel64GetG16(pixel),
detexPixel64GetR16(pixel),
detexPixel64GetA16(pixel)
);
*source_pixel64_buffer = pixel;
source_pixel64_buffer++;
}
}
// Swapping red and blue (not in-place).
static void ConvertPixel24RGB8ToPixel32BGRX8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
/* Swap R and B. */
uint32_t red = source_pixel_buffer[0];
uint32_t green = source_pixel_buffer[1];
uint32_t blue = source_pixel_buffer[2];
uint32_t pixel = detexPack32RGB8Alpha0xFF(blue, green, red);
*target_pixel32_buffer = pixel;
source_pixel_buffer += 3;
target_pixel32_buffer++;
}
}
// In-place signed integer conversions (8-bit components).
static void ConvertPixel8R8ToPixel8SignedR8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
for (int i = 0; i < nu_pixels; i++)
{
int32_t red = *source_pixel_buffer;
red -= 128;
*source_pixel_buffer = red;
source_pixel_buffer++;
}
}
static void ConvertPixel16RG8ToPixel16SignedRG8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel16_buffer;
uint32_t red = (uint8_t)((int)detexPixel32GetR8(pixel) - 128);
uint32_t green = (uint8_t)((int)detexPixel32GetG8(pixel) - 128);
*source_pixel16_buffer = detexPack32RG8(red, green);
source_pixel16_buffer++;
}
}
static void ConvertPixel8SignedR8ToPixel8R8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
for (int i = 0; i < nu_pixels; i++)
{
int32_t red = *(int8_t *)source_pixel_buffer + 128;
*source_pixel_buffer = (uint8_t)red;
source_pixel_buffer++;
}
}
static void ConvertPixel16SignedRG8ToPixel16RG8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel16_buffer;
uint32_t red = (uint8_t)(detexPixel32GetSignedR8(pixel) + 128);
uint32_t green = (uint8_t)(detexPixel32GetSignedG8(pixel) + 128);
*source_pixel16_buffer = detexPack32RG8(red, green);
source_pixel16_buffer++;
}
}
// In-place signed integer conversions (16-bit components).
static void ConvertPixel16R16ToPixel16SignedR16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
int32_t red = *source_pixel16_buffer;
red -= 32768;
*(int16_t *)source_pixel16_buffer = (int16_t)red;
source_pixel16_buffer++;
}
}
static void ConvertPixel32RG16ToPixel32SignedRG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
uint32_t red = (uint16_t)((int)detexPixel32GetR16(pixel) - 32768);
uint32_t green = (uint16_t)((int)detexPixel32GetG16(pixel) - 32768);
*source_pixel32_buffer = detexPack32RG16(red, green);
source_pixel32_buffer++;
}
}
static void ConvertPixel16SignedR16ToPixel16R16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
int32_t red = *(int16_t *)source_pixel16_buffer;
red += 32768;
*source_pixel16_buffer = (uint16_t)red;
source_pixel16_buffer++;
}
}
static void ConvertPixel32SignedRG16ToPixel32RG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
uint32_t red = (uint16_t)(detexPixel32GetSignedR16(pixel) + 32768);
uint32_t green = (uint16_t)(detexPixel32GetSignedG16(pixel) + 32768);
*source_pixel32_buffer = detexPack32RG16(red, green);
source_pixel32_buffer++;
}
}
// Reducing the number of components.
static void ConvertPixel32RGBA8ToPixel8R8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
*target_pixel_buffer = detexPixel32GetR8(pixel);
source_pixel32_buffer++;
target_pixel_buffer++;
}
}
static void ConvertPixel32RGBA8ToPixel16RG8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
uint16_t *target_pixel16_buffer = (uint16_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
*target_pixel16_buffer = (uint16_t)detexPack32RG8(detexPixel32GetR8(pixel), detexPixel32GetG8(pixel));
source_pixel32_buffer++;
target_pixel16_buffer++;
}
}
static void ConvertPixel24RGB8ToPixel8R8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = source_pixel_buffer[0];
*target_pixel_buffer = red;
source_pixel_buffer += 3;
target_pixel_buffer++;
}
}
static void ConvertPixel24RGB8ToPixel16RG8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = source_pixel_buffer[0];
uint32_t green = source_pixel_buffer[1];
target_pixel_buffer[0] = red;
target_pixel_buffer[1] = green;
source_pixel_buffer += 3;
target_pixel_buffer += 2;
}
}
// Increasing the number of components.
static void ConvertPixel8R8ToPixel32RGBX8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = *source_pixel_buffer;
*target_pixel32_buffer = detexPack32RGB8Alpha0xFF(red, 0, 0);
source_pixel_buffer++;
target_pixel32_buffer++;
}
}
static void ConvertPixel16RG8ToPixel32RGBX8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel16_buffer;
uint32_t red = detexPixel32GetR8(pixel);
uint32_t green = detexPixel32GetG8(pixel);
*target_pixel32_buffer = detexPack32RGB8Alpha0xFF(red, green, 0);
source_pixel16_buffer++;
target_pixel32_buffer++;
}
}
// Conversion to component of different size.
static void ConvertPixel16R16ToPixel8R8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel16_buffer;
*target_pixel_buffer = (detexPixel32GetR16(pixel) + 127) * 255 / 65535;
source_pixel16_buffer++;
target_pixel_buffer++;
}
}
static void ConvertPixel32RG16ToPixel16RG8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
uint16_t *target_pixel16_buffer = (uint16_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
*target_pixel16_buffer = (uint16_t)detexPack32RG8(
(detexPixel32GetR16(pixel) + 127) * 255 / 65535,
(detexPixel32GetG16(pixel) + 127) * 255 / 65535
);
source_pixel32_buffer++;
target_pixel16_buffer++;
}
}
static void ConvertPixel48RGB16ToPixel24RGB8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = source_pixel16_buffer[0];
uint32_t green = source_pixel16_buffer[1];
uint32_t blue = source_pixel16_buffer[2];
target_pixel_buffer[0] = (red + 127) * 255 / 65535;
target_pixel_buffer[1] = (green + 127) * 255 / 65535;
target_pixel_buffer[2] = (blue + 127) * 255 / 65535;
source_pixel16_buffer += 3;
target_pixel_buffer += 3;
}
}
static void ConvertPixel64RGBX16ToPixel32RGBX8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint64_t *source_pixel64_buffer = (uint64_t *)source_pixel_buffer;
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint64_t pixel = *source_pixel64_buffer;
*target_pixel32_buffer = (uint32_t)detexPack32RGB8Alpha0xFF(
(detexPixel64GetR16(pixel) + 127) * 255 / 65535,
(detexPixel64GetG16(pixel) + 127) * 255 / 65535,
(detexPixel64GetB16(pixel) + 127) * 255 / 65535
);
source_pixel64_buffer++;
target_pixel32_buffer++;
}
}
static void ConvertPixel64RGBA16ToPixel32RGBA8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint64_t *source_pixel64_buffer = (uint64_t *)source_pixel_buffer;
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint64_t pixel = *source_pixel64_buffer;
*target_pixel32_buffer = (uint32_t)detexPack32RGBA8(
(detexPixel64GetR16(pixel) + 127) * 255 / 65535,
(detexPixel64GetG16(pixel) + 127) * 255 / 65535,
(detexPixel64GetB16(pixel) + 127) * 255 / 65535,
(detexPixel64GetA16(pixel) + 127) * 255 / 65535
);
source_pixel64_buffer++;
target_pixel32_buffer++;
}
}
static void ConvertPixel8R8ToPixel16R16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *target_pixel16_buffer = (uint16_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++) {
uint32_t pixel = *source_pixel_buffer;
*target_pixel16_buffer = pixel * 65535 / 255;
source_pixel_buffer++;
target_pixel16_buffer++;
}
}
static void ConvertPixel16RG8ToPixel32RG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel16_buffer;
*target_pixel32_buffer = detexPack32RG16(
detexPixel32GetR8(pixel) * 65535 / 255,
detexPixel32GetG8(pixel) * 65535 / 255
);
source_pixel16_buffer++;
target_pixel32_buffer++;
}
}
static void ConvertPixel24RGB8ToPixel48RGB16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *target_pixel16_buffer = (uint16_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = source_pixel_buffer[0];
uint32_t green = source_pixel_buffer[1];
uint32_t blue = source_pixel_buffer[2];
target_pixel16_buffer[0] = red * 65535 / 255;
target_pixel16_buffer[1] = green * 65535 / 255;
target_pixel16_buffer[2] = blue * 65535 / 255;
source_pixel_buffer += 3;
target_pixel16_buffer += 3;
}
}
static void ConvertPixel32RGBX8ToPixel64RGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
uint64_t *target_pixel64_buffer = (uint64_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
*target_pixel64_buffer = detexPack64RGBA16(
detexPixel32GetR8(pixel) * 65535 / 255,
detexPixel32GetG8(pixel) * 65535 / 255,
detexPixel32GetB8(pixel) * 65535 / 255,
0xFFFF
);
source_pixel32_buffer++;
target_pixel64_buffer++;
}
}
static void ConvertPixel32RGBA8ToPixel64RGBA16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
uint64_t *target_pixel64_buffer = (uint64_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
*target_pixel64_buffer = detexPack64RGBA16(
detexPixel32GetR8(pixel) * 65535 / 255,
detexPixel32GetG8(pixel) * 65535 / 255,
detexPixel32GetB8(pixel) * 65535 / 255,
detexPixel32GetA8(pixel) * 65535 / 255
);
source_pixel32_buffer++;
target_pixel64_buffer++;
}
}
// Float to half-float conversion.
static void ConvertPixel32FloatR32ToPixel16FloatR16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertFloatToHalfFloat((float *)source_pixel_buffer, nu_pixels, (uint16_t *)target_pixel_buffer);
}
static void ConvertPixel64FloatRG32ToPixel32FloatRG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertFloatToHalfFloat((float *)source_pixel_buffer, nu_pixels * 2, (uint16_t *)target_pixel_buffer);
}
static void ConvertPixel96FloatRGB32ToPixel48FloatRGB16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertFloatToHalfFloat((float *)source_pixel_buffer, nu_pixels * 3, (uint16_t *)target_pixel_buffer);
}
static void ConvertPixel128FloatRGBX32ToPixel64FloatRGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertFloatToHalfFloat((float *)source_pixel_buffer, nu_pixels * 4, (uint16_t *)target_pixel_buffer);
}
// Float to 16-bit integer conversion.
static void ConvertPixel32FloatR32ToPixel16R16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedFloatToUInt16((float *)source_pixel_buffer, nu_pixels, (uint16_t *)target_pixel_buffer);
}
static void ConvertPixel64FloatRG32ToPixel32RG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedFloatToUInt16((float *)source_pixel_buffer, nu_pixels * 2, (uint16_t *)target_pixel_buffer);
}
static void ConvertPixel96FloatRGB32ToPixel48RGB16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedFloatToUInt16((float *)source_pixel_buffer, nu_pixels * 3, (uint16_t *)target_pixel_buffer);
}
static void ConvertPixel128FloatRGBX32ToPixel64RGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedFloatToUInt16((float *)source_pixel_buffer, nu_pixels * 4, (uint16_t *)target_pixel_buffer);
}
// Half-float to float conversion.
static void ConvertPixel16FloatR16ToPixel32FloatR32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertHalfFloatToFloat((uint16_t *)source_pixel_buffer, nu_pixels, (float *)target_pixel_buffer);
}
static void ConvertPixel32FloatRG16ToPixel64FloatRG32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertHalfFloatToFloat((uint16_t *)source_pixel_buffer, nu_pixels * 2, (float *)target_pixel_buffer);
}
static void ConvertPixel48FloatRGB16ToPixel96FloatRGB32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertHalfFloatToFloat((uint16_t *)source_pixel_buffer, nu_pixels * 3, (float *)target_pixel_buffer);
}
static void ConvertPixel64FloatRGBX16ToPixel128FloatRGBX32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertHalfFloatToFloat((uint16_t *)source_pixel_buffer, nu_pixels * 4, (float *)target_pixel_buffer);
}
// Conversion from 16-bit integer to half-float (in-place).
static void ConvertPixel16R16ToPixel16FloatR16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float float_buffer[64];
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
// Split conversion into stages.
for (int i = 0; i < nu_pixels; i += 64)
{
float *target_pixelf_buffer = (float *)float_buffer;
int nu_stage_pixels = 64;
if (i + 64 > nu_pixels)
nu_stage_pixels = nu_pixels - i;
for (int j = 0; j < nu_stage_pixels; j++)
{
int red = *source_pixel16_buffer;
float redf = red * (1.0f / 65535.0f);
*target_pixelf_buffer = redf;
source_pixel16_buffer++;
target_pixelf_buffer++;
}
ConvertPixel32FloatR32ToPixel16FloatR16((uint8_t *)float_buffer, nu_stage_pixels, source_pixel_buffer);
source_pixel_buffer += nu_stage_pixels * 2;
}
}
static void ConvertPixel32RG16ToPixel32FloatRG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float float_buffer[128];
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
// Split conversion into stages.
for (int i = 0; i < nu_pixels; i += 64)
{
float *target_pixelf_buffer = (float *)float_buffer;
int nu_stage_pixels = 64;
if (i + 64 > nu_pixels)
{
nu_stage_pixels = nu_pixels - i;
}
for (int j = 0; j < nu_stage_pixels; j++)
{
int red = source_pixel16_buffer[0];
int green = source_pixel16_buffer[1];
float redf = red * (1.0f / 65535.0f);
float greenf = green * (1.0f / 65535.0f);
target_pixelf_buffer[0] = redf;
target_pixelf_buffer[1] = greenf;
source_pixel16_buffer += 2;
target_pixelf_buffer += 2;
}
ConvertPixel64FloatRG32ToPixel32FloatRG16((uint8_t *)float_buffer, nu_stage_pixels, source_pixel_buffer);
source_pixel_buffer += nu_stage_pixels * 4;
}
}
static void ConvertPixel48RGB16ToPixel48FloatRGB16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float float_buffer[192];
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
// Split conversion into stages.
for (int i = 0; i < nu_pixels; i += 64)
{
float *target_pixelf_buffer = (float *)float_buffer;
int nu_stage_pixels = 64;
if (i + 64 > nu_pixels)
{
nu_stage_pixels = nu_pixels - i;
}
for (int j = 0; j < nu_stage_pixels; j++)
{
int red = source_pixel16_buffer[0];
int green = source_pixel16_buffer[1];
int blue = source_pixel16_buffer[2];
float redf = red * (1.0f / 65535.0f);
float greenf = green * (1.0f / 65535.0f);
float bluef = blue * (1.0f / 65535.0f);
target_pixelf_buffer[0] = redf;
target_pixelf_buffer[1] = greenf;
target_pixelf_buffer[2] = bluef;
source_pixel16_buffer += 3;
target_pixelf_buffer += 3;
}
ConvertPixel96FloatRGB32ToPixel48FloatRGB16((uint8_t *)float_buffer, nu_stage_pixels, source_pixel_buffer);
source_pixel_buffer += nu_stage_pixels * 6;
}
}
static void ConvertPixel64RGBX16ToPixel64FloatRGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float float_buffer[128];
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
// Split conversion into stages.
for (int i = 0; i < nu_pixels; i += 32)
{
float *target_pixelf_buffer = (float *)float_buffer;
int nu_stage_pixels = 32;
if (i + 32 > nu_pixels)
{
nu_stage_pixels = nu_pixels - i;
}
for (int j = 0; j < nu_stage_pixels; j++)
{
int16_t red = source_pixel16_buffer[0];
int16_t green = source_pixel16_buffer[1];
int16_t blue = source_pixel16_buffer[2];
float redf = red * (1.0f / 65535.0f);
float greenf = green * (1.0f / 65535.0f);
float bluef = blue * (1.0f / 65535.0f);
target_pixelf_buffer[0] = redf;
target_pixelf_buffer[1] = greenf;
target_pixelf_buffer[2] = bluef;
target_pixelf_buffer[3] = 1.0f;
source_pixel16_buffer += 4;
target_pixelf_buffer += 4;
}
ConvertPixel128FloatRGBX32ToPixel64FloatRGBX16((uint8_t *)float_buffer, nu_stage_pixels, source_pixel_buffer);
source_pixel_buffer += nu_stage_pixels * 8;
}
}
// Conversion from normalized half-float to 16-bit integer (in-place).
static void ConvertPixel16FloatR16ToPixel16R16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedHalfFloatToUInt16((uint16_t *)source_pixel_buffer, nu_pixels);
}
static void ConvertPixel32FloatRG16ToPixel32RG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedHalfFloatToUInt16((uint16_t *)source_pixel_buffer, nu_pixels * 2);
}
static void ConvertPixel48FloatRGB16ToPixel48RGB16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedHalfFloatToUInt16((uint16_t *)source_pixel_buffer, nu_pixels * 3);
}
static void ConvertPixel64FloatRGBX16ToPixel64RGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedHalfFloatToUInt16((uint16_t *)source_pixel_buffer, nu_pixels * 4);
}
static void ConvertPixel64FloatRGBA16ToPixel64RGBA16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
detexConvertNormalizedHalfFloatToUInt16((uint16_t *)source_pixel_buffer, nu_pixels * 4);
}
// Conversion from HDR half-float to 16-bit integer (in-place). Depends on gamma parameters.
static void ConvertPixel16FloatR16HDRToPixel16R16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
detexConvertHDRHalfFloatToUInt16(source_pixel16_buffer, nu_pixels);
}
static void ConvertPixel32FloatRG16HDRToPixel32RG16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
detexConvertHDRHalfFloatToUInt16(source_pixel16_buffer, nu_pixels * 2);
}
static void ConvertPixel64FloatRGBX16HDRToPixel64RGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
detexConvertHDRHalfFloatToUInt16(source_pixel16_buffer, nu_pixels * 4);
}
// Conversion HDR float to float (in_place).
static void ConvertPixel32FloatR32HDRToPixel32FloatR32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float *source_pixelf_buffer = (float *)source_pixel_buffer;
detexConvertHDRFloatToFloat(source_pixelf_buffer, nu_pixels);
}
static void ConvertPixel64FloatRG32HDRToPixel64FloatRG32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float *source_pixelf_buffer = (float *)source_pixel_buffer;
detexConvertHDRFloatToFloat(source_pixelf_buffer, nu_pixels * 2);
}
static void ConvertPixel96FloatRGB32HDRToPixel96FloatRGB32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float *source_pixelf_buffer = (float *)source_pixel_buffer;
detexConvertHDRFloatToFloat(source_pixelf_buffer, nu_pixels * 3);
}
static void ConvertPixel128FloatRGBX32HDRToPixel128FloatRGBX32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float *source_pixelf_buffer = (float *)source_pixel_buffer;
detexConvertHDRFloatToFloat(source_pixelf_buffer, nu_pixels * 4);
}
// Conversion between packed RGB8 and RGBX8 and vice-versa.
static void ConvertPixel24RGB8ToPixel32RGBX8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *target_pixel32_buffer = (uint32_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = source_pixel_buffer[0];
uint32_t green = source_pixel_buffer[1];
uint32_t blue = source_pixel_buffer[2];
*target_pixel32_buffer = detexPack32RGB8Alpha0xFF(red, green, blue);
source_pixel_buffer += 3;
target_pixel32_buffer++;
}
}
static void ConvertPixel32RGBX8ToPixel24RGB8(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint32_t *source_pixel32_buffer = (uint32_t *)source_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t pixel = *source_pixel32_buffer;
target_pixel_buffer[0] = detexPixel32GetR8(pixel);
target_pixel_buffer[1] = detexPixel32GetG8(pixel);
target_pixel_buffer[2] = detexPixel32GetB8(pixel);
source_pixel32_buffer++;
target_pixel_buffer += 3;
}
}
// Conversion between packed half-float RGB16 and half-float RGBX16.
static void ConvertPixel48RGB16ToPixel64RGBX16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint16_t hf[1];
float f[1];
f[0] = 1.0f;
detexConvertFloatToHalfFloat(&f[0], 1, &hf[0]);
uint16_t *source_pixel16_buffer = (uint16_t *)source_pixel_buffer;
uint64_t *target_pixel64_buffer = (uint64_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint32_t red = source_pixel16_buffer[0];
uint32_t green = source_pixel16_buffer[1];
uint32_t blue = source_pixel16_buffer[2];
*target_pixel64_buffer = detexPack64RGBA16(red, green, blue, hf[0]);
source_pixel16_buffer += 3;
target_pixel64_buffer++;
}
}
static void ConvertPixel64RGBX16ToPixel48RGB16(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
uint64_t *source_pixel64_buffer = (uint64_t *)source_pixel_buffer;
uint16_t *target_pixel16_buffer = (uint16_t *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
uint64_t pixel = *source_pixel64_buffer;
target_pixel16_buffer[0] = detexPixel64GetR16(pixel);
target_pixel16_buffer[1] = detexPixel64GetG16(pixel);
target_pixel16_buffer[2] = detexPixel64GetB16(pixel);
source_pixel64_buffer++;
target_pixel16_buffer += 3;
}
}
// Conversion between packed float RGB32 and float RGBX32.
static void ConvertPixel96RGB32ToPixel128RGBX32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float *source_pixelf_buffer = (float *)source_pixel_buffer;
float *target_pixelf_buffer = (float *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
float red = source_pixelf_buffer[0];
float green = source_pixelf_buffer[1];
float blue = source_pixelf_buffer[2];
target_pixelf_buffer[0] = red;
target_pixelf_buffer[1] = green;
target_pixelf_buffer[2] = blue;
target_pixelf_buffer[3] = 1.0f;
source_pixelf_buffer += 3;
target_pixelf_buffer += 4;
}
}
static void ConvertPixel128RGBX32ToPixel96RGB32(uint8_t * DETEX_RESTRICT source_pixel_buffer, int nu_pixels, uint8_t * DETEX_RESTRICT target_pixel_buffer)
{
float *source_pixelf_buffer = (float *)source_pixel_buffer;
float *target_pixelf_buffer = (float *)target_pixel_buffer;
for (int i = 0; i < nu_pixels; i++)
{
float red = source_pixelf_buffer[0];
float green = source_pixelf_buffer[1];
float blue = source_pixelf_buffer[2];
target_pixelf_buffer[0] = red;
target_pixelf_buffer[1] = green;
target_pixelf_buffer[2] = blue;
source_pixelf_buffer += 4;
target_pixelf_buffer += 3;
}
}
typedef void (*detexConversionFunc)(uint8_t *source_pixel_buffer, int nu_pixels, uint8_t *target_pixel_buffer);
typedef struct
{
uint32_t source_format;
uint32_t target_format;
detexConversionFunc conversion_func;
} detexConversionType;
// Conversion table. Conversions for which the source pixel size is equal to the
// target pixel size are performed in-place on the source pixel buffer.
detexConversionType detex_conversion_table[] =
{
// No-ops (in-place).
// 0
{ DETEX_PIXEL_FORMAT_RGBX8, DETEX_PIXEL_FORMAT_RGBA8, ConvertNoop },
{ DETEX_PIXEL_FORMAT_RGBA8, DETEX_PIXEL_FORMAT_RGBX8, ConvertNoop },
{ DETEX_PIXEL_FORMAT_BGRX8, DETEX_PIXEL_FORMAT_BGRA8, ConvertNoop },
{ DETEX_PIXEL_FORMAT_BGRA8, DETEX_PIXEL_FORMAT_BGRX8, ConvertNoop },
// Swapping red and blue (in-place).
{ DETEX_PIXEL_FORMAT_RGBX8, DETEX_PIXEL_FORMAT_BGRX8, ConvertPixel32RGBA8ToPixel32BGRA8 },
{ DETEX_PIXEL_FORMAT_BGRX8, DETEX_PIXEL_FORMAT_RGBX8, ConvertPixel32RGBA8ToPixel32BGRA8 },
{ DETEX_PIXEL_FORMAT_RGBA8, DETEX_PIXEL_FORMAT_BGRA8, ConvertPixel32RGBA8ToPixel32BGRA8 },
{ DETEX_PIXEL_FORMAT_BGRA8, DETEX_PIXEL_FORMAT_RGBA8, ConvertPixel32RGBA8ToPixel32BGRA8 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX16, DETEX_PIXEL_FORMAT_FLOAT_BGRX16, ConvertPixel64RGBX16ToPixel64BGRX16 },
{ DETEX_PIXEL_FORMAT_FLOAT_BGRX16, DETEX_PIXEL_FORMAT_FLOAT_RGBX16, ConvertPixel64RGBX16ToPixel64BGRX16 },
// Swapping red and blue (not in-place)
{ DETEX_PIXEL_FORMAT_RGB8, DETEX_PIXEL_FORMAT_BGRX8, ConvertPixel24RGB8ToPixel32BGRX8 },
// Signed integer conversions (in-place).
// 11
{ DETEX_PIXEL_FORMAT_R8, DETEX_PIXEL_FORMAT_SIGNED_R8, ConvertPixel8R8ToPixel8SignedR8 },
{ DETEX_PIXEL_FORMAT_RG8, DETEX_PIXEL_FORMAT_SIGNED_RG8, ConvertPixel16RG8ToPixel16SignedRG8 },
{ DETEX_PIXEL_FORMAT_SIGNED_R8, DETEX_PIXEL_FORMAT_R8, ConvertPixel8SignedR8ToPixel8R8 },
{ DETEX_PIXEL_FORMAT_SIGNED_RG8, DETEX_PIXEL_FORMAT_RG8, ConvertPixel16SignedRG8ToPixel16RG8 },
{ DETEX_PIXEL_FORMAT_R16, DETEX_PIXEL_FORMAT_SIGNED_R16, ConvertPixel16R16ToPixel16SignedR16 },
{ DETEX_PIXEL_FORMAT_RG16, DETEX_PIXEL_FORMAT_SIGNED_RG16, ConvertPixel32RG16ToPixel32SignedRG16 },
{ DETEX_PIXEL_FORMAT_SIGNED_R16, DETEX_PIXEL_FORMAT_R16, ConvertPixel16SignedR16ToPixel16R16 },
{ DETEX_PIXEL_FORMAT_SIGNED_RG16, DETEX_PIXEL_FORMAT_RG16, ConvertPixel32SignedRG16ToPixel32RG16 },
// Reducing the number of components.
{ DETEX_PIXEL_FORMAT_RGBA8, DETEX_PIXEL_FORMAT_R8, ConvertPixel32RGBA8ToPixel8R8 },
{ DETEX_PIXEL_FORMAT_RGBA8, DETEX_PIXEL_FORMAT_RG8, ConvertPixel32RGBA8ToPixel16RG8 },
{ DETEX_PIXEL_FORMAT_RGB8, DETEX_PIXEL_FORMAT_R8, ConvertPixel24RGB8ToPixel8R8 },
{ DETEX_PIXEL_FORMAT_RGB8, DETEX_PIXEL_FORMAT_RG8, ConvertPixel24RGB8ToPixel16RG8 },
// Increasing the number of components.
// 23
{ DETEX_PIXEL_FORMAT_R8, DETEX_PIXEL_FORMAT_RGBX8, ConvertPixel8R8ToPixel32RGBX8 },
{ DETEX_PIXEL_FORMAT_RG8, DETEX_PIXEL_FORMAT_RGBX8, ConvertPixel16RG8ToPixel32RGBX8 },
// Conversion to component of different size.
{ DETEX_PIXEL_FORMAT_R16, DETEX_PIXEL_FORMAT_R8, ConvertPixel16R16ToPixel8R8 },
{ DETEX_PIXEL_FORMAT_RG16, DETEX_PIXEL_FORMAT_RG8, ConvertPixel32RG16ToPixel16RG8 },
{ DETEX_PIXEL_FORMAT_RGB16, DETEX_PIXEL_FORMAT_RGB8, ConvertPixel48RGB16ToPixel24RGB8 },
{ DETEX_PIXEL_FORMAT_RGBX16, DETEX_PIXEL_FORMAT_RGBX8, ConvertPixel64RGBX16ToPixel32RGBX8 },
{ DETEX_PIXEL_FORMAT_RGBA16, DETEX_PIXEL_FORMAT_RGBA8, ConvertPixel64RGBA16ToPixel32RGBA8 },
{ DETEX_PIXEL_FORMAT_R8, DETEX_PIXEL_FORMAT_R16, ConvertPixel8R8ToPixel16R16 },
{ DETEX_PIXEL_FORMAT_RG8, DETEX_PIXEL_FORMAT_RG16, ConvertPixel16RG8ToPixel32RG16 },
{ DETEX_PIXEL_FORMAT_RGB8, DETEX_PIXEL_FORMAT_RGB16, ConvertPixel24RGB8ToPixel48RGB16 },
{ DETEX_PIXEL_FORMAT_RGBX8, DETEX_PIXEL_FORMAT_RGBX16, ConvertPixel32RGBX8ToPixel64RGBX16 },
{ DETEX_PIXEL_FORMAT_RGBA8, DETEX_PIXEL_FORMAT_RGBA16, ConvertPixel32RGBA8ToPixel64RGBA16 },
// Integer to half-float conversion (in-place).
// 35
{ DETEX_PIXEL_FORMAT_R16, DETEX_PIXEL_FORMAT_FLOAT_R16, ConvertPixel16R16ToPixel16FloatR16 },
{ DETEX_PIXEL_FORMAT_RG16, DETEX_PIXEL_FORMAT_FLOAT_RG16, ConvertPixel32RG16ToPixel32FloatRG16 },
{ DETEX_PIXEL_FORMAT_RGB16, DETEX_PIXEL_FORMAT_FLOAT_RGB16, ConvertPixel48RGB16ToPixel48FloatRGB16 },
{ DETEX_PIXEL_FORMAT_RGBX16, DETEX_PIXEL_FORMAT_FLOAT_RGBX16, ConvertPixel64RGBX16ToPixel64FloatRGBX16 },
// Half-float to integer conversion (in-place). Note: Integer format has higher precision.
{ DETEX_PIXEL_FORMAT_FLOAT_R16, DETEX_PIXEL_FORMAT_R16, ConvertPixel16FloatR16ToPixel16R16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RG16, DETEX_PIXEL_FORMAT_RG16, ConvertPixel32FloatRG16ToPixel32RG16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB16, DETEX_PIXEL_FORMAT_RGB16, ConvertPixel48FloatRGB16ToPixel48RGB16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX16, DETEX_PIXEL_FORMAT_RGBX16, ConvertPixel64FloatRGBX16ToPixel64RGBX16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBA16, DETEX_PIXEL_FORMAT_RGBA16, ConvertPixel64FloatRGBA16ToPixel64RGBA16 },
// HDR half-float to integer conversion (in-place).
{ DETEX_PIXEL_FORMAT_FLOAT_R16_HDR, DETEX_PIXEL_FORMAT_R16, ConvertPixel16FloatR16HDRToPixel16R16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RG16_HDR, DETEX_PIXEL_FORMAT_RG16, ConvertPixel32FloatRG16HDRToPixel32RG16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX16_HDR, DETEX_PIXEL_FORMAT_RGBX16, ConvertPixel64FloatRGBX16HDRToPixel64RGBX16 },
// Float to half-float conversion.
// 47
{ DETEX_PIXEL_FORMAT_FLOAT_R32, DETEX_PIXEL_FORMAT_FLOAT_R16, ConvertPixel32FloatR32ToPixel16FloatR16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RG32, DETEX_PIXEL_FORMAT_FLOAT_RG16, ConvertPixel64FloatRG32ToPixel32FloatRG16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB32, DETEX_PIXEL_FORMAT_FLOAT_RGB16, ConvertPixel96FloatRGB32ToPixel48FloatRGB16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX32, DETEX_PIXEL_FORMAT_FLOAT_RGBX16, ConvertPixel128FloatRGBX32ToPixel64FloatRGBX16 },
// Float to 16-bit integer conversion.
{ DETEX_PIXEL_FORMAT_FLOAT_R32, DETEX_PIXEL_FORMAT_R16, ConvertPixel32FloatR32ToPixel16R16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RG32, DETEX_PIXEL_FORMAT_RG16, ConvertPixel64FloatRG32ToPixel32RG16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB32, DETEX_PIXEL_FORMAT_RGB16, ConvertPixel96FloatRGB32ToPixel48RGB16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX32, DETEX_PIXEL_FORMAT_RGBX16, ConvertPixel128FloatRGBX32ToPixel64RGBX16 },
// Half-float to float conversion.
// 55
{ DETEX_PIXEL_FORMAT_FLOAT_R16, DETEX_PIXEL_FORMAT_FLOAT_R32, ConvertPixel16FloatR16ToPixel32FloatR32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RG16, DETEX_PIXEL_FORMAT_FLOAT_RG32, ConvertPixel32FloatRG16ToPixel64FloatRG32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB16, DETEX_PIXEL_FORMAT_FLOAT_RGB32, ConvertPixel48FloatRGB16ToPixel96FloatRGB32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX16, DETEX_PIXEL_FORMAT_FLOAT_RGBX32, ConvertPixel64FloatRGBX16ToPixel128FloatRGBX32 },
// HDR Float to float conversion.
{ DETEX_PIXEL_FORMAT_FLOAT_R32_HDR, DETEX_PIXEL_FORMAT_FLOAT_R32, ConvertPixel32FloatR32HDRToPixel32FloatR32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RG32_HDR, DETEX_PIXEL_FORMAT_FLOAT_RG32, ConvertPixel64FloatRG32HDRToPixel64FloatRG32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB32_HDR, DETEX_PIXEL_FORMAT_FLOAT_RGB32, ConvertPixel96FloatRGB32HDRToPixel96FloatRGB32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX32_HDR, DETEX_PIXEL_FORMAT_FLOAT_RGBX32,
ConvertPixel128FloatRGBX32HDRToPixel128FloatRGBX32 },
// Conversion between packed RGB8 and RGBX8.
// 62
{ DETEX_PIXEL_FORMAT_RGB8, DETEX_PIXEL_FORMAT_RGBX8, ConvertPixel24RGB8ToPixel32RGBX8 },
{ DETEX_PIXEL_FORMAT_RGBX8, DETEX_PIXEL_FORMAT_RGB8, ConvertPixel32RGBX8ToPixel24RGB8 },
// Conversion between packed half-float RGB16 and half-float RGBX16.
{ DETEX_PIXEL_FORMAT_FLOAT_RGB16, DETEX_PIXEL_FORMAT_FLOAT_RGBX16, ConvertPixel48RGB16ToPixel64RGBX16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX16, DETEX_PIXEL_FORMAT_FLOAT_RGB16, ConvertPixel64RGBX16ToPixel48RGB16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB16_HDR, DETEX_PIXEL_FORMAT_FLOAT_RGBX16_HDR, ConvertPixel48RGB16ToPixel64RGBX16 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX16_HDR, DETEX_PIXEL_FORMAT_FLOAT_RGB16_HDR, ConvertPixel64RGBX16ToPixel48RGB16 },
// Conversion between packed float RGB32 and float RGBX32.
{ DETEX_PIXEL_FORMAT_FLOAT_RGB32, DETEX_PIXEL_FORMAT_FLOAT_RGBX32, ConvertPixel96RGB32ToPixel128RGBX32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX32, DETEX_PIXEL_FORMAT_FLOAT_RGB32, ConvertPixel128RGBX32ToPixel96RGB32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGB32_HDR, DETEX_PIXEL_FORMAT_FLOAT_RGBX32_HDR, ConvertPixel96RGB32ToPixel128RGBX32 },
{ DETEX_PIXEL_FORMAT_FLOAT_RGBX32_HDR, DETEX_PIXEL_FORMAT_FLOAT_RGB32_HDR, ConvertPixel128RGBX32ToPixel96RGB32 },
};
#define NU_CONVERSION_TYPES (sizeof(detex_conversion_table) / sizeof(detex_conversion_table[0]))
/** Return the number of components of a pixel format or texture format. */
static DETEX_INLINE_ONLY int detexGetNumberOfComponents(uint32_t pixel_format)
{
return 1 + ((pixel_format & 0x30) >> 4);
}
/** Return the component size in bytes of a pixel format or texture format. */
static DETEX_INLINE_ONLY int detexGetComponentSize(uint32_t pixel_format)
{
return 1 << (pixel_format & 0x3);
}
/** Return the approximate precision in bits of the components of a pixel format. */
static DETEX_INLINE_ONLY uint32_t detexGetComponentPrecision(uint32_t pixel_format)
{
return detexGetComponentSize(pixel_format) * 8 - ((pixel_format & DETEX_PIXEL_FORMAT_FLOAT_BIT) != 0) * 5 * (1 + (detexGetComponentSize(pixel_format) == 4));
}
static uint32_t cached_source_format = -1;
static uint32_t cached_target_format = -1;
static int cached_nu_conversions = -1;
static uint32_t cached_conversion[4];
static void CacheResult(uint32_t source_format, uint32_t target_format, int n, uint32_t *conversion)
{
cached_source_format = source_format;
cached_target_format = target_format;
cached_nu_conversions = n;
for (int i = 0; i < n; i++)
{
cached_conversion[i] = conversion[i];
}
}
/** Match conversion. Returns number of conversion steps, -1 if not succesful.*/
static int detexMatchConversion(uint32_t source_pixel_format, uint32_t target_pixel_format, uint32_t *conversion)
{
// Immediately return if the formats are identical.
if (source_pixel_format == target_pixel_format)
return 0;
#ifdef TRACE_MATCH_CONVERSION
printf("Matching conversion between %s and %s.\n", detexGetTextureFormatText(source_pixel_format),
detexGetTextureFormatText(target_pixel_format));
#endif
// Check whether the conversion has been cached.
if (source_pixel_format == cached_source_format && target_pixel_format == cached_target_format)
{
for (int i = 0; i < cached_nu_conversions; i++)
conversion[i] = cached_conversion[i];
return cached_nu_conversions;
}
// First check direct conversions.
for (int i = 0; i < NU_CONVERSION_TYPES; i++)
{
if (detex_conversion_table[i].target_format == target_pixel_format && detex_conversion_table[i].source_format == source_pixel_format)
{
conversion[0] = i;
CacheResult(source_pixel_format, target_pixel_format, 1, conversion);
return 1;
}
}
// Check two-step conversions.
int min_components = detexGetNumberOfComponents(source_pixel_format);
int n = detexGetNumberOfComponents(target_pixel_format);
if (n < min_components)
min_components = n;
int min_precision = detexGetComponentPrecision(source_pixel_format);
n = detexGetComponentPrecision(target_pixel_format);
if (n < min_precision)
min_precision = n;
for (int i = 0; i < NU_CONVERSION_TYPES; i++)
{
if (detex_conversion_table[i].target_format == target_pixel_format)
{
// Avoid loss of components.
if (detexGetNumberOfComponents(detex_conversion_table[i].source_format) < min_components)
continue;
// Avoid loss of precision.
if (detexGetComponentPrecision(detex_conversion_table[i].source_format) < min_precision)
continue;
conversion[1] = i;
for (int j = 0; j < NU_CONVERSION_TYPES; j++)
{
if (detex_conversion_table[j].target_format == detex_conversion_table[i].source_format && detex_conversion_table[j].source_format == source_pixel_format)
{
conversion[0] = j;
CacheResult(source_pixel_format, target_pixel_format, 2, conversion);
return 2;
}
}
}
}
// Check three-step conversions.
for (int i = 0; i < NU_CONVERSION_TYPES; i++)
{
if (detex_conversion_table[i].source_format == source_pixel_format)
{
// Avoid loss of components.
if (detexGetNumberOfComponents(detex_conversion_table[i].target_format) < min_components)
continue;
// Avoid loss of precision.
if (detexGetComponentPrecision(detex_conversion_table[i].target_format) < min_precision)
continue;
conversion[0] = i;
#ifdef TRACE_MATCH_CONVERSION
printf("Trying conversion ( %d ? ? )\n", conversion[0]);
#endif
// Match the third conversion with the target format.
for (int j = 0; j < NU_CONVERSION_TYPES; j++)
{
if (detex_conversion_table[j].target_format == target_pixel_format)
{
// Avoid loss of components.
if (detexGetNumberOfComponents(detex_conversion_table[j].source_format) < min_components)
continue;
// Avoid loss of precision.
if (detexGetComponentPrecision(detex_conversion_table[j].source_format) < min_precision)
continue;
conversion[2] = j;
#ifdef TRACE_MATCH_CONVERSION
printf("Trying conversion ( %d ? %d )\n", conversion[0], conversion[2]);
#endif
for (int k = 0; k < NU_CONVERSION_TYPES; k++)
if (detex_conversion_table[k].target_format == detex_conversion_table[j].source_format && detex_conversion_table[k].source_format == detex_conversion_table[i].target_format)
{
conversion[1] = k;
CacheResult(source_pixel_format, target_pixel_format, 3, conversion);
return 3;
}
}
}
}
}
// Check four-step conversions.
for (int i = 0; i < NU_CONVERSION_TYPES; i++)
// Match the first conversion with the source format.
if (detex_conversion_table[i].source_format == source_pixel_format)
{
// Avoid loss of components.
if (detexGetNumberOfComponents(detex_conversion_table[i].target_format) < min_components)
continue;
// Avoid loss of precision.
if (detexGetComponentPrecision(detex_conversion_table[i].target_format) < min_precision)
continue;
conversion[0] = i;
#ifdef TRACE_MATCH_CONVERSION
printf("Trying conversion ( %d ? ? ? )\n", conversion[0]);
#endif
// Match the fourth conversion with the target format.
for (int j = 0; j < NU_CONVERSION_TYPES; j++)
{
if (detex_conversion_table[j].target_format == target_pixel_format)
{
// Avoid loss of components.
if (detexGetNumberOfComponents(detex_conversion_table[j].source_format) < min_components)
continue;
// Avoid loss of precision.
if (detexGetComponentPrecision(detex_conversion_table[j].source_format) < min_precision)
continue;
conversion[3] = j;
#ifdef TRACE_MATCH_CONVERSION
printf("Trying conversion ( %d ? ? %d )\n", conversion[0], conversion[3]);
#endif
// Match the second conversion
for (int k = 0; k < NU_CONVERSION_TYPES; k++)
{
if (detex_conversion_table[k].source_format == detex_conversion_table[i].target_format)
{
// Avoid loss of components.
if (detexGetNumberOfComponents(detex_conversion_table[k].target_format) < min_components)
continue;
// Avoid loss of precision.
if (detexGetComponentPrecision(detex_conversion_table[k].target_format) < min_precision)
continue;
conversion[1] = k;
#ifdef TRACE_MATCH_CONVERSION
printf("Trying conversion ( %d %d ? %d )\n", conversion[0], conversion[1], conversion[3]);
#endif
// Match the third conversion.
for (int l = 0; l < NU_CONVERSION_TYPES; l++)\
{
if (detex_conversion_table[l].target_format == detex_conversion_table[j].source_format && detex_conversion_table[l].source_format == detex_conversion_table[k].target_format)
{
conversion[2] = l;
CacheResult(source_pixel_format, target_pixel_format, 4, conversion);
return 4;
}
}
}
}
}
}
}
return -1;
}
/** Temporary pixel buffer management for conversion function. */
#define DETEX_MAX_TEMP_PIXEL_BUFFERS 3
typedef struct
{
uint8_t *pixel_buffer[DETEX_MAX_TEMP_PIXEL_BUFFERS];
uint32_t size[DETEX_MAX_TEMP_PIXEL_BUFFERS];
int nu_buffers;
} TempPixelBufferInfo;
static void InitTemporaryPixelBuffers(TempPixelBufferInfo *info)
{
info->nu_buffers = 0;
}
static uint8_t *AllocateTemporaryPixelBuffer(TempPixelBufferInfo *info, uint32_t size)
{
if (info->nu_buffers == DETEX_MAX_TEMP_PIXEL_BUFFERS)
return NULL;
uint8_t *buffer = (uint8_t *)malloc(size);
info->pixel_buffer[info->nu_buffers] = buffer;
info->nu_buffers++;
return buffer;
}
static void FreeTemporaryPixelBuffers(TempPixelBufferInfo *info)
{
for (int i = 0; i < info->nu_buffers; i++)
{
free(info->pixel_buffer[i]);
}
}
/**
Convert pixels between different formats. Return true if successful.
If target_pixel_format is NULL, the conversion will be attempted in-place, without
allocating any temporary buffer.
*/
bool detexConvertPixels(uint8_t * DETEX_RESTRICT source_pixel_buffer, uint32_t nu_pixels, uint32_t source_pixel_format, uint8_t * DETEX_RESTRICT target_pixel_buffer, uint32_t target_pixel_format)
{
// printf("Converting between %s and %s (0x%08X and 0x%08X).\n", detexGetTextureFormatText(source_pixel_format),
// detexGetTextureFormatText(target_pixel_format), source_pixel_format, target_pixel_format);
if (source_pixel_format == target_pixel_format)
{
if (target_pixel_buffer != NULL)
{
memcpy(target_pixel_buffer, source_pixel_buffer, nu_pixels * detexGetPixelSize(source_pixel_format));
}
return true;
}
uint32_t conversion[4];
int nu_conversions = detexMatchConversion(source_pixel_format, target_pixel_format, conversion);
if (nu_conversions < 0)
{
detexSetErrorMessage("detexConvertPixels: Unable to find conversion path");
return false;
}
// Count in place/non-place steps.
int nu_non_in_place_conversions = 0;
int last_non_in_place_conversion = -1;
int first_non_in_place_conversion = -1;
for (int i = 0; i < nu_conversions; i++)
{
if (detexGetPixelSize(detex_conversion_table[conversion[i]].source_format) != detexGetPixelSize(detex_conversion_table[conversion[i]].target_format))
{
nu_non_in_place_conversions++;
last_non_in_place_conversion = i;
if (first_non_in_place_conversion < 0)
{
first_non_in_place_conversion = i;
}
}
}
if (target_pixel_buffer == NULL && nu_non_in_place_conversions > 0)
{
detexSetErrorMessage("Unable to find in-place conversion path");
return false;
}
// Perform conversions.
TempPixelBufferInfo temp_pixel_buffer_info;
InitTemporaryPixelBuffers(&temp_pixel_buffer_info);
if (first_non_in_place_conversion > 0)
{
// When doing a non-place conversion and the first conversion step is in-place,
// allocate a temporary buffer to avoid corrupting the source buffer.
uint8_t *temp_pixel_buffer = AllocateTemporaryPixelBuffer(&temp_pixel_buffer_info, detexGetPixelSize(source_pixel_format) * nu_pixels);
memcpy(temp_pixel_buffer, source_pixel_buffer, detexGetPixelSize(source_pixel_format) * nu_pixels);
source_pixel_buffer = temp_pixel_buffer;
}
if (target_pixel_buffer != NULL && nu_non_in_place_conversions == 0)
{
// When doing a non-in-place conversion with only in-place conversion steps,
// start by copying the source buffer to the target buffer.
memcpy(target_pixel_buffer, source_pixel_buffer, detexGetPixelSize(source_pixel_format) * nu_pixels);
source_pixel_buffer = target_pixel_buffer;
}
for (int i = 0; i < nu_conversions; i++)
{
if (detexGetPixelSize(detex_conversion_table[conversion[i]].source_format) == detexGetPixelSize(detex_conversion_table[conversion[i]].target_format))
{
// In-place conversion step.
detex_conversion_table[conversion[i]].conversion_func(source_pixel_buffer, nu_pixels, NULL);
}
else
{
if (i == last_non_in_place_conversion)
{
detex_conversion_table[conversion[i]].conversion_func(source_pixel_buffer, nu_pixels, target_pixel_buffer);
source_pixel_buffer = target_pixel_buffer;
}
else
{
uint8_t *temp_pixel_buffer = AllocateTemporaryPixelBuffer(&temp_pixel_buffer_info, nu_pixels * detexGetPixelSize(detex_conversion_table[conversion[i]].target_format));
if (temp_pixel_buffer == NULL)
{
// Error: Too many temporary buffers needed.
detexSetErrorMessage("detexConvertPixels: Too many temporary buffers needed");
FreeTemporaryPixelBuffers(&temp_pixel_buffer_info);
return false;
}
detex_conversion_table[conversion[i]].conversion_func(source_pixel_buffer, nu_pixels, temp_pixel_buffer);
source_pixel_buffer = temp_pixel_buffer;
}
}
}
FreeTemporaryPixelBuffers(&temp_pixel_buffer_info);
return true;
}