Merge remote-tracking branch 'origin/master' into dotnet7

This commit is contained in:
Wojtek Figat
2023-03-01 19:50:22 +01:00
41 changed files with 1383 additions and 114 deletions

View File

@@ -304,10 +304,13 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
const Char* gradlew = TEXT("gradlew.bat");
#else
const Char* gradlew = TEXT("gradlew");
#endif
#if PLATFORM_LINUX
Platform::RunProcess(String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath), data.OriginalOutputPath, Dictionary<String, String>(), true);
#endif
const bool distributionPackage = buildSettings->ForDistribution;
const String gradleCommand = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
const int32 result = Platform::RunProcess(gradleCommand, data.OriginalOutputPath, envVars, true);
const int32 result = Platform::RunProcess(gradleCommand, data.OriginalOutputPath, Dictionary<String, String>(), true);
if (result != 0)
{
data.Error(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result);

View File

@@ -67,10 +67,12 @@ public class Editor : EditorModule
else if (options.Platform.Target == TargetPlatform.Linux)
{
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Linux", "PLATFORM_TOOLS_LINUX");
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID");
}
else if (options.Platform.Target == TargetPlatform.Mac)
{
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Mac", "PLATFORM_TOOLS_MAC");
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID");
}
// Visual Studio integration

View File

@@ -49,6 +49,12 @@ namespace FlaxEditor.GUI.Input
ClearSearchButton.LocalY += 2;
ClearSearchButton.LocalX -= 2;
ClearSearchButton.Clicked += Clear;
ClearSearchButton.HoverBegin += () =>
{
_changeCursor = false;
Cursor = CursorType.Default;
};
ClearSearchButton.HoverEnd += () => _changeCursor = true;
TextChanged += () => ClearSearchButton.Visible = !string.IsNullOrEmpty(Text);
}

View File

@@ -119,6 +119,7 @@ namespace FlaxEditor.Windows
switch (BuildPlatform)
{
case BuildPlatform.LinuxX64:
case BuildPlatform.AndroidARM64:
IsSupported = true;
break;
default:
@@ -129,6 +130,7 @@ namespace FlaxEditor.Windows
switch (BuildPlatform)
{
case BuildPlatform.MacOSx64:
case BuildPlatform.AndroidARM64:
IsSupported = true;
break;
default:

View File

@@ -88,10 +88,12 @@ public sealed class VulkanSdk : Sdk
/// <summary>
/// Tries the get includes folder path (header files). This handles uppercase and lowercase installations for all platforms.
/// </summary>
/// <param name="platform">Target platform hint.</param>
/// <param name="includesFolderPath">The includes folder path.</param>
/// <returns>True if got valid folder, otherwise false.</returns>
public bool TryGetIncludePath(out string includesFolderPath)
public bool TryGetIncludePath(TargetPlatform platform, out string includesFolderPath)
{
includesFolderPath = string.Empty;
if (IsValid)
{
var vulkanSdk = RootPath;
@@ -99,6 +101,11 @@ public sealed class VulkanSdk : Sdk
// Use system-installed headers
if (vulkanSdk.EndsWith("/include") && Directory.Exists(vulkanSdk))
{
if (platform != Flax.Build.Platform.BuildTargetPlatform)
{
Log.Warning(string.Format("Cannot use system-installed VulkanSDK at {0} when building for platform {1}", vulkanSdk, platform));
return false;
}
includesFolderPath = vulkanSdk;
return true;
}
@@ -123,8 +130,6 @@ public sealed class VulkanSdk : Sdk
foreach (var include in includes)
Log.Warning(string.Format("No Vulkan header files in {0}", include));
}
includesFolderPath = string.Empty;
return false;
}
}

View File

@@ -8,7 +8,7 @@
/// <summary>
/// Actor that synchronizes Animated Model skeleton pose with physical bones bodies simulated with physics. Child rigidbodies are used for per-bone simulation - rigidbodies names must match skeleton bone name and should be ordered based on importance in the skeleton tree (parents first).
/// </summary>
API_CLASS() class FLAXENGINE_API Ragdoll : public Actor
API_CLASS(Attributes="ActorToolbox(\"Physics\")") class FLAXENGINE_API Ragdoll : public Actor
{
DECLARE_SCENE_OBJECT(Ragdoll);
API_AUTO_SERIALIZATION();

View File

@@ -775,6 +775,14 @@ Actor* FindActorRecursive(Actor* node, const Tag& tag)
return result;
}
void FindActorsRecursive(Actor* node, const Tag& tag, Array<Actor*>& result)
{
if (node->HasTag(tag))
result.Add(node);
for (Actor* child : node->Children)
FindActorsRecursive(child, tag, result);
}
Actor* Level::FindActor(const Tag& tag, Actor* root)
{
PROFILE_CPU();
@@ -804,12 +812,12 @@ Array<Actor*> Level::FindActors(const Tag& tag, Actor* root)
Array<Actor*> result;
if (root)
{
FindActorRecursive(root, tag);
FindActorsRecursive(root, tag, result);
}
else
{
for (Scene* scene : Scenes)
FindActorRecursive(scene, tag);
FindActorsRecursive(scene, tag, result);
}
return result;
}

View File

@@ -11,7 +11,7 @@ typedef struct AAsset AAsset;
/// <summary>
/// Android platform file object implementation.
/// </summary>
class AndroidFile : public UnixFile
class FLAXENGINE_API AndroidFile : public UnixFile
{
public:

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Thread object for Android platform.
/// </summary>
class AndroidThread : public UnixThread
class FLAXENGINE_API AndroidThread : public UnixThread
{
public:

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Implementation of the window class for Android platform.
/// </summary>
class AndroidWindow : public WindowBase
class FLAXENGINE_API AndroidWindow : public WindowBase
{
friend AndroidPlatform;
public:

View File

@@ -30,7 +30,6 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView&
const StringAsANSI<> initialDirectoryAnsi(*initialDirectory, initialDirectory.Length());
const StringAsANSI<> titleAnsi(*title, title.Length());
const char* initDir = initialDirectory.HasChars() ? initialDirectoryAnsi.Get() : ".";
char cmd[2048];
String xdgCurrentDesktop;
StringBuilder fileFilter;
Array<String> fileFilterEntries;
@@ -39,6 +38,7 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView&
const bool zenitySupported = FileSystem::FileExists(TEXT("/usr/bin/zenity"));
const bool kdialogSupported = FileSystem::FileExists(TEXT("/usr/bin/kdialog"));
char cmd[2048];
if (zenitySupported && (xdgCurrentDesktop != TEXT("KDE") || !kdialogSupported)) // Prefer kdialog when running on KDE
{
for (int32 i = 1; i < fileFilterEntries.Count(); i += 2)
@@ -87,6 +87,51 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView&
return false;
}
bool LinuxFileSystem::ShowBrowseFolderDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& title, String& path)
{
const StringAsANSI<> titleAnsi(*title, title.Length());
String xdgCurrentDesktop;
Platform::GetEnvironmentVariable(TEXT("XDG_CURRENT_DESKTOP"), xdgCurrentDesktop);
// TODO: support initialDirectory
const bool zenitySupported = FileSystem::FileExists(TEXT("/usr/bin/zenity"));
const bool kdialogSupported = FileSystem::FileExists(TEXT("/usr/bin/kdialog"));
char cmd[2048];
if (zenitySupported && (xdgCurrentDesktop != TEXT("KDE") || !kdialogSupported)) // Prefer kdialog when running on KDE
{
sprintf(cmd, "/usr/bin/zenity --modal --file-selection --directory --title=\"%s\" ", titleAnsi.Get());
}
else if (kdialogSupported)
{
sprintf(cmd, "/usr/bin/kdialog --getexistingdirectory --title \"%s\" ", titleAnsi.Get());
}
else
{
LOG(Error, "Missing file picker (install zenity or kdialog).");
return true;
}
FILE* f = popen(cmd, "r");
char buf[2048];
fgets(buf, ARRAY_COUNT(buf), f);
int result = pclose(f);
if (result != 0)
return true;
const char* c = buf;
while (*c)
{
const char* start = c;
while (*c != '\n')
c++;
path = String(start, (int32)(c - start));
if (path.HasChars())
break;
c++;
}
return false;
}
bool LinuxFileSystem::ShowFileExplorer(const StringView& path)
{
const StringAsANSI<> pathAnsi(*path, path.Length());

View File

@@ -15,6 +15,7 @@ public:
// [FileSystemBase]
static bool ShowOpenFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, Array<String, HeapAllocation>& filenames);
static bool ShowBrowseFolderDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& title, String& path);
static bool ShowFileExplorer(const StringView& path);
static bool CreateDirectory(const StringView& path);
static bool DeleteDirectory(const String& path, bool deleteContents = true);

View File

@@ -9,7 +9,7 @@
#define LINUXINPUT_MAX_GAMEPAD_EVENTS_PER_FRAME 32
#define TRIGGER_THRESHOLD 1000
class LinuxGamepad : public Gamepad
class FLAXENGINE_API LinuxGamepad : public Gamepad
{
public:
int fd;

View File

@@ -2759,6 +2759,30 @@ Window* LinuxPlatform::CreateWindow(const CreateWindowSettings& settings)
return New<LinuxWindow>(settings);
}
extern char **environ;
void LinuxPlatform::GetEnvironmentVariables(Dictionary<String, String, HeapAllocation>& result)
{
char **s = environ;
for (; *s; s++)
{
char* var = *s;
int32 split = -1;
for (int32 i = 0; var[i]; i++)
{
if (var[i] == '=')
{
split = i;
break;
}
}
if (split == -1)
result[String(var)] = String::Empty;
else
result[String(var, split)] = String(var + split + 1);
}
}
bool LinuxPlatform::GetEnvironmentVariable(const String& name, String& value)
{
char* env = getenv(StringAsANSI<>(*name).Get());

View File

@@ -131,6 +131,7 @@ public:
static String GetWorkingDirectory();
static bool SetWorkingDirectory(const String& path);
static Window* CreateWindow(const CreateWindowSettings& settings);
static void GetEnvironmentVariables(Dictionary<String, String, HeapAllocation>& result);
static bool GetEnvironmentVariable(const String& name, String& value);
static bool SetEnvironmentVariable(const String& name, const String& value);
static int32 StartProcess(const StringView& filename, const StringView& args, const StringView& workingDir, bool hiddenWindow = false, bool waitForEnd = false);

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Thread object for Linux platform.
/// </summary>
class LinuxThread : public UnixThread
class FLAXENGINE_API LinuxThread : public UnixThread
{
public:

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Implementation of the window class for Linux platform.
/// </summary>
class LinuxWindow : public WindowBase
class FLAXENGINE_API LinuxWindow : public WindowBase
{
friend LinuxPlatform;
public:

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Thread object for Mac platform.
/// </summary>
class MacThread : public UnixThread
class FLAXENGINE_API MacThread : public UnixThread
{
public:

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Implementation of the window class for Mac platform.
/// </summary>
class MacWindow : public WindowBase
class FLAXENGINE_API MacWindow : public WindowBase
{
private:

View File

@@ -14,7 +14,7 @@
/// <summary>
/// Implementation of the window class for Universal Windows Platform (UWP)
/// </summary>
class UWPWindow : public WindowBase
class FLAXENGINE_API UWPWindow : public WindowBase
{
friend UWPPlatform;

View File

@@ -9,7 +9,7 @@
/// <summary>
/// Unix platform file object implementation.
/// </summary>
class UnixFile : public FileBase
class FLAXENGINE_API UnixFile : public FileBase
{
protected:

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Thread object for Unix platform.
/// </summary>
class UnixThread : public ThreadBase
class FLAXENGINE_API UnixThread : public ThreadBase
{
protected:

View File

@@ -9,7 +9,7 @@
/// <summary>
/// Win32 platform file object implementation
/// </summary>
class Win32File : public FileBase
class FLAXENGINE_API Win32File : public FileBase
{
private:

View File

@@ -9,7 +9,7 @@
/// <summary>
/// Thread object for Win32 platform.
/// </summary>
class Win32Thread : public ThreadBase
class FLAXENGINE_API Win32Thread : public ThreadBase
{
private:

View File

@@ -11,7 +11,7 @@
/// <summary>
/// Implementation of the window class for Windows platform
/// </summary>
class WindowsWindow : public WindowBase
class FLAXENGINE_API WindowsWindow : public WindowBase
#if USE_EDITOR
, public Windows::IDropTarget
#endif

View File

@@ -149,6 +149,7 @@ public:
GlobalSurfaceAtlasTile* AtlasTiles = nullptr; // TODO: optimize with a single allocation for atlas tiles
Dictionary<void*, GlobalSurfaceAtlasObject> Objects;
Dictionary<Guid, GlobalSurfaceAtlasLight> Lights;
SamplesBuffer<uint32, 30> CulledObjectsUsageHistory;
// Cached data to be reused during RasterizeActor
uint64 CurrentFrame;
@@ -167,6 +168,7 @@ public:
FORCE_INLINE void ClearObjects()
{
CulledObjectsCounterIndex = -1;
CulledObjectsUsageHistory.Clear();
LastFrameAtlasDefragmentation = Engine::FrameCount;
SAFE_DELETE(AtlasTiles);
Objects.Clear();
@@ -717,8 +719,15 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
}
}
// Calculate optimal capacity for the objects buffer
objectsBufferCapacity *= sizeof(uint32) * 2; // Convert to bytes and add safe margin
objectsBufferCapacity = Math::Clamp(Math::AlignUp<uint32>(objectsBufferCapacity, 4096u), 32u * 1024u, 1024u * 1024u); // Align up to 4kB, clamp 32kB - 1MB
surfaceAtlasData.CulledObjectsUsageHistory.Add(objectsBufferCapacity); // Record history
objectsBufferCapacity = surfaceAtlasData.CulledObjectsUsageHistory.Maximum(); // Use biggest value from history
if (surfaceAtlasData.CulledObjectsUsageHistory.Count() == surfaceAtlasData.CulledObjectsUsageHistory.Capacity())
notReady = false; // Always ready when rendering for some time
// Allocate buffer for culled objects (estimated size)
objectsBufferCapacity = Math::Min(Math::AlignUp<uint32>(objectsBufferCapacity * sizeof(uint32), 4096u), (uint32)MAX_int32);
if (!surfaceAtlasData.CulledObjectsBuffer)
surfaceAtlasData.CulledObjectsBuffer = GPUDevice::Instance->CreateBuffer(TEXT("GlobalSurfaceAtlas.CulledObjectsBuffer"));
if (surfaceAtlasData.CulledObjectsBuffer->GetSize() < objectsBufferCapacity)
@@ -739,7 +748,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
data.ViewWorldPos = renderContext.View.Position;
data.ViewNearPlane = renderContext.View.Near;
data.ViewFarPlane = renderContext.View.Far;
data.CulledObjectsCapacity = objectsBufferCapacity;
data.CulledObjectsCapacity = objectsBufferCapacity / sizeof(uint32); // Capacity in items, not bytes
data.GlobalSurfaceAtlas = result.Constants;
context->UpdateCB(_cb0, &data);
context->BindCB(0, _cb0);

View File

@@ -460,6 +460,21 @@ TextureTool::PixelFormatSampler PixelFormatSamplers[] =
*(Color32*)ptr = Color32(srgb);
},
},
{
PixelFormat::R8G8_UNorm,
sizeof(uint16),
[](const void* ptr)
{
const uint8* rg = (const uint8*)ptr;
return Color((float)rg[0] / MAX_uint8, (float)rg[1] / MAX_uint8, 0, 1);
},
[](const void* ptr, const Color& color)
{
uint8* rg = (uint8*)ptr;
rg[0] = (uint8)(color.R * MAX_uint8);
rg[1] = (uint8)(color.G * MAX_uint8);
},
},
{
PixelFormat::R16G16_Float,
sizeof(Half2),

View File

@@ -63,7 +63,21 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
{
if (!PixelFormatExtensions::IsCompressed(textureData.Format))
return &textureData;
decompressed.Format = PixelFormatExtensions::IsSRGB(textureData.Format) ? PixelFormat::R8G8B8A8_UNorm_sRGB : PixelFormat::R8G8B8A8_UNorm;
const bool srgb = PixelFormatExtensions::IsSRGB(textureData.Format);
switch (textureData.Format)
{
case PixelFormat::BC4_UNorm:
case PixelFormat::BC4_SNorm:
decompressed.Format = PixelFormat::R8_UNorm;
break;
case PixelFormat::BC5_UNorm:
case PixelFormat::BC5_SNorm:
decompressed.Format = PixelFormat::R8G8_UNorm;
break;
default:
decompressed.Format = srgb ? PixelFormat::R8G8B8A8_UNorm_sRGB : PixelFormat::R8G8B8A8_UNorm;
break;
}
decompressed.Width = textureData.Width;
decompressed.Height = textureData.Height;
decompressed.Depth = textureData.Depth;
@@ -71,7 +85,7 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
decompressed.Items[0].Mips.Resize(1);
TextureMipData* decompressedData = decompressed.GetData(0, 0);
decompressedData->RowPitch = textureData.Width * sizeof(Color32);
decompressedData->RowPitch = textureData.Width * PixelFormatExtensions::SizeInBytes(decompressed.Format);
decompressedData->Lines = textureData.Height;
decompressedData->DepthPitch = decompressedData->RowPitch * decompressedData->Lines;
decompressedData->Data.Allocate(decompressedData->DepthPitch);
@@ -83,72 +97,74 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
const TextureMipData* blocksData = textureData.GetData(0, 0);
const byte* blocksBytes = blocksData->Data.Get();
typedef bool (*detexDecompressBlockFuncType)(const uint8_t* bitstring, uint32_t mode_mask, uint32_t flags, uint8_t* pixel_buffer);
detexDecompressBlockFuncType detexDecompressBlockFunc;
int32 pixelSize, blockSize;
switch (textureData.Format)
{
case PixelFormat::BC1_UNorm:
case PixelFormat::BC1_UNorm_sRGB:
{
for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++)
{
for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++)
{
const byte* block = blocksBytes + yBlock * blocksData->RowPitch + xBlock * 8;
detexDecompressBlockBC1(block, 0, 0, (byte*)&colors);
for (int32 y = 0; y < 4; y++)
{
for (int32 x = 0; x < 4; x++)
{
*((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x];
}
}
}
}
detexDecompressBlockFunc = detexDecompressBlockBC1;
pixelSize = 4;
blockSize = 8;
break;
}
case PixelFormat::BC2_UNorm:
case PixelFormat::BC2_UNorm_sRGB:
{
for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++)
{
for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++)
{
const byte* block = blocksBytes + yBlock * blocksData->RowPitch + xBlock * 16;
detexDecompressBlockBC2(block, 0, 0, (byte*)&colors);
for (int32 y = 0; y < 4; y++)
{
for (int32 x = 0; x < 4; x++)
{
*((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x];
}
}
}
}
detexDecompressBlockFunc = detexDecompressBlockBC2;
pixelSize = 4;
blockSize = 16;
break;
}
case PixelFormat::BC3_UNorm:
case PixelFormat::BC3_UNorm_sRGB:
{
for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++)
{
for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++)
{
const byte* block = blocksBytes + yBlock * blocksData->RowPitch + xBlock * 16;
detexDecompressBlockBC3(block, 0, 0, (byte*)&colors);
for (int32 y = 0; y < 4; y++)
{
for (int32 x = 0; x < 4; x++)
{
*((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x];
}
}
}
}
detexDecompressBlockFunc = detexDecompressBlockBC3;
pixelSize = 4;
blockSize = 16;
break;
case PixelFormat::BC4_UNorm:
detexDecompressBlockFunc = detexDecompressBlockRGTC1;
pixelSize = 1;
blockSize = 8;
break;
case PixelFormat::BC5_UNorm:
detexDecompressBlockFunc = detexDecompressBlockRGTC2;
pixelSize = 2;
blockSize = 16;
break;
case PixelFormat::BC7_UNorm:
case PixelFormat::BC7_UNorm_sRGB:
detexDecompressBlockFunc = detexDecompressBlockBPTC;
pixelSize = 4;
blockSize = 16;
break;
}
default:
LOG(Warning, "Texture data format {0} is not supported by stb library.", (int32)textureData.Format);
LOG(Warning, "Texture data format {0} is not supported by detex library.", (int32)textureData.Format);
return nullptr;
}
uint8 blockBuffer[DETEX_MAX_BLOCK_SIZE];
for (int32 y = 0; y < blocksHeight; y++)
{
int32 rows;
if (y * 4 + 3 >= textureData.Height)
rows = textureData.Height - y * 4;
else
rows = 4;
for (int32 x = 0; x < blocksWidth; x++)
{
const byte* block = blocksBytes + y * blocksData->RowPitch + x * blockSize;
if (!detexDecompressBlockFunc(block, DETEX_MODE_MASK_ALL, 0, blockBuffer))
memset(blockBuffer, 0, DETEX_MAX_BLOCK_SIZE);
uint8* pixels = decompressedBytes + y * 4 * textureData.Width * pixelSize + x * 4 * pixelSize;
int32 columns;
if (x * 4 + 3 >= textureData.Width)
columns = textureData.Width - x * 4;
else
columns = 4;
for (int32 row = 0; row < rows; row++)
memcpy(pixels + row * textureData.Width * pixelSize, blockBuffer + row * 4 * pixelSize, columns * pixelSize);
}
}
return &decompressed;
}

View File

@@ -114,6 +114,11 @@ namespace FlaxEngine.GUI
/// </summary>
protected float _animateTime;
/// <summary>
/// If the cursor should change to an IBeam
/// </summary>
protected bool _changeCursor = true;
/// <summary>
/// Event fired when text gets changed
/// </summary>
@@ -1131,7 +1136,7 @@ namespace FlaxEngine.GUI
/// <inheritdoc />
public override void OnMouseEnter(Float2 location)
{
if (_isEditing)
if (_isEditing && _changeCursor)
Cursor = CursorType.IBeam;
base.OnMouseEnter(location);
@@ -1159,8 +1164,8 @@ namespace FlaxEngine.GUI
// Modify selection end
SetSelection(_selectionStart, currentIndex);
}
if (Cursor == CursorType.Default && _isEditing)
if (Cursor == CursorType.Default && _isEditing && _changeCursor)
Cursor = CursorType.IBeam;
}
@@ -1191,7 +1196,7 @@ namespace FlaxEngine.GUI
SetSelection(hitPos);
}
if (Cursor == CursorType.Default)
if (Cursor == CursorType.Default && _changeCursor)
Cursor = CursorType.IBeam;
return true;
@@ -1200,6 +1205,8 @@ namespace FlaxEngine.GUI
if (button == MouseButton.Left && !IsFocused)
{
Focus();
if (_changeCursor)
Cursor = CursorType.IBeam;
return true;
}

45
Source/ThirdParty/detex/bits.cpp vendored Normal file
View File

@@ -0,0 +1,45 @@
/*
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 "detex.h"
#include "bits.h"
uint32_t detexBlock128ExtractBits(detexBlock128 *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;
}

62
Source/ThirdParty/detex/bits.h vendored Normal file
View File

@@ -0,0 +1,62 @@
/*
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.
*/
/* Data structure used to extract bits from 128-bit bitstring. */
typedef struct {
uint64_t data0;
uint64_t data1;
int index;
} detexBlock128;
uint32_t detexBlock128ExtractBits(detexBlock128 *block, int nu_bits);
/* 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;
}
/* Clear bit0 to bit1 of 64-bit bitstring. */
static DETEX_INLINE_ONLY uint64_t detexClearBits64(uint64_t data, int bit0, int bit1) {
uint64_t mask = ~(((uint64_t)1 << (bit1 + 1)) - 1);
mask |= ((uint64_t)1 << bit0) - 1;
return data & mask;
}
/* Set bit0 to bit1 of 64-bit bitstring. */
static DETEX_INLINE_ONLY uint64_t detexSetBits64(uint64_t data, int bit0, int bit1, uint64_t val) {
uint64_t d = detexClearBits64(data, bit0, bit1);
d |= val << bit0;
return d;
}

203
Source/ThirdParty/detex/bptc-tables.cpp vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
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 "detex.h"
#include "bits.h"
#include "bptc-tables.h"
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
};

29
Source/ThirdParty/detex/bptc-tables.h vendored Normal file
View File

@@ -0,0 +1,29 @@
/*
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.
*/
extern const uint8_t detex_bptc_table_P2[64 * 16];
extern const uint8_t detex_bptc_table_P3[64 * 16];
extern const uint8_t detex_bptc_table_anchor_index_second_subset[64];
extern const uint8_t detex_bptc_table_anchor_index_second_subset_of_three[64];
extern const uint8_t detex_bptc_table_anchor_index_third_subset[64];
extern const uint16_t detex_bptc_table_aWeight2[4];
extern const uint16_t detex_bptc_table_aWeight3[8];
extern const uint16_t detex_bptc_table_aWeight4[16];

View File

@@ -0,0 +1,623 @@
/*
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 "detex.h"
#include "bits.h"
#include "bptc-tables.h"
// BPTC mode layout:
//
// Number of subsets = { 3, 2, 3, 2, 1, 1, 1, 2 };
// Partition bits = { 4, 6, 6, 6, 0, 0, 0, 6 };
// Rotation bits = { 0, 0, 0, 0, 2, 2, 0, 0 };
// Mode 4 has one index selection bit.
//
// #subsets color alpha before color index after color index after After Index
// alpha pbits bits (*)
// Mode 0 3 4 0 1 + 4 = 5 5 + 6 * 3 * 4 = 77 77 + 6 = 83 + 48 - 3 = 128
// Mode 1 2 6 0 2 + 6 = 8 8 + 4 * 3 * 6 = 80 80 + 2 = 82 + 48 - 2 = 128
// Mode 2 3 5 0 3 + 6 = 9 9 + 6 * 3 * 5 = 99 99 99 + 32 - 3 = 128
// Mode 3 2 7 0 4 + 6 = 10 10 + 4 * 3 * 7 = 94 94 + 4 = 98 + 32 - 2 = 128
// Mode 4 1 5 6 5 + 2 + 1 = 8 8 + 2 * 3 * 5 = 38 37 + 2 * 6 = 50 50 + 80 - 2 = 128
// Mode 5 1 7 8 6 + 2 = 8 8 + 2 * 3 * 7 = 50 50 + 2 * 8 = 66 66 + 64 - 2 = 128
// Mode 6 1 7 7 7 7 + 2 * 3 * 7 = 49 49 + 2 * 7 = 63 + 2 = 65 + 64 - 1 = 128
// Mode 7 2 5 5 8 + 6 = 14 14 + 4 * 3 * 5 = 74 74 + 4 * 5 = 94 + 4 = 98 + 32 - 2 = 128
//
// (*) For formats without alpha, the number of index bits is reduced by #subsets anchor bits.
// For formats with alpha, the number of index bits is reduced by 2 * #subsets by the anchor bits.
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];
}
static const int8_t components_in_qword0_table[8] = { 2, -1, 1, 1, 3, 3, 3, 2 };
/* Extract endpoint colors. */
static void ExtractEndpoints(int mode, int nu_subsets, detexBlock128 * 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 mask = (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 & mask;
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, detexBlock128 * 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;
}
}
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 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];
}
// Functions to extract parameters. */
static int ExtractMode(detexBlock128 *block) {
for (int i = 0; i < 8; i++)
if (block->data0 & ((uint64_t)1 << i)) {
block->index = i + 1;
return i;
}
// Illegal.
return - 1;
}
static DETEX_INLINE_ONLY int ExtractPartitionSetID(detexBlock128 *block, int mode) {
return detexBlock128ExtractBits(block, GetNumberOfPartitionBits(mode));
}
static DETEX_INLINE_ONLY int GetPartitionIndex(int nu_subsets, int partition_set_id, int i) {
if (nu_subsets == 1)
return 0;
if (nu_subsets == 2)
return detex_bptc_table_P2[partition_set_id * 16 + i];
return detex_bptc_table_P3[partition_set_id * 16 + i];
}
static DETEX_INLINE_ONLY int ExtractRotationBits(detexBlock128 *block, int mode) {
return detexBlock128ExtractBits(block, GetNumberOfRotationBits(mode));
}
static DETEX_INLINE_ONLY int GetAnchorIndex(int partition_set_id, int partition, int nu_subsets) {
if (partition == 0)
return 0;
if (nu_subsets == 2)
return detex_bptc_table_anchor_index_second_subset[partition_set_id];
if (partition == 1)
return detex_bptc_table_anchor_index_second_subset_of_three[partition_set_id];
return detex_bptc_table_anchor_index_third_subset[partition_set_id];
}
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 };
/* Decompress a 128-bit 4x4 pixel texture block compressed using BPTC mode 1. */
static bool DecompressBlockBPTCMode1(detexBlock128 * 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) {
detexBlock128 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;
}
#if 0
/* Modify compressed block to use specific colors. For later use. */
static void SetBlockColors(uint8_t * DETEX_RESTRICT bitstring, uint32_t flags,
uint32_t * DETEX_RESTRICT colors) {
if ((flags & TWO_COLORS) == 0)
return;
uint64_t data0 = *(uint64_t *)&bitstring[0];
uint64_t data1 = *(uint64_t *)&bitstring[8];
if ((flags & BPTC_MODE_ALLOWED_ALL) == (1 << 3)) {
// Mode 3, 7 color bits.
// Color bits at index: 10
// Color bits end before index: 10 + 4 * 3 * 7 = 94
uint32_t r0 = detexPixel32GetR8(colors[0]);
uint32_t g0 = detexPixel32GetG8(colors[0]);
uint32_t b0 = detexPixel32GetB8(colors[0]);
uint32_t r1 = detexPixel32GetR8(colors[1]);
uint32_t g1 = detexPixel32GetG8(colors[1]);
uint32_t b1 = detexPixel32GetB8(colors[1]);
data0 = detexSetBits64(data0, 10, 16, r0 >> 1);
data0 = detexSetBits64(data0, 17, 23, r0 >> 1);
data0 = detexSetBits64(data0, 24, 30, r1 >> 1);
data0 = detexSetBits64(data0, 31, 37, r1 >> 1);
data0 = detexSetBits64(data0, 38, 44, g0 >> 1);
data0 = detexSetBits64(data0, 45, 51, g0 >> 1);
data0 = detexSetBits64(data0, 52, 58, g1 >> 1);
data0 = detexSetBits64(data0, 59, 63, (g1 >> 1) & 0x1F);
data1 = detexSetBits64(data1, 0, 1, ((g1 >> 1) & 0x60) >> 5);
data1 = detexSetBits64(data1, 2, 8, b0 >> 1);
data1 = detexSetBits64(data1, 9, 15, b0 >> 1);
data1 = detexSetBits64(data1, 16, 22, b1 >> 1);
data1 = detexSetBits64(data1, 23, 29, b1 >> 1);
*(uint64_t *)&bitstring[0] = data0;
*(uint64_t *)&bitstring[8] = data1;
// printf("bptc_set_block_colors: Colors set for mode 3.\n");
}
else if ((flags & BPTC_MODE_ALLOWED_ALL) == (1 << 5)) {
// Mode 5, 7 color bits, 8 alpha bits.
// Color bits at index: 6 + 2 = 8
// Alpha bits at index: 8 + 2 * 3 * 7 = 50
// Alpha bits end before index: 50 + 2 * 8 = 66
uint32_t r0 = detexPixel32GetR8(colors[0]);
uint32_t g0 = detexPixel32GetG8(colors[0]);
uint32_t b0 = detexPixel32GetB8(colors[0]);
uint32_t r1 = detexPixel32GetR8(colors[1]);
uint32_t g1 = detexPixel32GetG8(colors[1]);
uint32_t b1 = detexPixel32GetB8(colors[1]);
data0 = detexSetBits64(data0, 8, 14, r0 >> 1);
data0 = detexSetBits64(data0, 15, 21, r1 >> 1);
data0 = detexSetBits64(data0, 22, 28, g0 >> 1);
data0 = detexSetBits64(data0, 29, 35, g0 >> 1);
data0 = detexSetBits64(data0, 36, 42, b0 >> 1);
data0 = detexSetBits64(data0, 43, 49, b1 >> 1);
if (flags & (MODES_ALLOWED_PUNCHTHROUGH_ONLY)) {
data0 = detexSetBits64(data0, 50, 57, 0x00);
data0 = detexSetBits64(data0, 58, 63, 0x3F);
data1 = detexSetBits64(data1, 0, 1, 0x3);
}
*(uint64_t *)&bitstring[0] = data0;
*(uint64_t *)&bitstring[8] = data1;
// printf("bptc_set_block_colors: Colors set for mode 5.\n");
}
else if ((flags & BPTC_MODE_ALLOWED_ALL) == (1 << 6)) {
// Mode 5, 7 color bits, 7 alpha bits.
// Color bits at index 7.
// Alpha bits at index: 7 + 2 * 3 * 7 = 49
// Alpha bits end before index: 49 + 2 * 7 = 63
uint32_t r0 = detexPixel32GetR8(colors[0]);
uint32_t g0 = detexPixel32GetG8(colors[0]);
uint32_t b0 = detexPixel32GetB8(colors[0]);
uint32_t r1 = detexPixel32GetR8(colors[1]);
uint32_t g1 = detexPixel32GetG8(colors[1]);
uint32_t b1 = detexPixel32GetB8(colors[1]);
data0 = detexSetBits64(data0, 7, 13, r0 >> 1);
data0 = detexSetBits64(data0, 14, 20, r1 >> 1);
data0 = detexSetBits64(data0, 21, 27, g0 >> 1);
data0 = detexSetBits64(data0, 28, 34, g1 >> 1);
data0 = detexSetBits64(data0, 35, 41, b0 >> 1);
data0 = detexSetBits64(data0, 42, 48, b1 >> 1);
if (flags & (MODES_ALLOWED_PUNCHTHROUGH_ONLY)) {
data0 = detexSetBits64(data0, 49, 55, 0x00);
data0 = detexSetBits64(data0, 56, 62, 0x7F);
}
*(uint64_t *)&bitstring[0] = data0;
// printf("bptc_set_block_colors: Colors set for mode 6.\n");
}
}
#endif
/* Return the internal mode of the BPTC block. */
uint32_t detexGetModeBPTC(const uint8_t *bitstring) {
detexBlock128 block;
block.data0 = *(uint64_t *)&bitstring[0];
block.data1 = *(uint64_t *)&bitstring[8];
block.index = 0;
int mode = ExtractMode(&block);
return mode;
}
void detexSetModeBPTC(uint8_t *bitstring, uint32_t mode, uint32_t flags,
uint32_t *colors) {
// Mode 0 starts with 1
// Mode 1 starts with 01
// ...
// Mode 7 starts with 00000001
int bit = 0x1 << mode;
bitstring[0] &= ~(bit - 1);
bitstring[0] |= bit;
return;
}

View File

@@ -0,0 +1,148 @@
/*
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 "detex.h"
// 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);
}

View File

@@ -34,7 +34,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define DETEX_HELPER_SHARED_IMPORT __declspec(dllimport)
#define DETEX_HELPER_SHARED_EXPORT __declspec(dllexport)
#define DETEX_HELPER_SHARED_LOCAL
#define DETEX_INLINE_ONLY __forceinline
#else
#if __GNUC__ >= 4
#define DETEX_HELPER_SHARED_IMPORT __attribute__ ((visibility ("default")))
@@ -45,7 +44,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define DETEX_HELPER_SHARED_EXPORT
#define DETEX_HELPER_SHARED_LOCAL
#endif
#define DETEX_INLINE_ONLY __attribute__((always_inline)) inline
#endif
/* Now we use the generic helper definitions above to define DETEX_API and DETEX_LOCAL. */
@@ -74,6 +72,7 @@ __BEGIN_DECLS
#include <stdint.h>
#include <stdbool.h>
#define DETEX_INLINE_ONLY __attribute__((always_inline)) inline
#define DETEX_RESTRICT __restrict
/* Maximum uncompressed block size in bytes. */

View File

@@ -48,7 +48,7 @@ public class volk : ThirdPartyModule
}
string includesFolderPath;
if (VulkanSdk.Instance.TryGetIncludePath(out includesFolderPath))
if (VulkanSdk.Instance.TryGetIncludePath(options.Platform.Target, out includesFolderPath))
{
options.PublicIncludePaths.Add(includesFolderPath);
}

View File

@@ -248,7 +248,7 @@ namespace Flax.Build.Bindings
public static void GenerateCppVirtualWrapperCallBaseMethod(BuildData buildData, StringBuilder contents, VirtualClassInfo classInfo, FunctionInfo functionInfo, string scriptVTableBase, string scriptVTableOffset)
{
contents.AppendLine(" // Prevent stack overflow by calling native base method");
if (buildData.Toolchain.Compiler == TargetCompiler.Clang)
if (buildData.Toolchain?.Compiler == TargetCompiler.Clang)
{
// Clang compiler
// TODO: secure VTableFunctionInjector with mutex (even at cost of performance)
@@ -1616,7 +1616,7 @@ namespace Flax.Build.Bindings
}
var t = functionInfo.IsConst ? " const" : string.Empty;
contents.AppendLine($" typedef {functionInfo.ReturnType} ({classInfo.NativeName}::*{functionInfo.UniqueName}_Signature)({thunkParams}){t};");
if (buildData.Toolchain.Compiler != TargetCompiler.Clang)
if (buildData.Toolchain?.Compiler != TargetCompiler.Clang)
{
// MSVC or other compiler
contents.AppendLine($" typedef {functionInfo.ReturnType} ({classInfo.NativeName}Internal::*{functionInfo.UniqueName}_Internal_Signature)({thunkParams}){t};");
@@ -1689,7 +1689,7 @@ namespace Flax.Build.Bindings
}
// Native interfaces override in managed code requires vtables hacking which requires additional inject on Clang-platforms
if (buildData.Toolchain.Compiler == TargetCompiler.Clang && classInfo.IsClass && classInfo.Interfaces != null)
if (buildData.Toolchain?.Compiler == TargetCompiler.Clang && classInfo.IsClass && classInfo.Interfaces != null)
{
// Override vtable entries of interface methods (for each virtual function in each interface)
foreach (var interfaceInfo in classInfo.Interfaces)
@@ -2559,7 +2559,7 @@ namespace Flax.Build.Bindings
contents.AppendLine();
// Native interfaces override in managed code requires vtables hacking which requires additional inject on Clang-platforms
if (buildData.Toolchain.Compiler == TargetCompiler.Clang)
if (buildData.Toolchain?.Compiler == TargetCompiler.Clang)
{
// Generate functions that inject script wrappers into vtable entry
foreach (var functionInfo in interfaceInfo.Functions)

View File

@@ -28,7 +28,7 @@ namespace Flax.Build.Platforms
SystemIncludePaths.Add(includePath);
else
Log.Error($"Missing toolset header files location {includePath}");
var cppIncludePath = Path.Combine(includePath, "c++", ClangVersion.ToString());
var cppIncludePath = Path.Combine(includePath, "c++", LibStdCppVersion);
if (Directory.Exists(cppIncludePath))
SystemIncludePaths.Add(cppIncludePath);
else

View File

@@ -72,6 +72,11 @@ namespace Flax.Build.Platforms
/// </summary>
protected Version ClangVersion;
/// <summary>
/// The C++ standard library version.
/// </summary>
protected string LibStdCppVersion;
/// <summary>
/// Initializes a new instance of the <see cref="UnixToolchain"/> class.
/// </summary>
@@ -136,6 +141,7 @@ namespace Flax.Build.Platforms
// Determinate compiler version
ClangVersion = GetClangVersion(ClangPath);
LibStdCppVersion = GetLibStdCppVersion(ClangPath) ?? ClangVersion.ToString();
// Check version
if (ClangVersion.Major < 6)
@@ -154,6 +160,31 @@ namespace Flax.Build.Platforms
{
if (!File.Exists(path))
throw new Exception(string.Format("Missing Clang ({0})", path));
// Parse the version
string output = Utilities.ReadProcessOutput(path, "--version -dumpversion");
Regex versionPattern = new Regex("\\d+(\\.\\d+)+");
Match versionMatch = versionPattern.Match(output);
if (versionMatch.Success)
{
string[] parts = versionMatch.Value.Split('.');
int major = 0, minor = 0, patch = 0;
if (parts.Length >= 1)
major = Convert.ToInt32(parts[0]);
if (parts.Length >= 2)
minor = Convert.ToInt32(parts[1]);
if (parts.Length >= 3)
patch = Convert.ToInt32(parts[2]);
return new Version(major, minor, patch);
}
throw new Exception(string.Format("Failed to get Clang version ({0})", path));
}
public static string GetLibStdCppVersion(string path)
{
if (!File.Exists(path))
return null;
using (var process = new Process())
{
process.StartInfo.UseShellExecute = false;
@@ -161,33 +192,18 @@ namespace Flax.Build.Platforms
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = path;
process.StartInfo.Arguments = "--version";
process.StartInfo.Arguments = "-v";
process.Start();
process.WaitForExit();
if (process.ExitCode == 0)
{
// Parse the version
string data = process.StandardOutput.ReadLine();
Regex versionPattern = new Regex("version \\d+(\\.\\d+)+");
Match versionMatch = versionPattern.Match(data);
if (versionMatch.Value.StartsWith("version "))
{
var versionString = versionMatch.Value.Replace("version ", "");
string[] parts = versionString.Split('.');
int major = 0, minor = 0, patch = 0;
if (parts.Length >= 1)
major = Convert.ToInt32(parts[0]);
if (parts.Length >= 2)
minor = Convert.ToInt32(parts[1]);
if (parts.Length >= 3)
patch = Convert.ToInt32(parts[2]);
return new Version(major, minor, patch);
}
}
throw new Exception(string.Format("Failed to get Clang version ({0})", path));
Regex versionPattern = new Regex("Selected GCC installation: .*\\/(\\d+(\\.\\d+)*)");
Match versionMatch = versionPattern.Match(process.StandardError.ReadToEnd().Trim());
if (versionMatch.Success)
return versionMatch.Groups[1].Value;
}
return null;
}
/// <summary>

View File

@@ -217,8 +217,8 @@
<!-- Tag -->
<Type Name="Tag">
<DisplayString Condition="Index == -1">None</DisplayString>
<DisplayString Condition="Index != -1">Tag={TagsListDebug[Index]}</DisplayString>
<DisplayString Condition="Index == 0">None</DisplayString>
<DisplayString Condition="Index != 0">Tag={TagsListDebug[Index - 1]}</DisplayString>
</Type>
</AutoVisualizer>