Merge pull request #1505 from Margen67/cleanup
Remove (hopefully) last OpenGL leftovers & crunch
This commit is contained in:
commit
11508caa49
|
@ -18,7 +18,6 @@ addons:
|
||||||
- python3
|
- python3
|
||||||
- libc++-dev
|
- libc++-dev
|
||||||
- libc++abi-dev
|
- libc++abi-dev
|
||||||
- libglew-dev
|
|
||||||
- libgtk-3-dev
|
- libgtk-3-dev
|
||||||
- libpthread-stubs0-dev
|
- libpthread-stubs0-dev
|
||||||
#- libvulkan1
|
#- libvulkan1
|
||||||
|
|
|
@ -105,7 +105,7 @@ sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes in
|
||||||
|
|
||||||
You will also need some development libraries. To get them on an Ubuntu system:
|
You will also need some development libraries. To get them on an Ubuntu system:
|
||||||
```
|
```
|
||||||
sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libglew-dev libx11-dev libvulkan-dev libc++-dev libc++abi-dev
|
sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libx11-dev libvulkan-dev libc++-dev libc++abi-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
In addition, you will need the latest Vulkan libraries and drivers for your hardware.
|
In addition, you will need the latest Vulkan libraries and drivers for your hardware.
|
||||||
|
|
|
@ -22,9 +22,6 @@ includedirs({
|
||||||
defines({
|
defines({
|
||||||
"_UNICODE",
|
"_UNICODE",
|
||||||
"UNICODE",
|
"UNICODE",
|
||||||
|
|
||||||
-- TODO(benvanik): find a better place for this stuff.
|
|
||||||
"GLEW_NO_GLU=1",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
-- TODO(DrChat): Find a way to disable this on other architectures.
|
-- TODO(DrChat): Find a way to disable this on other architectures.
|
||||||
|
@ -217,7 +214,6 @@ solution("xenia")
|
||||||
include("third_party/discord-rpc.lua")
|
include("third_party/discord-rpc.lua")
|
||||||
include("third_party/cxxopts.lua")
|
include("third_party/cxxopts.lua")
|
||||||
include("third_party/cpptoml.lua")
|
include("third_party/cpptoml.lua")
|
||||||
include("third_party/glew.lua")
|
|
||||||
include("third_party/glslang-spirv.lua")
|
include("third_party/glslang-spirv.lua")
|
||||||
include("third_party/imgui.lua")
|
include("third_party/imgui.lua")
|
||||||
include("third_party/libav.lua")
|
include("third_party/libav.lua")
|
||||||
|
|
|
@ -12,7 +12,6 @@ project("xenia-app")
|
||||||
"capstone",
|
"capstone",
|
||||||
"dxbc",
|
"dxbc",
|
||||||
"discord-rpc",
|
"discord-rpc",
|
||||||
"glew",
|
|
||||||
"glslang-spirv",
|
"glslang-spirv",
|
||||||
"imgui",
|
"imgui",
|
||||||
"libavcodec",
|
"libavcodec",
|
||||||
|
@ -71,7 +70,6 @@ project("xenia-app")
|
||||||
"X11",
|
"X11",
|
||||||
"xcb",
|
"xcb",
|
||||||
"X11-xcb",
|
"X11-xcb",
|
||||||
"GL",
|
|
||||||
"vulkan",
|
"vulkan",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,87 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
|
|
||||||
#define XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "xenia/base/string_buffer.h"
|
|
||||||
#include "xenia/gpu/shader_translator.h"
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace gpu {
|
|
||||||
|
|
||||||
class GlslShaderTranslator : public ShaderTranslator {
|
|
||||||
public:
|
|
||||||
enum class Dialect {
|
|
||||||
kGL45,
|
|
||||||
kVulkan,
|
|
||||||
};
|
|
||||||
|
|
||||||
GlslShaderTranslator(Dialect dialect);
|
|
||||||
~GlslShaderTranslator() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void Reset() override;
|
|
||||||
|
|
||||||
void EmitTranslationError(const char* message) override;
|
|
||||||
void EmitUnimplementedTranslationError() override;
|
|
||||||
|
|
||||||
void StartTranslation() override;
|
|
||||||
std::vector<uint8_t> CompleteTranslation() override;
|
|
||||||
|
|
||||||
void ProcessLabel(uint32_t cf_index) override;
|
|
||||||
void ProcessControlFlowNopInstruction(uint32_t cf_index) override;
|
|
||||||
void ProcessControlFlowInstructionBegin(uint32_t cf_index) override;
|
|
||||||
void ProcessControlFlowInstructionEnd(uint32_t cf_index) override;
|
|
||||||
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
|
|
||||||
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
|
|
||||||
void ProcessLoopStartInstruction(
|
|
||||||
const ParsedLoopStartInstruction& instr) override;
|
|
||||||
void ProcessLoopEndInstruction(
|
|
||||||
const ParsedLoopEndInstruction& instr) override;
|
|
||||||
void ProcessCallInstruction(const ParsedCallInstruction& instr) override;
|
|
||||||
void ProcessReturnInstruction(const ParsedReturnInstruction& instr) override;
|
|
||||||
void ProcessJumpInstruction(const ParsedJumpInstruction& instr) override;
|
|
||||||
void ProcessAllocInstruction(const ParsedAllocInstruction& instr) override;
|
|
||||||
void ProcessVertexFetchInstruction(
|
|
||||||
const ParsedVertexFetchInstruction& instr) override;
|
|
||||||
void ProcessTextureFetchInstruction(
|
|
||||||
const ParsedTextureFetchInstruction& instr) override;
|
|
||||||
void ProcessAluInstruction(const ParsedAluInstruction& instr) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Indent();
|
|
||||||
void Unindent();
|
|
||||||
|
|
||||||
void EmitLoadOperand(size_t i, const InstructionOperand& op);
|
|
||||||
void EmitStoreVectorResult(const InstructionResult& result);
|
|
||||||
void EmitStoreScalarResult(const InstructionResult& result);
|
|
||||||
void EmitStoreResult(const InstructionResult& result, const char* temp);
|
|
||||||
|
|
||||||
Dialect dialect_;
|
|
||||||
|
|
||||||
StringBuffer source_;
|
|
||||||
int depth_ = 0;
|
|
||||||
char depth_prefix_[16] = {0};
|
|
||||||
bool cf_wrote_pc_ = false;
|
|
||||||
bool cf_exec_pred_ = false;
|
|
||||||
bool cf_exec_pred_cond_ = false;
|
|
||||||
|
|
||||||
bool ProcessVectorAluOperation(const ParsedAluInstruction& instr);
|
|
||||||
bool ProcessScalarAluOperation(const ParsedAluInstruction& instr);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace gpu
|
|
||||||
} // namespace xe
|
|
||||||
|
|
||||||
#endif // XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/gpu/dxbc_shader_translator.h"
|
#include "xenia/gpu/dxbc_shader_translator.h"
|
||||||
#include "xenia/gpu/glsl_shader_translator.h"
|
|
||||||
#include "xenia/gpu/shader_translator.h"
|
#include "xenia/gpu/shader_translator.h"
|
||||||
#include "xenia/gpu/spirv_shader_translator.h"
|
#include "xenia/gpu/spirv_shader_translator.h"
|
||||||
#include "xenia/ui/spirv/spirv_disassembler.h"
|
#include "xenia/ui/spirv/spirv_disassembler.h"
|
||||||
|
@ -34,8 +33,7 @@ DEFINE_string(shader_input_type, "",
|
||||||
"GPU");
|
"GPU");
|
||||||
DEFINE_string(shader_output, "", "Output shader file path.", "GPU");
|
DEFINE_string(shader_output, "", "Output shader file path.", "GPU");
|
||||||
DEFINE_string(shader_output_type, "ucode",
|
DEFINE_string(shader_output_type, "ucode",
|
||||||
"Translator to use: [ucode, glsl45, spirv, spirvtext, dxbc].",
|
"Translator to use: [ucode, spirv, spirvtext, dxbc].", "GPU");
|
||||||
"GPU");
|
|
||||||
DEFINE_string(shader_output_patch, "",
|
DEFINE_string(shader_output_patch, "",
|
||||||
"Tessellation patch type in the generated tessellation "
|
"Tessellation patch type in the generated tessellation "
|
||||||
"evaluation (domain) shader, or unspecified to produce a vertex "
|
"evaluation (domain) shader, or unspecified to produce a vertex "
|
||||||
|
@ -105,9 +103,6 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
|
||||||
if (cvars::shader_output_type == "spirv" ||
|
if (cvars::shader_output_type == "spirv" ||
|
||||||
cvars::shader_output_type == "spirvtext") {
|
cvars::shader_output_type == "spirvtext") {
|
||||||
translator = std::make_unique<SpirvShaderTranslator>();
|
translator = std::make_unique<SpirvShaderTranslator>();
|
||||||
} else if (cvars::shader_output_type == "glsl45") {
|
|
||||||
translator = std::make_unique<GlslShaderTranslator>(
|
|
||||||
GlslShaderTranslator::Dialect::kGL45);
|
|
||||||
} else if (cvars::shader_output_type == "dxbc") {
|
} else if (cvars::shader_output_type == "dxbc") {
|
||||||
translator = std::make_unique<DxbcShaderTranslator>(
|
translator = std::make_unique<DxbcShaderTranslator>(
|
||||||
0, cvars::shader_output_dxbc_rov);
|
0, cvars::shader_output_dxbc_rov);
|
||||||
|
|
|
@ -36,7 +36,6 @@ using xe::ui::vulkan::CheckResult;
|
||||||
PipelineCache::PipelineCache(RegisterFile* register_file,
|
PipelineCache::PipelineCache(RegisterFile* register_file,
|
||||||
ui::vulkan::VulkanDevice* device)
|
ui::vulkan::VulkanDevice* device)
|
||||||
: register_file_(register_file), device_(device) {
|
: register_file_(register_file), device_(device) {
|
||||||
// We can also use the GLSL translator with a Vulkan dialect.
|
|
||||||
shader_translator_.reset(new SpirvShaderTranslator());
|
shader_translator_.reset(new SpirvShaderTranslator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#include "third_party/xxhash/xxhash.h"
|
#include "third_party/xxhash/xxhash.h"
|
||||||
|
|
||||||
#include "xenia/gpu/glsl_shader_translator.h"
|
|
||||||
#include "xenia/gpu/register_file.h"
|
#include "xenia/gpu/register_file.h"
|
||||||
#include "xenia/gpu/spirv_shader_translator.h"
|
#include "xenia/gpu/spirv_shader_translator.h"
|
||||||
#include "xenia/gpu/vulkan/render_cache.h"
|
#include "xenia/gpu/vulkan/render_cache.h"
|
||||||
|
|
|
@ -20,7 +20,6 @@ project("xenia-hid-demo")
|
||||||
kind("WindowedApp")
|
kind("WindowedApp")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
"glew",
|
|
||||||
"imgui",
|
"imgui",
|
||||||
"volk",
|
"volk",
|
||||||
"xenia-base",
|
"xenia-base",
|
||||||
|
@ -29,10 +28,6 @@ project("xenia-hid-demo")
|
||||||
"xenia-ui",
|
"xenia-ui",
|
||||||
"xenia-ui-vulkan",
|
"xenia-ui-vulkan",
|
||||||
})
|
})
|
||||||
defines({
|
|
||||||
"GLEW_STATIC=1",
|
|
||||||
"GLEW_MX=1",
|
|
||||||
})
|
|
||||||
files({
|
files({
|
||||||
"hid_demo.cc",
|
"hid_demo.cc",
|
||||||
"../base/main_"..platform_suffix..".cc",
|
"../base/main_"..platform_suffix..".cc",
|
||||||
|
@ -46,7 +41,6 @@ project("xenia-hid-demo")
|
||||||
"X11",
|
"X11",
|
||||||
"xcb",
|
"xcb",
|
||||||
"X11-xcb",
|
"X11-xcb",
|
||||||
"GL",
|
|
||||||
"vulkan",
|
"vulkan",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
The OpenGL Extension Wrangler Library
|
|
||||||
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
|
|
||||||
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
|
|
||||||
Copyright (C) 2002, Lev Povalahev
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
* The name of the author may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
||||||
THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
Mesa 3-D graphics library
|
|
||||||
Version: 7.0
|
|
||||||
|
|
||||||
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
||||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2007 The Khronos Group Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and/or associated documentation files (the
|
|
||||||
"Materials"), to deal in the Materials without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Materials, and to
|
|
||||||
permit persons to whom the Materials are furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Materials.
|
|
||||||
|
|
||||||
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,926 +0,0 @@
|
||||||
#ifndef __glxext_h_
|
|
||||||
#define __glxext_h_ 1
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Copyright (c) 2013-2014 The Khronos Group Inc.
|
|
||||||
**
|
|
||||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
** copy of this software and/or associated documentation files (the
|
|
||||||
** "Materials"), to deal in the Materials without restriction, including
|
|
||||||
** without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
|
||||||
** permit persons to whom the Materials are furnished to do so, subject to
|
|
||||||
** the following conditions:
|
|
||||||
**
|
|
||||||
** The above copyright notice and this permission notice shall be included
|
|
||||||
** in all copies or substantial portions of the Materials.
|
|
||||||
**
|
|
||||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
** This header is generated from the Khronos OpenGL / OpenGL ES XML
|
|
||||||
** API Registry. The current version of the Registry, generator scripts
|
|
||||||
** used to make the header, and the header can be found at
|
|
||||||
** http://www.opengl.org/registry/
|
|
||||||
**
|
|
||||||
** Khronos $Revision: 28198 $ on $Date: 2014-09-18 07:42:14 -0700 (Thu, 18 Sep 2014) $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define GLX_GLXEXT_VERSION 20140918
|
|
||||||
|
|
||||||
/* Generated C header for:
|
|
||||||
* API: glx
|
|
||||||
* Versions considered: .*
|
|
||||||
* Versions emitted: 1\.[3-9]
|
|
||||||
* Default extensions included: glx
|
|
||||||
* Additional extensions included: _nomatch_^
|
|
||||||
* Extensions removed: _nomatch_^
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GLX_VERSION_1_3
|
|
||||||
#define GLX_VERSION_1_3 1
|
|
||||||
typedef XID GLXContextID;
|
|
||||||
typedef struct __GLXFBConfigRec *GLXFBConfig;
|
|
||||||
typedef XID GLXWindow;
|
|
||||||
typedef XID GLXPbuffer;
|
|
||||||
#define GLX_WINDOW_BIT 0x00000001
|
|
||||||
#define GLX_PIXMAP_BIT 0x00000002
|
|
||||||
#define GLX_PBUFFER_BIT 0x00000004
|
|
||||||
#define GLX_RGBA_BIT 0x00000001
|
|
||||||
#define GLX_COLOR_INDEX_BIT 0x00000002
|
|
||||||
#define GLX_PBUFFER_CLOBBER_MASK 0x08000000
|
|
||||||
#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001
|
|
||||||
#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002
|
|
||||||
#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004
|
|
||||||
#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008
|
|
||||||
#define GLX_AUX_BUFFERS_BIT 0x00000010
|
|
||||||
#define GLX_DEPTH_BUFFER_BIT 0x00000020
|
|
||||||
#define GLX_STENCIL_BUFFER_BIT 0x00000040
|
|
||||||
#define GLX_ACCUM_BUFFER_BIT 0x00000080
|
|
||||||
#define GLX_CONFIG_CAVEAT 0x20
|
|
||||||
#define GLX_X_VISUAL_TYPE 0x22
|
|
||||||
#define GLX_TRANSPARENT_TYPE 0x23
|
|
||||||
#define GLX_TRANSPARENT_INDEX_VALUE 0x24
|
|
||||||
#define GLX_TRANSPARENT_RED_VALUE 0x25
|
|
||||||
#define GLX_TRANSPARENT_GREEN_VALUE 0x26
|
|
||||||
#define GLX_TRANSPARENT_BLUE_VALUE 0x27
|
|
||||||
#define GLX_TRANSPARENT_ALPHA_VALUE 0x28
|
|
||||||
#define GLX_DONT_CARE 0xFFFFFFFF
|
|
||||||
#define GLX_NONE 0x8000
|
|
||||||
#define GLX_SLOW_CONFIG 0x8001
|
|
||||||
#define GLX_TRUE_COLOR 0x8002
|
|
||||||
#define GLX_DIRECT_COLOR 0x8003
|
|
||||||
#define GLX_PSEUDO_COLOR 0x8004
|
|
||||||
#define GLX_STATIC_COLOR 0x8005
|
|
||||||
#define GLX_GRAY_SCALE 0x8006
|
|
||||||
#define GLX_STATIC_GRAY 0x8007
|
|
||||||
#define GLX_TRANSPARENT_RGB 0x8008
|
|
||||||
#define GLX_TRANSPARENT_INDEX 0x8009
|
|
||||||
#define GLX_VISUAL_ID 0x800B
|
|
||||||
#define GLX_SCREEN 0x800C
|
|
||||||
#define GLX_NON_CONFORMANT_CONFIG 0x800D
|
|
||||||
#define GLX_DRAWABLE_TYPE 0x8010
|
|
||||||
#define GLX_RENDER_TYPE 0x8011
|
|
||||||
#define GLX_X_RENDERABLE 0x8012
|
|
||||||
#define GLX_FBCONFIG_ID 0x8013
|
|
||||||
#define GLX_RGBA_TYPE 0x8014
|
|
||||||
#define GLX_COLOR_INDEX_TYPE 0x8015
|
|
||||||
#define GLX_MAX_PBUFFER_WIDTH 0x8016
|
|
||||||
#define GLX_MAX_PBUFFER_HEIGHT 0x8017
|
|
||||||
#define GLX_MAX_PBUFFER_PIXELS 0x8018
|
|
||||||
#define GLX_PRESERVED_CONTENTS 0x801B
|
|
||||||
#define GLX_LARGEST_PBUFFER 0x801C
|
|
||||||
#define GLX_WIDTH 0x801D
|
|
||||||
#define GLX_HEIGHT 0x801E
|
|
||||||
#define GLX_EVENT_MASK 0x801F
|
|
||||||
#define GLX_DAMAGED 0x8020
|
|
||||||
#define GLX_SAVED 0x8021
|
|
||||||
#define GLX_WINDOW 0x8022
|
|
||||||
#define GLX_PBUFFER 0x8023
|
|
||||||
#define GLX_PBUFFER_HEIGHT 0x8040
|
|
||||||
#define GLX_PBUFFER_WIDTH 0x8041
|
|
||||||
typedef GLXFBConfig *( *PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements);
|
|
||||||
typedef GLXFBConfig *( *PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
|
|
||||||
typedef int ( *PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value);
|
|
||||||
typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
|
|
||||||
typedef GLXWindow ( *PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
|
|
||||||
typedef void ( *PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win);
|
|
||||||
typedef GLXPixmap ( *PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
|
|
||||||
typedef void ( *PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap);
|
|
||||||
typedef GLXPbuffer ( *PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list);
|
|
||||||
typedef void ( *PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf);
|
|
||||||
typedef void ( *PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
|
|
||||||
typedef GLXContext ( *PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
|
|
||||||
typedef Bool ( *PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
|
|
||||||
typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLEPROC) (void);
|
|
||||||
typedef int ( *PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value);
|
|
||||||
typedef void ( *PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask);
|
|
||||||
typedef void ( *PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
GLXFBConfig *glXGetFBConfigs (Display *dpy, int screen, int *nelements);
|
|
||||||
GLXFBConfig *glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements);
|
|
||||||
int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value);
|
|
||||||
XVisualInfo *glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config);
|
|
||||||
GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
|
|
||||||
void glXDestroyWindow (Display *dpy, GLXWindow win);
|
|
||||||
GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
|
|
||||||
void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap);
|
|
||||||
GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list);
|
|
||||||
void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf);
|
|
||||||
void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
|
|
||||||
GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
|
|
||||||
Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
|
|
||||||
GLXDrawable glXGetCurrentReadDrawable (void);
|
|
||||||
int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value);
|
|
||||||
void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask);
|
|
||||||
void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_VERSION_1_3 */
|
|
||||||
|
|
||||||
#ifndef GLX_VERSION_1_4
|
|
||||||
#define GLX_VERSION_1_4 1
|
|
||||||
typedef void ( *__GLXextFuncPtr)(void);
|
|
||||||
#define GLX_SAMPLE_BUFFERS 100000
|
|
||||||
#define GLX_SAMPLES 100001
|
|
||||||
typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_VERSION_1_4 */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_context_flush_control
|
|
||||||
#define GLX_ARB_context_flush_control 1
|
|
||||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
|
||||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
|
||||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
|
||||||
#endif /* GLX_ARB_context_flush_control */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_create_context
|
|
||||||
#define GLX_ARB_create_context 1
|
|
||||||
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
|
||||||
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
|
||||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
||||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
||||||
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
|
||||||
typedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_ARB_create_context */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_create_context_profile
|
|
||||||
#define GLX_ARB_create_context_profile 1
|
|
||||||
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
||||||
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
|
||||||
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
||||||
#endif /* GLX_ARB_create_context_profile */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_create_context_robustness
|
|
||||||
#define GLX_ARB_create_context_robustness 1
|
|
||||||
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
|
||||||
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
|
||||||
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
|
||||||
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
|
|
||||||
#endif /* GLX_ARB_create_context_robustness */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_fbconfig_float
|
|
||||||
#define GLX_ARB_fbconfig_float 1
|
|
||||||
#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9
|
|
||||||
#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004
|
|
||||||
#endif /* GLX_ARB_fbconfig_float */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_framebuffer_sRGB
|
|
||||||
#define GLX_ARB_framebuffer_sRGB 1
|
|
||||||
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
|
|
||||||
#endif /* GLX_ARB_framebuffer_sRGB */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_get_proc_address
|
|
||||||
#define GLX_ARB_get_proc_address 1
|
|
||||||
typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
__GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_ARB_get_proc_address */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_multisample
|
|
||||||
#define GLX_ARB_multisample 1
|
|
||||||
#define GLX_SAMPLE_BUFFERS_ARB 100000
|
|
||||||
#define GLX_SAMPLES_ARB 100001
|
|
||||||
#endif /* GLX_ARB_multisample */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_robustness_application_isolation
|
|
||||||
#define GLX_ARB_robustness_application_isolation 1
|
|
||||||
#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
|
|
||||||
#endif /* GLX_ARB_robustness_application_isolation */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_robustness_share_group_isolation
|
|
||||||
#define GLX_ARB_robustness_share_group_isolation 1
|
|
||||||
#endif /* GLX_ARB_robustness_share_group_isolation */
|
|
||||||
|
|
||||||
#ifndef GLX_ARB_vertex_buffer_object
|
|
||||||
#define GLX_ARB_vertex_buffer_object 1
|
|
||||||
#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095
|
|
||||||
#endif /* GLX_ARB_vertex_buffer_object */
|
|
||||||
|
|
||||||
#ifndef GLX_3DFX_multisample
|
|
||||||
#define GLX_3DFX_multisample 1
|
|
||||||
#define GLX_SAMPLE_BUFFERS_3DFX 0x8050
|
|
||||||
#define GLX_SAMPLES_3DFX 0x8051
|
|
||||||
#endif /* GLX_3DFX_multisample */
|
|
||||||
|
|
||||||
#ifndef GLX_AMD_gpu_association
|
|
||||||
#define GLX_AMD_gpu_association 1
|
|
||||||
#define GLX_GPU_VENDOR_AMD 0x1F00
|
|
||||||
#define GLX_GPU_RENDERER_STRING_AMD 0x1F01
|
|
||||||
#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02
|
|
||||||
#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2
|
|
||||||
#define GLX_GPU_RAM_AMD 0x21A3
|
|
||||||
#define GLX_GPU_CLOCK_AMD 0x21A4
|
|
||||||
#define GLX_GPU_NUM_PIPES_AMD 0x21A5
|
|
||||||
#define GLX_GPU_NUM_SIMD_AMD 0x21A6
|
|
||||||
#define GLX_GPU_NUM_RB_AMD 0x21A7
|
|
||||||
#define GLX_GPU_NUM_SPI_AMD 0x21A8
|
|
||||||
typedef unsigned int ( *PFNGLXGETGPUIDSAMDPROC) (unsigned int maxCount, unsigned int *ids);
|
|
||||||
typedef int ( *PFNGLXGETGPUINFOAMDPROC) (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);
|
|
||||||
typedef unsigned int ( *PFNGLXGETCONTEXTGPUIDAMDPROC) (GLXContext ctx);
|
|
||||||
typedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC) (unsigned int id, GLXContext share_list);
|
|
||||||
typedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (unsigned int id, GLXContext share_context, const int *attribList);
|
|
||||||
typedef Bool ( *PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC) (GLXContext ctx);
|
|
||||||
typedef Bool ( *PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (GLXContext ctx);
|
|
||||||
typedef GLXContext ( *PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);
|
|
||||||
typedef void ( *PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC) (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
unsigned int glXGetGPUIDsAMD (unsigned int maxCount, unsigned int *ids);
|
|
||||||
int glXGetGPUInfoAMD (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);
|
|
||||||
unsigned int glXGetContextGPUIDAMD (GLXContext ctx);
|
|
||||||
GLXContext glXCreateAssociatedContextAMD (unsigned int id, GLXContext share_list);
|
|
||||||
GLXContext glXCreateAssociatedContextAttribsAMD (unsigned int id, GLXContext share_context, const int *attribList);
|
|
||||||
Bool glXDeleteAssociatedContextAMD (GLXContext ctx);
|
|
||||||
Bool glXMakeAssociatedContextCurrentAMD (GLXContext ctx);
|
|
||||||
GLXContext glXGetCurrentAssociatedContextAMD (void);
|
|
||||||
void glXBlitContextFramebufferAMD (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_AMD_gpu_association */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_buffer_age
|
|
||||||
#define GLX_EXT_buffer_age 1
|
|
||||||
#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
|
|
||||||
#endif /* GLX_EXT_buffer_age */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_create_context_es2_profile
|
|
||||||
#define GLX_EXT_create_context_es2_profile 1
|
|
||||||
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
|
||||||
#endif /* GLX_EXT_create_context_es2_profile */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_create_context_es_profile
|
|
||||||
#define GLX_EXT_create_context_es_profile 1
|
|
||||||
#define GLX_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
|
|
||||||
#endif /* GLX_EXT_create_context_es_profile */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_fbconfig_packed_float
|
|
||||||
#define GLX_EXT_fbconfig_packed_float 1
|
|
||||||
#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1
|
|
||||||
#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008
|
|
||||||
#endif /* GLX_EXT_fbconfig_packed_float */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_framebuffer_sRGB
|
|
||||||
#define GLX_EXT_framebuffer_sRGB 1
|
|
||||||
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2
|
|
||||||
#endif /* GLX_EXT_framebuffer_sRGB */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_import_context
|
|
||||||
#define GLX_EXT_import_context 1
|
|
||||||
#define GLX_SHARE_CONTEXT_EXT 0x800A
|
|
||||||
#define GLX_VISUAL_ID_EXT 0x800B
|
|
||||||
#define GLX_SCREEN_EXT 0x800C
|
|
||||||
typedef Display *( *PFNGLXGETCURRENTDISPLAYEXTPROC) (void);
|
|
||||||
typedef int ( *PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value);
|
|
||||||
typedef GLXContextID ( *PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context);
|
|
||||||
typedef GLXContext ( *PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID);
|
|
||||||
typedef void ( *PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Display *glXGetCurrentDisplayEXT (void);
|
|
||||||
int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value);
|
|
||||||
GLXContextID glXGetContextIDEXT (const GLXContext context);
|
|
||||||
GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID);
|
|
||||||
void glXFreeContextEXT (Display *dpy, GLXContext context);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_EXT_import_context */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_stereo_tree
|
|
||||||
#define GLX_EXT_stereo_tree 1
|
|
||||||
typedef struct {
|
|
||||||
int type;
|
|
||||||
unsigned long serial;
|
|
||||||
Bool send_event;
|
|
||||||
Display *display;
|
|
||||||
int extension;
|
|
||||||
int evtype;
|
|
||||||
GLXDrawable window;
|
|
||||||
Bool stereo_tree;
|
|
||||||
} GLXStereoNotifyEventEXT;
|
|
||||||
#define GLX_STEREO_TREE_EXT 0x20F5
|
|
||||||
#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
|
|
||||||
#define GLX_STEREO_NOTIFY_EXT 0x00000000
|
|
||||||
#endif /* GLX_EXT_stereo_tree */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_swap_control
|
|
||||||
#define GLX_EXT_swap_control 1
|
|
||||||
#define GLX_SWAP_INTERVAL_EXT 0x20F1
|
|
||||||
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
|
|
||||||
typedef void ( *PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_EXT_swap_control */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_swap_control_tear
|
|
||||||
#define GLX_EXT_swap_control_tear 1
|
|
||||||
#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
|
|
||||||
#endif /* GLX_EXT_swap_control_tear */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_texture_from_pixmap
|
|
||||||
#define GLX_EXT_texture_from_pixmap 1
|
|
||||||
#define GLX_TEXTURE_1D_BIT_EXT 0x00000001
|
|
||||||
#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
|
|
||||||
#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
|
|
||||||
#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
|
|
||||||
#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
|
|
||||||
#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
|
|
||||||
#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
|
|
||||||
#define GLX_Y_INVERTED_EXT 0x20D4
|
|
||||||
#define GLX_TEXTURE_FORMAT_EXT 0x20D5
|
|
||||||
#define GLX_TEXTURE_TARGET_EXT 0x20D6
|
|
||||||
#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
|
|
||||||
#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
|
|
||||||
#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
|
|
||||||
#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
|
|
||||||
#define GLX_TEXTURE_1D_EXT 0x20DB
|
|
||||||
#define GLX_TEXTURE_2D_EXT 0x20DC
|
|
||||||
#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
|
|
||||||
#define GLX_FRONT_LEFT_EXT 0x20DE
|
|
||||||
#define GLX_FRONT_RIGHT_EXT 0x20DF
|
|
||||||
#define GLX_BACK_LEFT_EXT 0x20E0
|
|
||||||
#define GLX_BACK_RIGHT_EXT 0x20E1
|
|
||||||
#define GLX_FRONT_EXT 0x20DE
|
|
||||||
#define GLX_BACK_EXT 0x20E0
|
|
||||||
#define GLX_AUX0_EXT 0x20E2
|
|
||||||
#define GLX_AUX1_EXT 0x20E3
|
|
||||||
#define GLX_AUX2_EXT 0x20E4
|
|
||||||
#define GLX_AUX3_EXT 0x20E5
|
|
||||||
#define GLX_AUX4_EXT 0x20E6
|
|
||||||
#define GLX_AUX5_EXT 0x20E7
|
|
||||||
#define GLX_AUX6_EXT 0x20E8
|
|
||||||
#define GLX_AUX7_EXT 0x20E9
|
|
||||||
#define GLX_AUX8_EXT 0x20EA
|
|
||||||
#define GLX_AUX9_EXT 0x20EB
|
|
||||||
typedef void ( *PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
|
|
||||||
typedef void ( *PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
|
|
||||||
void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_EXT_texture_from_pixmap */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_visual_info
|
|
||||||
#define GLX_EXT_visual_info 1
|
|
||||||
#define GLX_X_VISUAL_TYPE_EXT 0x22
|
|
||||||
#define GLX_TRANSPARENT_TYPE_EXT 0x23
|
|
||||||
#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24
|
|
||||||
#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25
|
|
||||||
#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26
|
|
||||||
#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27
|
|
||||||
#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28
|
|
||||||
#define GLX_NONE_EXT 0x8000
|
|
||||||
#define GLX_TRUE_COLOR_EXT 0x8002
|
|
||||||
#define GLX_DIRECT_COLOR_EXT 0x8003
|
|
||||||
#define GLX_PSEUDO_COLOR_EXT 0x8004
|
|
||||||
#define GLX_STATIC_COLOR_EXT 0x8005
|
|
||||||
#define GLX_GRAY_SCALE_EXT 0x8006
|
|
||||||
#define GLX_STATIC_GRAY_EXT 0x8007
|
|
||||||
#define GLX_TRANSPARENT_RGB_EXT 0x8008
|
|
||||||
#define GLX_TRANSPARENT_INDEX_EXT 0x8009
|
|
||||||
#endif /* GLX_EXT_visual_info */
|
|
||||||
|
|
||||||
#ifndef GLX_EXT_visual_rating
|
|
||||||
#define GLX_EXT_visual_rating 1
|
|
||||||
#define GLX_VISUAL_CAVEAT_EXT 0x20
|
|
||||||
#define GLX_SLOW_VISUAL_EXT 0x8001
|
|
||||||
#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
|
|
||||||
#endif /* GLX_EXT_visual_rating */
|
|
||||||
|
|
||||||
#ifndef GLX_INTEL_swap_event
|
|
||||||
#define GLX_INTEL_swap_event 1
|
|
||||||
#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000
|
|
||||||
#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180
|
|
||||||
#define GLX_COPY_COMPLETE_INTEL 0x8181
|
|
||||||
#define GLX_FLIP_COMPLETE_INTEL 0x8182
|
|
||||||
#endif /* GLX_INTEL_swap_event */
|
|
||||||
|
|
||||||
#ifndef GLX_MESA_agp_offset
|
|
||||||
#define GLX_MESA_agp_offset 1
|
|
||||||
typedef unsigned int ( *PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
unsigned int glXGetAGPOffsetMESA (const void *pointer);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_MESA_agp_offset */
|
|
||||||
|
|
||||||
#ifndef GLX_MESA_copy_sub_buffer
|
|
||||||
#define GLX_MESA_copy_sub_buffer 1
|
|
||||||
typedef void ( *PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_MESA_copy_sub_buffer */
|
|
||||||
|
|
||||||
#ifndef GLX_MESA_pixmap_colormap
|
|
||||||
#define GLX_MESA_pixmap_colormap 1
|
|
||||||
typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_MESA_pixmap_colormap */
|
|
||||||
|
|
||||||
#ifndef GLX_MESA_query_renderer
|
|
||||||
#define GLX_MESA_query_renderer 1
|
|
||||||
#define GLX_RENDERER_VENDOR_ID_MESA 0x8183
|
|
||||||
#define GLX_RENDERER_DEVICE_ID_MESA 0x8184
|
|
||||||
#define GLX_RENDERER_VERSION_MESA 0x8185
|
|
||||||
#define GLX_RENDERER_ACCELERATED_MESA 0x8186
|
|
||||||
#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187
|
|
||||||
#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188
|
|
||||||
#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189
|
|
||||||
#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A
|
|
||||||
#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B
|
|
||||||
#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C
|
|
||||||
#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D
|
|
||||||
#define GLX_RENDERER_ID_MESA 0x818E
|
|
||||||
typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value);
|
|
||||||
typedef const char *( *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute);
|
|
||||||
typedef Bool ( *PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);
|
|
||||||
typedef const char *( *PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXQueryCurrentRendererIntegerMESA (int attribute, unsigned int *value);
|
|
||||||
const char *glXQueryCurrentRendererStringMESA (int attribute);
|
|
||||||
Bool glXQueryRendererIntegerMESA (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);
|
|
||||||
const char *glXQueryRendererStringMESA (Display *dpy, int screen, int renderer, int attribute);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_MESA_query_renderer */
|
|
||||||
|
|
||||||
#ifndef GLX_MESA_release_buffers
|
|
||||||
#define GLX_MESA_release_buffers 1
|
|
||||||
typedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_MESA_release_buffers */
|
|
||||||
|
|
||||||
#ifndef GLX_MESA_set_3dfx_mode
|
|
||||||
#define GLX_MESA_set_3dfx_mode 1
|
|
||||||
#define GLX_3DFX_WINDOW_MODE_MESA 0x1
|
|
||||||
#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2
|
|
||||||
typedef Bool ( *PFNGLXSET3DFXMODEMESAPROC) (int mode);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXSet3DfxModeMESA (int mode);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_MESA_set_3dfx_mode */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_copy_buffer
|
|
||||||
#define GLX_NV_copy_buffer 1
|
|
||||||
typedef void ( *PFNGLXCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
|
||||||
typedef void ( *PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
|
||||||
void glXNamedCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_copy_buffer */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_copy_image
|
|
||||||
#define GLX_NV_copy_image 1
|
|
||||||
typedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_copy_image */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_delay_before_swap
|
|
||||||
#define GLX_NV_delay_before_swap 1
|
|
||||||
typedef Bool ( *PFNGLXDELAYBEFORESWAPNVPROC) (Display *dpy, GLXDrawable drawable, GLfloat seconds);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXDelayBeforeSwapNV (Display *dpy, GLXDrawable drawable, GLfloat seconds);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_delay_before_swap */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_float_buffer
|
|
||||||
#define GLX_NV_float_buffer 1
|
|
||||||
#define GLX_FLOAT_COMPONENTS_NV 0x20B0
|
|
||||||
#endif /* GLX_NV_float_buffer */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_multisample_coverage
|
|
||||||
#define GLX_NV_multisample_coverage 1
|
|
||||||
#define GLX_COVERAGE_SAMPLES_NV 100001
|
|
||||||
#define GLX_COLOR_SAMPLES_NV 0x20B3
|
|
||||||
#endif /* GLX_NV_multisample_coverage */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_present_video
|
|
||||||
#define GLX_NV_present_video 1
|
|
||||||
#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0
|
|
||||||
typedef unsigned int *( *PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements);
|
|
||||||
typedef int ( *PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
unsigned int *glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements);
|
|
||||||
int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_present_video */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_swap_group
|
|
||||||
#define GLX_NV_swap_group 1
|
|
||||||
typedef Bool ( *PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group);
|
|
||||||
typedef Bool ( *PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier);
|
|
||||||
typedef Bool ( *PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
|
|
||||||
typedef Bool ( *PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
|
|
||||||
typedef Bool ( *PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count);
|
|
||||||
typedef Bool ( *PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group);
|
|
||||||
Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier);
|
|
||||||
Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
|
|
||||||
Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
|
|
||||||
Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count);
|
|
||||||
Bool glXResetFrameCountNV (Display *dpy, int screen);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_swap_group */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_video_capture
|
|
||||||
#define GLX_NV_video_capture 1
|
|
||||||
typedef XID GLXVideoCaptureDeviceNV;
|
|
||||||
#define GLX_DEVICE_ID_NV 0x20CD
|
|
||||||
#define GLX_UNIQUE_ID_NV 0x20CE
|
|
||||||
#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF
|
|
||||||
typedef int ( *PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
|
|
||||||
typedef GLXVideoCaptureDeviceNV *( *PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements);
|
|
||||||
typedef void ( *PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
|
|
||||||
typedef int ( *PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
|
|
||||||
typedef void ( *PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
|
|
||||||
GLXVideoCaptureDeviceNV *glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements);
|
|
||||||
void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
|
|
||||||
int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
|
|
||||||
void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_video_capture */
|
|
||||||
|
|
||||||
#ifndef GLX_NV_video_out
|
|
||||||
#define GLX_NV_video_out 1
|
|
||||||
typedef unsigned int GLXVideoDeviceNV;
|
|
||||||
#define GLX_VIDEO_OUT_COLOR_NV 0x20C3
|
|
||||||
#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4
|
|
||||||
#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5
|
|
||||||
#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6
|
|
||||||
#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7
|
|
||||||
#define GLX_VIDEO_OUT_FRAME_NV 0x20C8
|
|
||||||
#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9
|
|
||||||
#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA
|
|
||||||
#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB
|
|
||||||
#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC
|
|
||||||
typedef int ( *PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
|
|
||||||
typedef int ( *PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
|
|
||||||
typedef int ( *PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
|
|
||||||
typedef int ( *PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf);
|
|
||||||
typedef int ( *PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
|
|
||||||
typedef int ( *PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
|
|
||||||
int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
|
|
||||||
int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
|
|
||||||
int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf);
|
|
||||||
int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
|
|
||||||
int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_NV_video_out */
|
|
||||||
|
|
||||||
#ifndef GLX_OML_swap_method
|
|
||||||
#define GLX_OML_swap_method 1
|
|
||||||
#define GLX_SWAP_METHOD_OML 0x8060
|
|
||||||
#define GLX_SWAP_EXCHANGE_OML 0x8061
|
|
||||||
#define GLX_SWAP_COPY_OML 0x8062
|
|
||||||
#define GLX_SWAP_UNDEFINED_OML 0x8063
|
|
||||||
#endif /* GLX_OML_swap_method */
|
|
||||||
|
|
||||||
#ifndef GLX_OML_sync_control
|
|
||||||
#define GLX_OML_sync_control 1
|
|
||||||
#ifndef GLEXT_64_TYPES_DEFINED
|
|
||||||
/* This code block is duplicated in glext.h, so must be protected */
|
|
||||||
#define GLEXT_64_TYPES_DEFINED
|
|
||||||
/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
|
|
||||||
/* (as used in the GLX_OML_sync_control extension). */
|
|
||||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
|
||||||
#include <inttypes.h>
|
|
||||||
#elif defined(__sun__) || defined(__digital__)
|
|
||||||
#include <inttypes.h>
|
|
||||||
#if defined(__STDC__)
|
|
||||||
#if defined(__arch64__) || defined(_LP64)
|
|
||||||
typedef long int int64_t;
|
|
||||||
typedef unsigned long int uint64_t;
|
|
||||||
#else
|
|
||||||
typedef long long int int64_t;
|
|
||||||
typedef unsigned long long int uint64_t;
|
|
||||||
#endif /* __arch64__ */
|
|
||||||
#endif /* __STDC__ */
|
|
||||||
#elif defined( __VMS ) || defined(__sgi)
|
|
||||||
#include <inttypes.h>
|
|
||||||
#elif defined(__SCO__) || defined(__USLC__)
|
|
||||||
#include <stdint.h>
|
|
||||||
#elif defined(__UNIXOS2__) || defined(__SOL64__)
|
|
||||||
typedef long int int32_t;
|
|
||||||
typedef long long int int64_t;
|
|
||||||
typedef unsigned long long int uint64_t;
|
|
||||||
#elif defined(_WIN32) && defined(__GNUC__)
|
|
||||||
#include <stdint.h>
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
typedef __int32 int32_t;
|
|
||||||
typedef __int64 int64_t;
|
|
||||||
typedef unsigned __int64 uint64_t;
|
|
||||||
#else
|
|
||||||
/* Fallback if nothing above works */
|
|
||||||
#include <inttypes.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
typedef Bool ( *PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
|
|
||||||
typedef Bool ( *PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
|
|
||||||
typedef int64_t ( *PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
|
|
||||||
typedef Bool ( *PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
|
|
||||||
typedef Bool ( *PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
|
|
||||||
Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
|
|
||||||
int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
|
|
||||||
Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
|
|
||||||
Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_OML_sync_control */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIS_blended_overlay
|
|
||||||
#define GLX_SGIS_blended_overlay 1
|
|
||||||
#define GLX_BLENDED_RGBA_SGIS 0x8025
|
|
||||||
#endif /* GLX_SGIS_blended_overlay */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIS_multisample
|
|
||||||
#define GLX_SGIS_multisample 1
|
|
||||||
#define GLX_SAMPLE_BUFFERS_SGIS 100000
|
|
||||||
#define GLX_SAMPLES_SGIS 100001
|
|
||||||
#endif /* GLX_SGIS_multisample */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIS_shared_multisample
|
|
||||||
#define GLX_SGIS_shared_multisample 1
|
|
||||||
#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026
|
|
||||||
#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027
|
|
||||||
#endif /* GLX_SGIS_shared_multisample */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_dmbuffer
|
|
||||||
#define GLX_SGIX_dmbuffer 1
|
|
||||||
typedef XID GLXPbufferSGIX;
|
|
||||||
#ifdef _DM_BUFFER_H_
|
|
||||||
#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024
|
|
||||||
typedef Bool ( *PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
|
|
||||||
#endif
|
|
||||||
#endif /* _DM_BUFFER_H_ */
|
|
||||||
#endif /* GLX_SGIX_dmbuffer */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_fbconfig
|
|
||||||
#define GLX_SGIX_fbconfig 1
|
|
||||||
typedef struct __GLXFBConfigRec *GLXFBConfigSGIX;
|
|
||||||
#define GLX_WINDOW_BIT_SGIX 0x00000001
|
|
||||||
#define GLX_PIXMAP_BIT_SGIX 0x00000002
|
|
||||||
#define GLX_RGBA_BIT_SGIX 0x00000001
|
|
||||||
#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002
|
|
||||||
#define GLX_DRAWABLE_TYPE_SGIX 0x8010
|
|
||||||
#define GLX_RENDER_TYPE_SGIX 0x8011
|
|
||||||
#define GLX_X_RENDERABLE_SGIX 0x8012
|
|
||||||
#define GLX_FBCONFIG_ID_SGIX 0x8013
|
|
||||||
#define GLX_RGBA_TYPE_SGIX 0x8014
|
|
||||||
#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015
|
|
||||||
typedef int ( *PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
|
|
||||||
typedef GLXFBConfigSGIX *( *PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements);
|
|
||||||
typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
|
|
||||||
typedef GLXContext ( *PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
|
|
||||||
typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config);
|
|
||||||
typedef GLXFBConfigSGIX ( *PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
|
|
||||||
GLXFBConfigSGIX *glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements);
|
|
||||||
GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
|
|
||||||
GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
|
|
||||||
XVisualInfo *glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config);
|
|
||||||
GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGIX_fbconfig */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_hyperpipe
|
|
||||||
#define GLX_SGIX_hyperpipe 1
|
|
||||||
typedef struct {
|
|
||||||
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
|
|
||||||
int networkId;
|
|
||||||
} GLXHyperpipeNetworkSGIX;
|
|
||||||
typedef struct {
|
|
||||||
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
|
|
||||||
int channel;
|
|
||||||
unsigned int participationType;
|
|
||||||
int timeSlice;
|
|
||||||
} GLXHyperpipeConfigSGIX;
|
|
||||||
typedef struct {
|
|
||||||
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
|
|
||||||
int srcXOrigin, srcYOrigin, srcWidth, srcHeight;
|
|
||||||
int destXOrigin, destYOrigin, destWidth, destHeight;
|
|
||||||
} GLXPipeRect;
|
|
||||||
typedef struct {
|
|
||||||
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
|
|
||||||
int XOrigin, YOrigin, maxHeight, maxWidth;
|
|
||||||
} GLXPipeRectLimits;
|
|
||||||
#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80
|
|
||||||
#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91
|
|
||||||
#define GLX_BAD_HYPERPIPE_SGIX 92
|
|
||||||
#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001
|
|
||||||
#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002
|
|
||||||
#define GLX_PIPE_RECT_SGIX 0x00000001
|
|
||||||
#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002
|
|
||||||
#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003
|
|
||||||
#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004
|
|
||||||
#define GLX_HYPERPIPE_ID_SGIX 0x8030
|
|
||||||
typedef GLXHyperpipeNetworkSGIX *( *PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes);
|
|
||||||
typedef int ( *PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
|
|
||||||
typedef GLXHyperpipeConfigSGIX *( *PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes);
|
|
||||||
typedef int ( *PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId);
|
|
||||||
typedef int ( *PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId);
|
|
||||||
typedef int ( *PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
|
|
||||||
typedef int ( *PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
|
|
||||||
typedef int ( *PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
GLXHyperpipeNetworkSGIX *glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes);
|
|
||||||
int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
|
|
||||||
GLXHyperpipeConfigSGIX *glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes);
|
|
||||||
int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId);
|
|
||||||
int glXBindHyperpipeSGIX (Display *dpy, int hpId);
|
|
||||||
int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
|
|
||||||
int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
|
|
||||||
int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGIX_hyperpipe */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_pbuffer
|
|
||||||
#define GLX_SGIX_pbuffer 1
|
|
||||||
#define GLX_PBUFFER_BIT_SGIX 0x00000004
|
|
||||||
#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000
|
|
||||||
#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001
|
|
||||||
#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002
|
|
||||||
#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004
|
|
||||||
#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008
|
|
||||||
#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010
|
|
||||||
#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020
|
|
||||||
#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040
|
|
||||||
#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080
|
|
||||||
#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100
|
|
||||||
#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016
|
|
||||||
#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017
|
|
||||||
#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018
|
|
||||||
#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019
|
|
||||||
#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A
|
|
||||||
#define GLX_PRESERVED_CONTENTS_SGIX 0x801B
|
|
||||||
#define GLX_LARGEST_PBUFFER_SGIX 0x801C
|
|
||||||
#define GLX_WIDTH_SGIX 0x801D
|
|
||||||
#define GLX_HEIGHT_SGIX 0x801E
|
|
||||||
#define GLX_EVENT_MASK_SGIX 0x801F
|
|
||||||
#define GLX_DAMAGED_SGIX 0x8020
|
|
||||||
#define GLX_SAVED_SGIX 0x8021
|
|
||||||
#define GLX_WINDOW_SGIX 0x8022
|
|
||||||
#define GLX_PBUFFER_SGIX 0x8023
|
|
||||||
typedef GLXPbufferSGIX ( *PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
|
|
||||||
typedef void ( *PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf);
|
|
||||||
typedef int ( *PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
|
|
||||||
typedef void ( *PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask);
|
|
||||||
typedef void ( *PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
|
|
||||||
void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf);
|
|
||||||
int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
|
|
||||||
void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask);
|
|
||||||
void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGIX_pbuffer */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_swap_barrier
|
|
||||||
#define GLX_SGIX_swap_barrier 1
|
|
||||||
typedef void ( *PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier);
|
|
||||||
typedef Bool ( *PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier);
|
|
||||||
Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGIX_swap_barrier */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_swap_group
|
|
||||||
#define GLX_SGIX_swap_group 1
|
|
||||||
typedef void ( *PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGIX_swap_group */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_video_resize
|
|
||||||
#define GLX_SGIX_video_resize 1
|
|
||||||
#define GLX_SYNC_FRAME_SGIX 0x00000000
|
|
||||||
#define GLX_SYNC_SWAP_SGIX 0x00000001
|
|
||||||
typedef int ( *PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window);
|
|
||||||
typedef int ( *PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h);
|
|
||||||
typedef int ( *PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
|
|
||||||
typedef int ( *PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
|
|
||||||
typedef int ( *PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window);
|
|
||||||
int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h);
|
|
||||||
int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
|
|
||||||
int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
|
|
||||||
int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGIX_video_resize */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_video_source
|
|
||||||
#define GLX_SGIX_video_source 1
|
|
||||||
typedef XID GLXVideoSourceSGIX;
|
|
||||||
#ifdef _VL_H
|
|
||||||
typedef GLXVideoSourceSGIX ( *PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
|
|
||||||
typedef void ( *PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
|
|
||||||
void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource);
|
|
||||||
#endif
|
|
||||||
#endif /* _VL_H */
|
|
||||||
#endif /* GLX_SGIX_video_source */
|
|
||||||
|
|
||||||
#ifndef GLX_SGIX_visual_select_group
|
|
||||||
#define GLX_SGIX_visual_select_group 1
|
|
||||||
#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028
|
|
||||||
#endif /* GLX_SGIX_visual_select_group */
|
|
||||||
|
|
||||||
#ifndef GLX_SGI_cushion
|
|
||||||
#define GLX_SGI_cushion 1
|
|
||||||
typedef void ( *PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
void glXCushionSGI (Display *dpy, Window window, float cushion);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGI_cushion */
|
|
||||||
|
|
||||||
#ifndef GLX_SGI_make_current_read
|
|
||||||
#define GLX_SGI_make_current_read 1
|
|
||||||
typedef Bool ( *PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
|
|
||||||
typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
|
|
||||||
GLXDrawable glXGetCurrentReadDrawableSGI (void);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGI_make_current_read */
|
|
||||||
|
|
||||||
#ifndef GLX_SGI_swap_control
|
|
||||||
#define GLX_SGI_swap_control 1
|
|
||||||
typedef int ( *PFNGLXSWAPINTERVALSGIPROC) (int interval);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
int glXSwapIntervalSGI (int interval);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGI_swap_control */
|
|
||||||
|
|
||||||
#ifndef GLX_SGI_video_sync
|
|
||||||
#define GLX_SGI_video_sync 1
|
|
||||||
typedef int ( *PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count);
|
|
||||||
typedef int ( *PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
int glXGetVideoSyncSGI (unsigned int *count);
|
|
||||||
int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SGI_video_sync */
|
|
||||||
|
|
||||||
#ifndef GLX_SUN_get_transparent_index
|
|
||||||
#define GLX_SUN_get_transparent_index 1
|
|
||||||
typedef Status ( *PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex);
|
|
||||||
#ifdef GLX_GLXEXT_PROTOTYPES
|
|
||||||
Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex);
|
|
||||||
#endif
|
|
||||||
#endif /* GLX_SUN_get_transparent_index */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,840 +0,0 @@
|
||||||
#ifndef __wglext_h_
|
|
||||||
#define __wglext_h_ 1
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Copyright (c) 2013-2014 The Khronos Group Inc.
|
|
||||||
**
|
|
||||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
** copy of this software and/or associated documentation files (the
|
|
||||||
** "Materials"), to deal in the Materials without restriction, including
|
|
||||||
** without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
|
||||||
** permit persons to whom the Materials are furnished to do so, subject to
|
|
||||||
** the following conditions:
|
|
||||||
**
|
|
||||||
** The above copyright notice and this permission notice shall be included
|
|
||||||
** in all copies or substantial portions of the Materials.
|
|
||||||
**
|
|
||||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
** This header is generated from the Khronos OpenGL / OpenGL ES XML
|
|
||||||
** API Registry. The current version of the Registry, generator scripts
|
|
||||||
** used to make the header, and the header can be found at
|
|
||||||
** http://www.opengl.org/registry/
|
|
||||||
**
|
|
||||||
** Khronos $Revision: 27684 $ on $Date: 2014-08-11 01:21:35 -0700 (Mon, 11 Aug 2014) $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
|
||||||
#define WIN32_LEAN_AND_MEAN 1
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define WGL_WGLEXT_VERSION 20140810
|
|
||||||
|
|
||||||
/* Generated C header for:
|
|
||||||
* API: wgl
|
|
||||||
* Versions considered: .*
|
|
||||||
* Versions emitted: _nomatch_^
|
|
||||||
* Default extensions included: wgl
|
|
||||||
* Additional extensions included: _nomatch_^
|
|
||||||
* Extensions removed: _nomatch_^
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_buffer_region
|
|
||||||
#define WGL_ARB_buffer_region 1
|
|
||||||
#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001
|
|
||||||
#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002
|
|
||||||
#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004
|
|
||||||
#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008
|
|
||||||
typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType);
|
|
||||||
typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType);
|
|
||||||
VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion);
|
|
||||||
BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height);
|
|
||||||
BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_buffer_region */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_context_flush_control
|
|
||||||
#define WGL_ARB_context_flush_control 1
|
|
||||||
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
|
||||||
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
|
||||||
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
|
||||||
#endif /* WGL_ARB_context_flush_control */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_create_context
|
|
||||||
#define WGL_ARB_create_context 1
|
|
||||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
|
||||||
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
|
||||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
||||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
||||||
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
|
||||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
|
||||||
#define ERROR_INVALID_VERSION_ARB 0x2095
|
|
||||||
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_create_context */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_create_context_profile
|
|
||||||
#define WGL_ARB_create_context_profile 1
|
|
||||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
||||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
||||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
|
||||||
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
|
||||||
#endif /* WGL_ARB_create_context_profile */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_create_context_robustness
|
|
||||||
#define WGL_ARB_create_context_robustness 1
|
|
||||||
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
|
||||||
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
|
||||||
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
|
||||||
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
|
|
||||||
#endif /* WGL_ARB_create_context_robustness */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_extensions_string
|
|
||||||
#define WGL_ARB_extensions_string 1
|
|
||||||
typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
const char *WINAPI wglGetExtensionsStringARB (HDC hdc);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_extensions_string */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_framebuffer_sRGB
|
|
||||||
#define WGL_ARB_framebuffer_sRGB 1
|
|
||||||
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
|
|
||||||
#endif /* WGL_ARB_framebuffer_sRGB */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_make_current_read
|
|
||||||
#define WGL_ARB_make_current_read 1
|
|
||||||
#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043
|
|
||||||
#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
|
|
||||||
typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
|
|
||||||
typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
|
|
||||||
HDC WINAPI wglGetCurrentReadDCARB (void);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_make_current_read */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_multisample
|
|
||||||
#define WGL_ARB_multisample 1
|
|
||||||
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
|
||||||
#define WGL_SAMPLES_ARB 0x2042
|
|
||||||
#endif /* WGL_ARB_multisample */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_pbuffer
|
|
||||||
#define WGL_ARB_pbuffer 1
|
|
||||||
DECLARE_HANDLE(HPBUFFERARB);
|
|
||||||
#define WGL_DRAW_TO_PBUFFER_ARB 0x202D
|
|
||||||
#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
|
|
||||||
#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F
|
|
||||||
#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
|
|
||||||
#define WGL_PBUFFER_LARGEST_ARB 0x2033
|
|
||||||
#define WGL_PBUFFER_WIDTH_ARB 0x2034
|
|
||||||
#define WGL_PBUFFER_HEIGHT_ARB 0x2035
|
|
||||||
#define WGL_PBUFFER_LOST_ARB 0x2036
|
|
||||||
typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
|
|
||||||
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer);
|
|
||||||
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
|
|
||||||
HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer);
|
|
||||||
int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC);
|
|
||||||
BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer);
|
|
||||||
BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_pbuffer */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_pixel_format
|
|
||||||
#define WGL_ARB_pixel_format 1
|
|
||||||
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
|
||||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
|
||||||
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
|
|
||||||
#define WGL_ACCELERATION_ARB 0x2003
|
|
||||||
#define WGL_NEED_PALETTE_ARB 0x2004
|
|
||||||
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
|
|
||||||
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
|
|
||||||
#define WGL_SWAP_METHOD_ARB 0x2007
|
|
||||||
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
|
|
||||||
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
|
|
||||||
#define WGL_TRANSPARENT_ARB 0x200A
|
|
||||||
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
|
|
||||||
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
|
|
||||||
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
|
|
||||||
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
|
|
||||||
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
|
|
||||||
#define WGL_SHARE_DEPTH_ARB 0x200C
|
|
||||||
#define WGL_SHARE_STENCIL_ARB 0x200D
|
|
||||||
#define WGL_SHARE_ACCUM_ARB 0x200E
|
|
||||||
#define WGL_SUPPORT_GDI_ARB 0x200F
|
|
||||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
|
||||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
|
||||||
#define WGL_STEREO_ARB 0x2012
|
|
||||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
|
||||||
#define WGL_COLOR_BITS_ARB 0x2014
|
|
||||||
#define WGL_RED_BITS_ARB 0x2015
|
|
||||||
#define WGL_RED_SHIFT_ARB 0x2016
|
|
||||||
#define WGL_GREEN_BITS_ARB 0x2017
|
|
||||||
#define WGL_GREEN_SHIFT_ARB 0x2018
|
|
||||||
#define WGL_BLUE_BITS_ARB 0x2019
|
|
||||||
#define WGL_BLUE_SHIFT_ARB 0x201A
|
|
||||||
#define WGL_ALPHA_BITS_ARB 0x201B
|
|
||||||
#define WGL_ALPHA_SHIFT_ARB 0x201C
|
|
||||||
#define WGL_ACCUM_BITS_ARB 0x201D
|
|
||||||
#define WGL_ACCUM_RED_BITS_ARB 0x201E
|
|
||||||
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
|
|
||||||
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
|
|
||||||
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
|
|
||||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
|
||||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
|
||||||
#define WGL_AUX_BUFFERS_ARB 0x2024
|
|
||||||
#define WGL_NO_ACCELERATION_ARB 0x2025
|
|
||||||
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
|
|
||||||
#define WGL_FULL_ACCELERATION_ARB 0x2027
|
|
||||||
#define WGL_SWAP_EXCHANGE_ARB 0x2028
|
|
||||||
#define WGL_SWAP_COPY_ARB 0x2029
|
|
||||||
#define WGL_SWAP_UNDEFINED_ARB 0x202A
|
|
||||||
#define WGL_TYPE_RGBA_ARB 0x202B
|
|
||||||
#define WGL_TYPE_COLORINDEX_ARB 0x202C
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
|
|
||||||
BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
|
|
||||||
BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_pixel_format */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_pixel_format_float
|
|
||||||
#define WGL_ARB_pixel_format_float 1
|
|
||||||
#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0
|
|
||||||
#endif /* WGL_ARB_pixel_format_float */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_render_texture
|
|
||||||
#define WGL_ARB_render_texture 1
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
|
|
||||||
#define WGL_TEXTURE_FORMAT_ARB 0x2072
|
|
||||||
#define WGL_TEXTURE_TARGET_ARB 0x2073
|
|
||||||
#define WGL_MIPMAP_TEXTURE_ARB 0x2074
|
|
||||||
#define WGL_TEXTURE_RGB_ARB 0x2075
|
|
||||||
#define WGL_TEXTURE_RGBA_ARB 0x2076
|
|
||||||
#define WGL_NO_TEXTURE_ARB 0x2077
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078
|
|
||||||
#define WGL_TEXTURE_1D_ARB 0x2079
|
|
||||||
#define WGL_TEXTURE_2D_ARB 0x207A
|
|
||||||
#define WGL_MIPMAP_LEVEL_ARB 0x207B
|
|
||||||
#define WGL_CUBE_MAP_FACE_ARB 0x207C
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081
|
|
||||||
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082
|
|
||||||
#define WGL_FRONT_LEFT_ARB 0x2083
|
|
||||||
#define WGL_FRONT_RIGHT_ARB 0x2084
|
|
||||||
#define WGL_BACK_LEFT_ARB 0x2085
|
|
||||||
#define WGL_BACK_RIGHT_ARB 0x2086
|
|
||||||
#define WGL_AUX0_ARB 0x2087
|
|
||||||
#define WGL_AUX1_ARB 0x2088
|
|
||||||
#define WGL_AUX2_ARB 0x2089
|
|
||||||
#define WGL_AUX3_ARB 0x208A
|
|
||||||
#define WGL_AUX4_ARB 0x208B
|
|
||||||
#define WGL_AUX5_ARB 0x208C
|
|
||||||
#define WGL_AUX6_ARB 0x208D
|
|
||||||
#define WGL_AUX7_ARB 0x208E
|
|
||||||
#define WGL_AUX8_ARB 0x208F
|
|
||||||
#define WGL_AUX9_ARB 0x2090
|
|
||||||
typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer);
|
|
||||||
BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer);
|
|
||||||
BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_ARB_render_texture */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_robustness_application_isolation
|
|
||||||
#define WGL_ARB_robustness_application_isolation 1
|
|
||||||
#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
|
|
||||||
#endif /* WGL_ARB_robustness_application_isolation */
|
|
||||||
|
|
||||||
#ifndef WGL_ARB_robustness_share_group_isolation
|
|
||||||
#define WGL_ARB_robustness_share_group_isolation 1
|
|
||||||
#endif /* WGL_ARB_robustness_share_group_isolation */
|
|
||||||
|
|
||||||
#ifndef WGL_3DFX_multisample
|
|
||||||
#define WGL_3DFX_multisample 1
|
|
||||||
#define WGL_SAMPLE_BUFFERS_3DFX 0x2060
|
|
||||||
#define WGL_SAMPLES_3DFX 0x2061
|
|
||||||
#endif /* WGL_3DFX_multisample */
|
|
||||||
|
|
||||||
#ifndef WGL_3DL_stereo_control
|
|
||||||
#define WGL_3DL_stereo_control 1
|
|
||||||
#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055
|
|
||||||
#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056
|
|
||||||
#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057
|
|
||||||
#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_3DL_stereo_control */
|
|
||||||
|
|
||||||
#ifndef WGL_AMD_gpu_association
|
|
||||||
#define WGL_AMD_gpu_association 1
|
|
||||||
#define WGL_GPU_VENDOR_AMD 0x1F00
|
|
||||||
#define WGL_GPU_RENDERER_STRING_AMD 0x1F01
|
|
||||||
#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02
|
|
||||||
#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2
|
|
||||||
#define WGL_GPU_RAM_AMD 0x21A3
|
|
||||||
#define WGL_GPU_CLOCK_AMD 0x21A4
|
|
||||||
#define WGL_GPU_NUM_PIPES_AMD 0x21A5
|
|
||||||
#define WGL_GPU_NUM_SIMD_AMD 0x21A6
|
|
||||||
#define WGL_GPU_NUM_RB_AMD 0x21A7
|
|
||||||
#define WGL_GPU_NUM_SPI_AMD 0x21A8
|
|
||||||
typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids);
|
|
||||||
typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data);
|
|
||||||
typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc);
|
|
||||||
typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id);
|
|
||||||
typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc);
|
|
||||||
typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);
|
|
||||||
typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids);
|
|
||||||
INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data);
|
|
||||||
UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc);
|
|
||||||
HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id);
|
|
||||||
HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList);
|
|
||||||
BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc);
|
|
||||||
BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc);
|
|
||||||
HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void);
|
|
||||||
VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_AMD_gpu_association */
|
|
||||||
|
|
||||||
#ifndef WGL_ATI_pixel_format_float
|
|
||||||
#define WGL_ATI_pixel_format_float 1
|
|
||||||
#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0
|
|
||||||
#endif /* WGL_ATI_pixel_format_float */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_create_context_es2_profile
|
|
||||||
#define WGL_EXT_create_context_es2_profile 1
|
|
||||||
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
|
||||||
#endif /* WGL_EXT_create_context_es2_profile */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_create_context_es_profile
|
|
||||||
#define WGL_EXT_create_context_es_profile 1
|
|
||||||
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
|
|
||||||
#endif /* WGL_EXT_create_context_es_profile */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_depth_float
|
|
||||||
#define WGL_EXT_depth_float 1
|
|
||||||
#define WGL_DEPTH_FLOAT_EXT 0x2040
|
|
||||||
#endif /* WGL_EXT_depth_float */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_display_color_table
|
|
||||||
#define WGL_EXT_display_color_table 1
|
|
||||||
typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id);
|
|
||||||
typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length);
|
|
||||||
typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id);
|
|
||||||
typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id);
|
|
||||||
GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length);
|
|
||||||
GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id);
|
|
||||||
VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_EXT_display_color_table */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_extensions_string
|
|
||||||
#define WGL_EXT_extensions_string 1
|
|
||||||
typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
const char *WINAPI wglGetExtensionsStringEXT (void);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_EXT_extensions_string */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_framebuffer_sRGB
|
|
||||||
#define WGL_EXT_framebuffer_sRGB 1
|
|
||||||
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9
|
|
||||||
#endif /* WGL_EXT_framebuffer_sRGB */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_make_current_read
|
|
||||||
#define WGL_EXT_make_current_read 1
|
|
||||||
#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043
|
|
||||||
typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
|
|
||||||
typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
|
|
||||||
HDC WINAPI wglGetCurrentReadDCEXT (void);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_EXT_make_current_read */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_multisample
|
|
||||||
#define WGL_EXT_multisample 1
|
|
||||||
#define WGL_SAMPLE_BUFFERS_EXT 0x2041
|
|
||||||
#define WGL_SAMPLES_EXT 0x2042
|
|
||||||
#endif /* WGL_EXT_multisample */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_pbuffer
|
|
||||||
#define WGL_EXT_pbuffer 1
|
|
||||||
DECLARE_HANDLE(HPBUFFEREXT);
|
|
||||||
#define WGL_DRAW_TO_PBUFFER_EXT 0x202D
|
|
||||||
#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E
|
|
||||||
#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F
|
|
||||||
#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030
|
|
||||||
#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031
|
|
||||||
#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032
|
|
||||||
#define WGL_PBUFFER_LARGEST_EXT 0x2033
|
|
||||||
#define WGL_PBUFFER_WIDTH_EXT 0x2034
|
|
||||||
#define WGL_PBUFFER_HEIGHT_EXT 0x2035
|
|
||||||
typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
|
|
||||||
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer);
|
|
||||||
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
|
|
||||||
HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer);
|
|
||||||
int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC);
|
|
||||||
BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer);
|
|
||||||
BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_EXT_pbuffer */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_pixel_format
|
|
||||||
#define WGL_EXT_pixel_format 1
|
|
||||||
#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000
|
|
||||||
#define WGL_DRAW_TO_WINDOW_EXT 0x2001
|
|
||||||
#define WGL_DRAW_TO_BITMAP_EXT 0x2002
|
|
||||||
#define WGL_ACCELERATION_EXT 0x2003
|
|
||||||
#define WGL_NEED_PALETTE_EXT 0x2004
|
|
||||||
#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005
|
|
||||||
#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006
|
|
||||||
#define WGL_SWAP_METHOD_EXT 0x2007
|
|
||||||
#define WGL_NUMBER_OVERLAYS_EXT 0x2008
|
|
||||||
#define WGL_NUMBER_UNDERLAYS_EXT 0x2009
|
|
||||||
#define WGL_TRANSPARENT_EXT 0x200A
|
|
||||||
#define WGL_TRANSPARENT_VALUE_EXT 0x200B
|
|
||||||
#define WGL_SHARE_DEPTH_EXT 0x200C
|
|
||||||
#define WGL_SHARE_STENCIL_EXT 0x200D
|
|
||||||
#define WGL_SHARE_ACCUM_EXT 0x200E
|
|
||||||
#define WGL_SUPPORT_GDI_EXT 0x200F
|
|
||||||
#define WGL_SUPPORT_OPENGL_EXT 0x2010
|
|
||||||
#define WGL_DOUBLE_BUFFER_EXT 0x2011
|
|
||||||
#define WGL_STEREO_EXT 0x2012
|
|
||||||
#define WGL_PIXEL_TYPE_EXT 0x2013
|
|
||||||
#define WGL_COLOR_BITS_EXT 0x2014
|
|
||||||
#define WGL_RED_BITS_EXT 0x2015
|
|
||||||
#define WGL_RED_SHIFT_EXT 0x2016
|
|
||||||
#define WGL_GREEN_BITS_EXT 0x2017
|
|
||||||
#define WGL_GREEN_SHIFT_EXT 0x2018
|
|
||||||
#define WGL_BLUE_BITS_EXT 0x2019
|
|
||||||
#define WGL_BLUE_SHIFT_EXT 0x201A
|
|
||||||
#define WGL_ALPHA_BITS_EXT 0x201B
|
|
||||||
#define WGL_ALPHA_SHIFT_EXT 0x201C
|
|
||||||
#define WGL_ACCUM_BITS_EXT 0x201D
|
|
||||||
#define WGL_ACCUM_RED_BITS_EXT 0x201E
|
|
||||||
#define WGL_ACCUM_GREEN_BITS_EXT 0x201F
|
|
||||||
#define WGL_ACCUM_BLUE_BITS_EXT 0x2020
|
|
||||||
#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021
|
|
||||||
#define WGL_DEPTH_BITS_EXT 0x2022
|
|
||||||
#define WGL_STENCIL_BITS_EXT 0x2023
|
|
||||||
#define WGL_AUX_BUFFERS_EXT 0x2024
|
|
||||||
#define WGL_NO_ACCELERATION_EXT 0x2025
|
|
||||||
#define WGL_GENERIC_ACCELERATION_EXT 0x2026
|
|
||||||
#define WGL_FULL_ACCELERATION_EXT 0x2027
|
|
||||||
#define WGL_SWAP_EXCHANGE_EXT 0x2028
|
|
||||||
#define WGL_SWAP_COPY_EXT 0x2029
|
|
||||||
#define WGL_SWAP_UNDEFINED_EXT 0x202A
|
|
||||||
#define WGL_TYPE_RGBA_EXT 0x202B
|
|
||||||
#define WGL_TYPE_COLORINDEX_EXT 0x202C
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);
|
|
||||||
BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);
|
|
||||||
BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_EXT_pixel_format */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_pixel_format_packed_float
|
|
||||||
#define WGL_EXT_pixel_format_packed_float 1
|
|
||||||
#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8
|
|
||||||
#endif /* WGL_EXT_pixel_format_packed_float */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_swap_control
|
|
||||||
#define WGL_EXT_swap_control 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
|
|
||||||
typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglSwapIntervalEXT (int interval);
|
|
||||||
int WINAPI wglGetSwapIntervalEXT (void);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_EXT_swap_control */
|
|
||||||
|
|
||||||
#ifndef WGL_EXT_swap_control_tear
|
|
||||||
#define WGL_EXT_swap_control_tear 1
|
|
||||||
#endif /* WGL_EXT_swap_control_tear */
|
|
||||||
|
|
||||||
#ifndef WGL_I3D_digital_video_control
|
|
||||||
#define WGL_I3D_digital_video_control 1
|
|
||||||
#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050
|
|
||||||
#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051
|
|
||||||
#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052
|
|
||||||
#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue);
|
|
||||||
BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_I3D_digital_video_control */
|
|
||||||
|
|
||||||
#ifndef WGL_I3D_gamma
|
|
||||||
#define WGL_I3D_gamma 1
|
|
||||||
#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E
|
|
||||||
#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue);
|
|
||||||
BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue);
|
|
||||||
BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);
|
|
||||||
BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_I3D_gamma */
|
|
||||||
|
|
||||||
#ifndef WGL_I3D_genlock
|
|
||||||
#define WGL_I3D_genlock 1
|
|
||||||
#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044
|
|
||||||
#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045
|
|
||||||
#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046
|
|
||||||
#define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047
|
|
||||||
#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048
|
|
||||||
#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049
|
|
||||||
#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A
|
|
||||||
#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B
|
|
||||||
#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C
|
|
||||||
typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglEnableGenlockI3D (HDC hDC);
|
|
||||||
BOOL WINAPI wglDisableGenlockI3D (HDC hDC);
|
|
||||||
BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag);
|
|
||||||
BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource);
|
|
||||||
BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource);
|
|
||||||
BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge);
|
|
||||||
BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge);
|
|
||||||
BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate);
|
|
||||||
BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate);
|
|
||||||
BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay);
|
|
||||||
BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay);
|
|
||||||
BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_I3D_genlock */
|
|
||||||
|
|
||||||
#ifndef WGL_I3D_image_buffer
|
|
||||||
#define WGL_I3D_image_buffer 1
|
|
||||||
#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001
|
|
||||||
#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002
|
|
||||||
typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags);
|
|
||||||
BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress);
|
|
||||||
BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);
|
|
||||||
BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_I3D_image_buffer */
|
|
||||||
|
|
||||||
#ifndef WGL_I3D_swap_frame_lock
|
|
||||||
#define WGL_I3D_swap_frame_lock 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglEnableFrameLockI3D (void);
|
|
||||||
BOOL WINAPI wglDisableFrameLockI3D (void);
|
|
||||||
BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag);
|
|
||||||
BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_I3D_swap_frame_lock */
|
|
||||||
|
|
||||||
#ifndef WGL_I3D_swap_frame_usage
|
|
||||||
#define WGL_I3D_swap_frame_usage 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetFrameUsageI3D (float *pUsage);
|
|
||||||
BOOL WINAPI wglBeginFrameTrackingI3D (void);
|
|
||||||
BOOL WINAPI wglEndFrameTrackingI3D (void);
|
|
||||||
BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_I3D_swap_frame_usage */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_DX_interop
|
|
||||||
#define WGL_NV_DX_interop 1
|
|
||||||
#define WGL_ACCESS_READ_ONLY_NV 0x00000000
|
|
||||||
#define WGL_ACCESS_READ_WRITE_NV 0x00000001
|
|
||||||
#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle);
|
|
||||||
typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice);
|
|
||||||
typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle);
|
|
||||||
HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice);
|
|
||||||
BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice);
|
|
||||||
HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
|
|
||||||
BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject);
|
|
||||||
BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access);
|
|
||||||
BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects);
|
|
||||||
BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_DX_interop */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_DX_interop2
|
|
||||||
#define WGL_NV_DX_interop2 1
|
|
||||||
#endif /* WGL_NV_DX_interop2 */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_copy_image
|
|
||||||
#define WGL_NV_copy_image 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_copy_image */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_delay_before_swap
|
|
||||||
#define WGL_NV_delay_before_swap 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_delay_before_swap */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_float_buffer
|
|
||||||
#define WGL_NV_float_buffer 1
|
|
||||||
#define WGL_FLOAT_COMPONENTS_NV 0x20B0
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4
|
|
||||||
#define WGL_TEXTURE_FLOAT_R_NV 0x20B5
|
|
||||||
#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6
|
|
||||||
#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7
|
|
||||||
#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8
|
|
||||||
#endif /* WGL_NV_float_buffer */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_gpu_affinity
|
|
||||||
#define WGL_NV_gpu_affinity 1
|
|
||||||
DECLARE_HANDLE(HGPUNV);
|
|
||||||
struct _GPU_DEVICE {
|
|
||||||
DWORD cb;
|
|
||||||
CHAR DeviceName[32];
|
|
||||||
CHAR DeviceString[128];
|
|
||||||
DWORD Flags;
|
|
||||||
RECT rcVirtualScreen;
|
|
||||||
};
|
|
||||||
typedef struct _GPU_DEVICE *PGPU_DEVICE;
|
|
||||||
#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0
|
|
||||||
#define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice);
|
|
||||||
typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu);
|
|
||||||
BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice);
|
|
||||||
HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList);
|
|
||||||
BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu);
|
|
||||||
BOOL WINAPI wglDeleteDCNV (HDC hdc);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_gpu_affinity */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_multisample_coverage
|
|
||||||
#define WGL_NV_multisample_coverage 1
|
|
||||||
#define WGL_COVERAGE_SAMPLES_NV 0x2042
|
|
||||||
#define WGL_COLOR_SAMPLES_NV 0x20B9
|
|
||||||
#endif /* WGL_NV_multisample_coverage */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_present_video
|
|
||||||
#define WGL_NV_present_video 1
|
|
||||||
DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);
|
|
||||||
#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0
|
|
||||||
typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
|
|
||||||
BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
|
|
||||||
BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_present_video */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_render_depth_texture
|
|
||||||
#define WGL_NV_render_depth_texture 1
|
|
||||||
#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4
|
|
||||||
#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5
|
|
||||||
#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6
|
|
||||||
#define WGL_DEPTH_COMPONENT_NV 0x20A7
|
|
||||||
#endif /* WGL_NV_render_depth_texture */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_render_texture_rectangle
|
|
||||||
#define WGL_NV_render_texture_rectangle 1
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0
|
|
||||||
#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1
|
|
||||||
#define WGL_TEXTURE_RECTANGLE_NV 0x20A2
|
|
||||||
#endif /* WGL_NV_render_texture_rectangle */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_swap_group
|
|
||||||
#define WGL_NV_swap_group 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group);
|
|
||||||
BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier);
|
|
||||||
BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier);
|
|
||||||
BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers);
|
|
||||||
BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count);
|
|
||||||
BOOL WINAPI wglResetFrameCountNV (HDC hDC);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_swap_group */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_vertex_array_range
|
|
||||||
#define WGL_NV_vertex_array_range 1
|
|
||||||
typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
|
|
||||||
typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
void *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
|
|
||||||
void WINAPI wglFreeMemoryNV (void *pointer);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_vertex_array_range */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_video_capture
|
|
||||||
#define WGL_NV_video_capture 1
|
|
||||||
DECLARE_HANDLE(HVIDEOINPUTDEVICENV);
|
|
||||||
#define WGL_UNIQUE_ID_NV 0x20CE
|
|
||||||
#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF
|
|
||||||
typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice);
|
|
||||||
typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice);
|
|
||||||
UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList);
|
|
||||||
BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
|
|
||||||
BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue);
|
|
||||||
BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_video_capture */
|
|
||||||
|
|
||||||
#ifndef WGL_NV_video_output
|
|
||||||
#define WGL_NV_video_output 1
|
|
||||||
DECLARE_HANDLE(HPVIDEODEV);
|
|
||||||
#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0
|
|
||||||
#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1
|
|
||||||
#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2
|
|
||||||
#define WGL_VIDEO_OUT_COLOR_NV 0x20C3
|
|
||||||
#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4
|
|
||||||
#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5
|
|
||||||
#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6
|
|
||||||
#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7
|
|
||||||
#define WGL_VIDEO_OUT_FRAME 0x20C8
|
|
||||||
#define WGL_VIDEO_OUT_FIELD_1 0x20C9
|
|
||||||
#define WGL_VIDEO_OUT_FIELD_2 0x20CA
|
|
||||||
#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB
|
|
||||||
#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice);
|
|
||||||
BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice);
|
|
||||||
BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer);
|
|
||||||
BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer);
|
|
||||||
BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock);
|
|
||||||
BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_NV_video_output */
|
|
||||||
|
|
||||||
#ifndef WGL_OML_sync_control
|
|
||||||
#define WGL_OML_sync_control 1
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);
|
|
||||||
typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
|
|
||||||
typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
|
|
||||||
typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
|
|
||||||
#ifdef WGL_WGLEXT_PROTOTYPES
|
|
||||||
BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
|
|
||||||
BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator);
|
|
||||||
INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
|
|
||||||
INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
|
|
||||||
BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
|
|
||||||
BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
|
|
||||||
#endif
|
|
||||||
#endif /* WGL_OML_sync_control */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,55 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
|
||||||
# Visual Studio 2008
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crunch", "crunch\crunch.2008.vcproj", "{8F645BA1-B996-49EB-859B-970A671DE05D}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664} = {CF2E70E8-7133-4D96-92C7-68BB406C0664}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crnlib", "crnlib\crnlib.2008.vcproj", "{CF2E70E8-7133-4D96-92C7-68BB406C0664}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug_DLL|Win32 = Debug_DLL|Win32
|
|
||||||
Debug_DLL|x64 = Debug_DLL|x64
|
|
||||||
Debug|Win32 = Debug|Win32
|
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Release_DLL|Win32 = Release_DLL|Win32
|
|
||||||
Release_DLL|x64 = Release_DLL|x64
|
|
||||||
Release|Win32 = Release|Win32
|
|
||||||
Release|x64 = Release|x64
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug_DLL|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug_DLL|x64.ActiveCfg = Debug|x64
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release_DLL|Win32.ActiveCfg = Release|Win32
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release_DLL|x64.ActiveCfg = Release|x64
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|x64.Build.0 = Release|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|x64.Build.0 = Release_DLL|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|x64.Build.0 = Release|x64
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
||||||
<CodeBlocks_workspace_file>
|
|
||||||
<Workspace title="Workspace">
|
|
||||||
<Project filename="crunch/crunch.cbp" active="1">
|
|
||||||
<Depends filename="crnlib/crnlib.cbp" />
|
|
||||||
</Project>
|
|
||||||
<Project filename="crnlib/crnlib.cbp" />
|
|
||||||
</Workspace>
|
|
||||||
</CodeBlocks_workspace_file>
|
|
|
@ -1,74 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
|
||||||
# Visual Studio 2008
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example1", "example1\example1.2008.vcproj", "{8F745B42-F996-49EB-859B-970A671DE05D}"
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example2", "example2\example2.2008.vcproj", "{AF745B42-F996-49EB-859B-970A671DEF5E}"
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example3", "example3\example3.2008.vcproj", "{AF745B42-E296-46EB-859B-970A671DEF5E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug_DLL|Win32 = Debug_DLL|Win32
|
|
||||||
Debug_DLL|x64 = Debug_DLL|x64
|
|
||||||
Debug|Win32 = Debug|Win32
|
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Release_DLL|Win32 = Release_DLL|Win32
|
|
||||||
Release_DLL|x64 = Release_DLL|x64
|
|
||||||
Release|Win32 = Release|Win32
|
|
||||||
Release|x64 = Release|x64
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|x64.Build.0 = Release_DLL|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|x64.Build.0 = Release|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|x64.Build.0 = Release_DLL|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|x64.Build.0 = Release|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|x64.Build.0 = Release_DLL|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|x64.Build.0 = Release|x64
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
||||||
<CodeBlocks_workspace_file>
|
|
||||||
<Workspace title="Workspace">
|
|
||||||
<Project filename="crunch/crunch_linux.cbp" active="1">
|
|
||||||
<Depends filename="crnlib/crnlib_linux.cbp" />
|
|
||||||
</Project>
|
|
||||||
<Project filename="crnlib/crnlib_linux.cbp" />
|
|
||||||
</Workspace>
|
|
||||||
</CodeBlocks_workspace_file>
|
|
|
@ -1,96 +0,0 @@
|
||||||
COMPILE_OPTIONS = -O3 -fomit-frame-pointer -ffast-math -fno-math-errno -g -fno-strict-aliasing -Wall -Wno-unused-value -Wno-unused -march=core2
|
|
||||||
LINKER_OPTIONS = -lpthread -g
|
|
||||||
|
|
||||||
OBJECTS = \
|
|
||||||
crn_arealist.o \
|
|
||||||
crn_assert.o \
|
|
||||||
crn_checksum.o \
|
|
||||||
crn_colorized_console.o \
|
|
||||||
crn_command_line_params.o \
|
|
||||||
crn_comp.o \
|
|
||||||
crn_console.o \
|
|
||||||
crn_core.o \
|
|
||||||
crn_data_stream.o \
|
|
||||||
crn_mipmapped_texture.o \
|
|
||||||
crn_decomp.o \
|
|
||||||
crn_dxt1.o \
|
|
||||||
crn_dxt5a.o \
|
|
||||||
crn_dxt.o \
|
|
||||||
crn_dxt_endpoint_refiner.o \
|
|
||||||
crn_dxt_fast.o \
|
|
||||||
crn_dxt_hc_common.o \
|
|
||||||
crn_dxt_hc.o \
|
|
||||||
crn_dxt_image.o \
|
|
||||||
crn_dynamic_string.o \
|
|
||||||
crn_file_utils.o \
|
|
||||||
crn_find_files.o \
|
|
||||||
crn_hash.o \
|
|
||||||
crn_hash_map.o \
|
|
||||||
crn_huffman_codes.o \
|
|
||||||
crn_image_utils.o \
|
|
||||||
crnlib.o \
|
|
||||||
crn_math.o \
|
|
||||||
crn_mem.o \
|
|
||||||
crn_pixel_format.o \
|
|
||||||
crn_platform.o \
|
|
||||||
crn_prefix_coding.o \
|
|
||||||
crn_qdxt1.o \
|
|
||||||
crn_qdxt5.o \
|
|
||||||
crn_rand.o \
|
|
||||||
crn_resample_filters.o \
|
|
||||||
crn_resampler.o \
|
|
||||||
crn_ryg_dxt.o \
|
|
||||||
crn_sparse_bit_array.o \
|
|
||||||
crn_stb_image.o \
|
|
||||||
crn_strutils.o \
|
|
||||||
crn_symbol_codec.o \
|
|
||||||
crn_texture_file_types.o \
|
|
||||||
crn_threaded_resampler.o \
|
|
||||||
crn_threading_pthreads.o \
|
|
||||||
crn_timer.o \
|
|
||||||
crn_utils.o \
|
|
||||||
crn_value.o \
|
|
||||||
crn_vector.o \
|
|
||||||
crn_zeng.o \
|
|
||||||
crn_texture_comp.o \
|
|
||||||
crn_texture_conversion.o \
|
|
||||||
crn_dds_comp.o \
|
|
||||||
crn_lzma_codec.o \
|
|
||||||
crn_ktx_texture.o \
|
|
||||||
crn_etc.o \
|
|
||||||
crn_rg_etc1.o \
|
|
||||||
crn_miniz.o \
|
|
||||||
crn_jpge.o \
|
|
||||||
crn_jpgd.o \
|
|
||||||
lzma_7zBuf2.o \
|
|
||||||
lzma_7zBuf.o \
|
|
||||||
lzma_7zCrc.o \
|
|
||||||
lzma_7zFile.o \
|
|
||||||
lzma_7zStream.o \
|
|
||||||
lzma_Alloc.o \
|
|
||||||
lzma_Bcj2.o \
|
|
||||||
lzma_Bra86.o \
|
|
||||||
lzma_Bra.o \
|
|
||||||
lzma_BraIA64.o \
|
|
||||||
lzma_LzFind.o \
|
|
||||||
lzma_LzmaDec.o \
|
|
||||||
lzma_LzmaEnc.o \
|
|
||||||
lzma_LzmaLib.o
|
|
||||||
|
|
||||||
all: crunch
|
|
||||||
|
|
||||||
%.o: %.cpp
|
|
||||||
g++ $< -o $@ -c $(COMPILE_OPTIONS)
|
|
||||||
|
|
||||||
crunch.o: ../crunch/crunch.cpp
|
|
||||||
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
|
|
||||||
|
|
||||||
corpus_gen.o: ../crunch/corpus_gen.cpp
|
|
||||||
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
|
|
||||||
|
|
||||||
corpus_test.o: ../crunch/corpus_test.cpp
|
|
||||||
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
|
|
||||||
|
|
||||||
crunch: $(OBJECTS) crunch.o corpus_gen.o corpus_test.o
|
|
||||||
g++ $(OBJECTS) crunch.o corpus_gen.o corpus_test.o -o crunch $(LINKER_OPTIONS)
|
|
||||||
|
|
|
@ -1,698 +0,0 @@
|
||||||
// File: crn_arealist.cpp - 2D shape algebra (currently unused)
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
// Ported from the PowerView DOS image viewer, a product I wrote back in 1993. Not currently used in the open source release of crnlib.
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_arealist.h"
|
|
||||||
|
|
||||||
#define RECT_DEBUG
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
|
|
||||||
static void area_fatal_error(const char* pFunc, const char* pMsg, ...)
|
|
||||||
{
|
|
||||||
pFunc;
|
|
||||||
va_list args;
|
|
||||||
va_start(args, pMsg);
|
|
||||||
|
|
||||||
char buf[512];
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
_vsnprintf_s(buf, sizeof(buf), pMsg, args);
|
|
||||||
#else
|
|
||||||
vsnprintf(buf, sizeof(buf), pMsg, args);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
CRNLIB_FAIL(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Area * delete_area(Area_List *Plist, Area *Parea)
|
|
||||||
{
|
|
||||||
Area *p, *q;
|
|
||||||
|
|
||||||
#ifdef RECT_DEBUG
|
|
||||||
if ((Parea == Plist->Phead) || (Parea == Plist->Ptail))
|
|
||||||
area_fatal_error("delete_area", "tried to remove head or tail");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
p = Parea->Pprev;
|
|
||||||
q = Parea->Pnext;
|
|
||||||
p->Pnext = q;
|
|
||||||
q->Pprev = p;
|
|
||||||
|
|
||||||
Parea->Pnext = Plist->Pfree;
|
|
||||||
Parea->Pprev = NULL;
|
|
||||||
Plist->Pfree = Parea;
|
|
||||||
|
|
||||||
return (q);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Area * alloc_area(Area_List *Plist)
|
|
||||||
{
|
|
||||||
Area *p = Plist->Pfree;
|
|
||||||
|
|
||||||
if (p == NULL)
|
|
||||||
{
|
|
||||||
if (Plist->next_free == Plist->total_areas)
|
|
||||||
area_fatal_error("alloc_area", "Out of areas!");
|
|
||||||
|
|
||||||
p = Plist->Phead + Plist->next_free;
|
|
||||||
Plist->next_free++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Plist->Pfree = p->Pnext;
|
|
||||||
|
|
||||||
return (p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Area * insert_area_before(Area_List *Plist, Area *Parea,
|
|
||||||
int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
Area *p, *Pnew_area = alloc_area(Plist);
|
|
||||||
|
|
||||||
p = Parea->Pprev;
|
|
||||||
|
|
||||||
p->Pnext = Pnew_area;
|
|
||||||
|
|
||||||
Pnew_area->Pprev = p;
|
|
||||||
Pnew_area->Pnext = Parea;
|
|
||||||
|
|
||||||
Parea->Pprev = Pnew_area;
|
|
||||||
|
|
||||||
Pnew_area->x1 = x1;
|
|
||||||
Pnew_area->y1 = y1;
|
|
||||||
Pnew_area->x2 = x2;
|
|
||||||
Pnew_area->y2 = y2;
|
|
||||||
|
|
||||||
return (Pnew_area);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Area * insert_area_after(Area_List *Plist, Area *Parea,
|
|
||||||
int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
Area *p, *Pnew_area = alloc_area(Plist);
|
|
||||||
|
|
||||||
p = Parea->Pnext;
|
|
||||||
|
|
||||||
p->Pprev = Pnew_area;
|
|
||||||
|
|
||||||
Pnew_area->Pnext = p;
|
|
||||||
Pnew_area->Pprev = Parea;
|
|
||||||
|
|
||||||
Parea->Pnext = Pnew_area;
|
|
||||||
|
|
||||||
Pnew_area->x1 = x1;
|
|
||||||
Pnew_area->y1 = y1;
|
|
||||||
Pnew_area->x2 = x2;
|
|
||||||
Pnew_area->y2 = y2;
|
|
||||||
|
|
||||||
return (Pnew_area);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_deinit(Area_List* Pobj_base)
|
|
||||||
{
|
|
||||||
Area_List *Plist = (Area_List *)Pobj_base;
|
|
||||||
|
|
||||||
if (!Plist)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Plist->Phead)
|
|
||||||
{
|
|
||||||
crnlib_free(Plist->Phead);
|
|
||||||
Plist->Phead = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
crnlib_free(Plist);
|
|
||||||
}
|
|
||||||
|
|
||||||
Area_List * Area_List_init(int max_areas)
|
|
||||||
{
|
|
||||||
Area_List *Plist = (Area_List*)crnlib_calloc(1, sizeof(Area_List));
|
|
||||||
|
|
||||||
Plist->total_areas = max_areas + 2;
|
|
||||||
|
|
||||||
Plist->Phead = (Area *)crnlib_calloc(max_areas + 2, sizeof(Area));
|
|
||||||
Plist->Ptail = Plist->Phead + 1;
|
|
||||||
|
|
||||||
Plist->Phead->Pprev = NULL;
|
|
||||||
Plist->Phead->Pnext = Plist->Ptail;
|
|
||||||
|
|
||||||
Plist->Ptail->Pprev = Plist->Phead;
|
|
||||||
Plist->Ptail->Pnext = NULL;
|
|
||||||
|
|
||||||
Plist->Pfree = NULL;
|
|
||||||
Plist->next_free = 2;
|
|
||||||
|
|
||||||
return (Plist);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_print(Area_List *Plist)
|
|
||||||
{
|
|
||||||
Area *Parea = Plist->Phead->Pnext;
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
printf("%04i %04i : %04i %04i\n", Parea->x1, Parea->y1, Parea->x2, Parea->y2);
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Area_List * Area_List_dup_new(Area_List *Plist,
|
|
||||||
int x_ofs, int y_ofs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Area_List *Pnew_list = (Area_List*)crnlib_calloc(1, sizeof(Area_List));
|
|
||||||
|
|
||||||
Pnew_list->total_areas = Plist->total_areas;
|
|
||||||
|
|
||||||
Pnew_list->Phead = (Area *)crnlib_malloc(sizeof(Area) * Plist->total_areas);
|
|
||||||
Pnew_list->Ptail = Pnew_list->Phead + 1;
|
|
||||||
|
|
||||||
Pnew_list->Pfree = (Plist->Pfree) ? ((Plist->Pfree - Plist->Phead) + Pnew_list->Phead) : NULL;
|
|
||||||
|
|
||||||
Pnew_list->next_free = Plist->next_free;
|
|
||||||
|
|
||||||
memcpy(Pnew_list->Phead, Plist->Phead, sizeof(Area) * Plist->total_areas);
|
|
||||||
|
|
||||||
for (i = 0; i < Plist->total_areas; i++)
|
|
||||||
{
|
|
||||||
Pnew_list->Phead[i].Pnext = (Plist->Phead[i].Pnext == NULL) ? NULL : (Plist->Phead[i].Pnext - Plist->Phead) + Pnew_list->Phead;
|
|
||||||
Pnew_list->Phead[i].Pprev = (Plist->Phead[i].Pprev == NULL) ? NULL : (Plist->Phead[i].Pprev - Plist->Phead) + Pnew_list->Phead;
|
|
||||||
|
|
||||||
Pnew_list->Phead[i].x1 += x_ofs;
|
|
||||||
Pnew_list->Phead[i].y1 += y_ofs;
|
|
||||||
Pnew_list->Phead[i].x2 += x_ofs;
|
|
||||||
Pnew_list->Phead[i].y2 += y_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Pnew_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint Area_List_get_num(Area_List* Plist)
|
|
||||||
{
|
|
||||||
uint num = 0;
|
|
||||||
|
|
||||||
Area *Parea = Plist->Phead->Pnext;
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
num++;
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_dup(Area_List *Psrc_list, Area_List *Pdst_list,
|
|
||||||
int x_ofs, int y_ofs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (Psrc_list->total_areas != Pdst_list->total_areas)
|
|
||||||
area_fatal_error("Area_List_dup", "Src and Dst total_areas must be equal!");
|
|
||||||
|
|
||||||
Pdst_list->Pfree = (Psrc_list->Pfree) ? ((Psrc_list->Pfree - Psrc_list->Phead) + Pdst_list->Phead) : NULL;
|
|
||||||
|
|
||||||
Pdst_list->next_free = Psrc_list->next_free;
|
|
||||||
|
|
||||||
memcpy(Pdst_list->Phead, Psrc_list->Phead, sizeof(Area) * Psrc_list->total_areas);
|
|
||||||
|
|
||||||
if ((x_ofs) || (y_ofs))
|
|
||||||
{
|
|
||||||
for (i = 0; i < Psrc_list->total_areas; i++)
|
|
||||||
{
|
|
||||||
Pdst_list->Phead[i].Pnext = (Psrc_list->Phead[i].Pnext == NULL) ? NULL : (Psrc_list->Phead[i].Pnext - Psrc_list->Phead) + Pdst_list->Phead;
|
|
||||||
Pdst_list->Phead[i].Pprev = (Psrc_list->Phead[i].Pprev == NULL) ? NULL : (Psrc_list->Phead[i].Pprev - Psrc_list->Phead) + Pdst_list->Phead;
|
|
||||||
|
|
||||||
Pdst_list->Phead[i].x1 += x_ofs;
|
|
||||||
Pdst_list->Phead[i].y1 += y_ofs;
|
|
||||||
Pdst_list->Phead[i].x2 += x_ofs;
|
|
||||||
Pdst_list->Phead[i].y2 += y_ofs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < Psrc_list->total_areas; i++)
|
|
||||||
{
|
|
||||||
Pdst_list->Phead[i].Pnext = (Psrc_list->Phead[i].Pnext == NULL) ? NULL : (Psrc_list->Phead[i].Pnext - Psrc_list->Phead) + Pdst_list->Phead;
|
|
||||||
Pdst_list->Phead[i].Pprev = (Psrc_list->Phead[i].Pprev == NULL) ? NULL : (Psrc_list->Phead[i].Pprev - Psrc_list->Phead) + Pdst_list->Phead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_copy(
|
|
||||||
Area_List *Psrc_list, Area_List *Pdst_list,
|
|
||||||
int x_ofs, int y_ofs)
|
|
||||||
{
|
|
||||||
Area *Parea = Psrc_list->Phead->Pnext;
|
|
||||||
|
|
||||||
Area_List_clear(Pdst_list);
|
|
||||||
|
|
||||||
if ((x_ofs) || (y_ofs))
|
|
||||||
{
|
|
||||||
Area *Pprev_area = Pdst_list->Phead;
|
|
||||||
|
|
||||||
while (Parea != Psrc_list->Ptail)
|
|
||||||
{
|
|
||||||
// Area *p, *Pnew_area;
|
|
||||||
Area *Pnew_area;
|
|
||||||
|
|
||||||
if (Pdst_list->next_free == Pdst_list->total_areas)
|
|
||||||
area_fatal_error("Area_List_copy", "Out of areas!");
|
|
||||||
|
|
||||||
Pnew_area = Pdst_list->Phead + Pdst_list->next_free;
|
|
||||||
Pdst_list->next_free++;
|
|
||||||
|
|
||||||
Pnew_area->Pprev = Pprev_area;
|
|
||||||
Pprev_area->Pnext = Pnew_area;
|
|
||||||
|
|
||||||
Pnew_area->x1 = Parea->x1 + x_ofs;
|
|
||||||
Pnew_area->y1 = Parea->y1 + y_ofs;
|
|
||||||
Pnew_area->x2 = Parea->x2 + x_ofs;
|
|
||||||
Pnew_area->y2 = Parea->y2 + y_ofs;
|
|
||||||
|
|
||||||
Pprev_area = Pnew_area;
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pprev_area->Pnext = Pdst_list->Ptail;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
while (Parea != Psrc_list->Ptail)
|
|
||||||
{
|
|
||||||
insert_area_after(Pdst_list, Pdst_list->Phead,
|
|
||||||
Parea->x1,
|
|
||||||
Parea->y1,
|
|
||||||
Parea->x2,
|
|
||||||
Parea->y2);
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Area *Pprev_area = Pdst_list->Phead;
|
|
||||||
|
|
||||||
while (Parea != Psrc_list->Ptail)
|
|
||||||
{
|
|
||||||
// Area *p, *Pnew_area;
|
|
||||||
Area *Pnew_area;
|
|
||||||
|
|
||||||
if (Pdst_list->next_free == Pdst_list->total_areas)
|
|
||||||
area_fatal_error("Area_List_copy", "Out of areas!");
|
|
||||||
|
|
||||||
Pnew_area = Pdst_list->Phead + Pdst_list->next_free;
|
|
||||||
Pdst_list->next_free++;
|
|
||||||
|
|
||||||
Pnew_area->Pprev = Pprev_area;
|
|
||||||
Pprev_area->Pnext = Pnew_area;
|
|
||||||
|
|
||||||
Pnew_area->x1 = Parea->x1;
|
|
||||||
Pnew_area->y1 = Parea->y1;
|
|
||||||
Pnew_area->x2 = Parea->x2;
|
|
||||||
Pnew_area->y2 = Parea->y2;
|
|
||||||
|
|
||||||
Pprev_area = Pnew_area;
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pprev_area->Pnext = Pdst_list->Ptail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_clear(Area_List *Plist)
|
|
||||||
{
|
|
||||||
Plist->Phead->Pnext = Plist->Ptail;
|
|
||||||
Plist->Ptail->Pprev = Plist->Phead;
|
|
||||||
Plist->Pfree = NULL;
|
|
||||||
Plist->next_free = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_set(Area_List *Plist, int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
Plist->Pfree = NULL;
|
|
||||||
|
|
||||||
Plist->Phead[2].x1 = x1;
|
|
||||||
Plist->Phead[2].y1 = y1;
|
|
||||||
Plist->Phead[2].x2 = x2;
|
|
||||||
Plist->Phead[2].y2 = y2;
|
|
||||||
|
|
||||||
Plist->Phead[2].Pprev = Plist->Phead;
|
|
||||||
Plist->Phead->Pnext = Plist->Phead + 2;
|
|
||||||
|
|
||||||
Plist->Phead[2].Pnext = Plist->Ptail;
|
|
||||||
Plist->Ptail->Pprev = Plist->Phead + 2;
|
|
||||||
|
|
||||||
Plist->next_free = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_remove(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
int l, h;
|
|
||||||
Area *Parea = Plist->Phead->Pnext;
|
|
||||||
|
|
||||||
#ifdef RECT_DEBUG
|
|
||||||
if ((x1 > x2) || (y1 > y2))
|
|
||||||
area_fatal_error("area_list_remove", "invalid coords: %i %i %i %i", x1, y1, x2, y2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
// Not touching
|
|
||||||
if ((x2 < Parea->x1) || (x1 > Parea->x2) ||
|
|
||||||
(y2 < Parea->y1) || (y1 > Parea->y2))
|
|
||||||
{
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Completely covers
|
|
||||||
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
|
|
||||||
(y1 <= Parea->y1) && (y2 >= Parea->y2))
|
|
||||||
{
|
|
||||||
if ((x1 == Parea->x1) && (x2 == Parea->x2) &&
|
|
||||||
(y1 == Parea->y1) && (y2 == Parea->y2))
|
|
||||||
{
|
|
||||||
delete_area(Plist, Parea);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parea = delete_area(Plist, Parea);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// top
|
|
||||||
if (y1 > Parea->y1)
|
|
||||||
{
|
|
||||||
insert_area_before(Plist, Parea,
|
|
||||||
Parea->x1, Parea->y1,
|
|
||||||
Parea->x2, y1 - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bottom
|
|
||||||
if (y2 < Parea->y2)
|
|
||||||
{
|
|
||||||
insert_area_before(Plist, Parea,
|
|
||||||
Parea->x1, y2 + 1,
|
|
||||||
Parea->x2, Parea->y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
l = math::maximum(y1, Parea->y1);
|
|
||||||
h = math::minimum(y2, Parea->y2);
|
|
||||||
|
|
||||||
// left middle
|
|
||||||
if (x1 > Parea->x1)
|
|
||||||
{
|
|
||||||
insert_area_before(Plist, Parea,
|
|
||||||
Parea->x1, l,
|
|
||||||
x1 - 1, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
// right middle
|
|
||||||
if (x2 < Parea->x2)
|
|
||||||
{
|
|
||||||
insert_area_before(Plist, Parea,
|
|
||||||
x2 + 1, l,
|
|
||||||
Parea->x2, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
// early out - we know there's nothing else to remove, as areas can
|
|
||||||
// never overlap
|
|
||||||
if ((x1 >= Parea->x1) && (x2 <= Parea->x2) &&
|
|
||||||
(y1 >= Parea->y1) && (y2 <= Parea->y2))
|
|
||||||
{
|
|
||||||
delete_area(Plist, Parea);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parea = delete_area(Plist, Parea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_insert(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2,
|
|
||||||
bool combine)
|
|
||||||
{
|
|
||||||
Area *Parea = Plist->Phead->Pnext;
|
|
||||||
|
|
||||||
#ifdef RECT_DEBUG
|
|
||||||
if ((x1 > x2) || (y1 > y2))
|
|
||||||
area_fatal_error("Area_List_insert", "invalid coords: %i %i %i %i", x1, y1, x2, y2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
// totally covers
|
|
||||||
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
|
|
||||||
(y1 <= Parea->y1) && (y2 >= Parea->y2))
|
|
||||||
{
|
|
||||||
Parea = delete_area(Plist, Parea);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// intersects
|
|
||||||
if ((x2 >= Parea->x1) && (x1 <= Parea->x2) &&
|
|
||||||
(y2 >= Parea->y1) && (y1 <= Parea->y2))
|
|
||||||
{
|
|
||||||
int ax1, ay1, ax2, ay2;
|
|
||||||
|
|
||||||
ax1 = Parea->x1;
|
|
||||||
ay1 = Parea->y1;
|
|
||||||
ax2 = Parea->x2;
|
|
||||||
ay2 = Parea->y2;
|
|
||||||
|
|
||||||
if (x1 < ax1)
|
|
||||||
Area_List_insert(Plist, x1, math::maximum(y1, ay1), ax1 - 1, math::minimum(y2, ay2), combine);
|
|
||||||
|
|
||||||
if (x2 > ax2)
|
|
||||||
Area_List_insert(Plist, ax2 + 1, math::maximum(y1, ay1), x2, math::minimum(y2, ay2), combine);
|
|
||||||
|
|
||||||
if (y1 < ay1)
|
|
||||||
Area_List_insert(Plist, x1, y1, x2, ay1 - 1, combine);
|
|
||||||
|
|
||||||
if (y2 > ay2)
|
|
||||||
Area_List_insert(Plist, x1, ay2 + 1, x2, y2, combine);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (combine)
|
|
||||||
{
|
|
||||||
if ((x1 == Parea->x1) && (x2 == Parea->x2))
|
|
||||||
{
|
|
||||||
if ((y2 == Parea->y1 - 1) || (y1 == Parea->y2 + 1))
|
|
||||||
{
|
|
||||||
delete_area(Plist, Parea);
|
|
||||||
Area_List_insert(Plist, x1, math::minimum(y1, Parea->y1), x2, math::maximum(y2, Parea->y2), CRNLIB_TRUE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((y1 == Parea->y1) && (y2 == Parea->y2))
|
|
||||||
{
|
|
||||||
if ((x2 == Parea->x1 - 1) || (x1 == Parea->x2 + 1))
|
|
||||||
{
|
|
||||||
delete_area(Plist, Parea);
|
|
||||||
Area_List_insert(Plist, math::minimum(x1, Parea->x1), y1, math::maximum(x2, Parea->x2), y2, CRNLIB_TRUE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert_area_before(Plist, Parea, x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Area_List_intersect_area(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
Area *Parea = Plist->Phead->Pnext;
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
// doesn't cover
|
|
||||||
if ((x2 < Parea->x1) || (x1 > Parea->x2) ||
|
|
||||||
(y2 < Parea->y1) || (y1 > Parea->y2))
|
|
||||||
{
|
|
||||||
Parea = delete_area(Plist, Parea);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// totally covers
|
|
||||||
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
|
|
||||||
(y1 <= Parea->y1) && (y2 >= Parea->y2))
|
|
||||||
{
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Oct 21- should insert after, because deleted area will access the NEXT area!
|
|
||||||
// insert_area_after(Plist, Parea,
|
|
||||||
// math::maximum(x1, Parea->x1),
|
|
||||||
// math::maximum(y1, Parea->y1),
|
|
||||||
// math::minimum(x2, Parea->x2),
|
|
||||||
// math::minimum(y2, Parea->y2));
|
|
||||||
|
|
||||||
insert_area_before(Plist, Parea,
|
|
||||||
math::maximum(x1, Parea->x1),
|
|
||||||
math::maximum(y1, Parea->y1),
|
|
||||||
math::minimum(x2, Parea->x2),
|
|
||||||
math::minimum(y2, Parea->y2));
|
|
||||||
|
|
||||||
Parea = delete_area(Plist, Parea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void Area_List_intersect_Area_List(
|
|
||||||
Area_List *Pouter_list,
|
|
||||||
Area_List *Pinner_list,
|
|
||||||
Area_List *Pdst_list)
|
|
||||||
{
|
|
||||||
Area *Parea1 = Pouter_list->Phead->Pnext;
|
|
||||||
|
|
||||||
while (Parea1 != Pouter_list->Ptail)
|
|
||||||
{
|
|
||||||
Area *Parea2 = Pinner_list->Phead->Pnext;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
x1 = Parea1->x1; x2 = Parea1->x2;
|
|
||||||
y1 = Parea1->y1; y2 = Parea1->y2;
|
|
||||||
|
|
||||||
while (Parea2 != Pinner_list->Ptail)
|
|
||||||
{
|
|
||||||
if ((x1 <= Parea2->x2) && (x2 >= Parea2->x1) &&
|
|
||||||
(y1 <= Parea2->y2) && (y2 >= Parea2->y1))
|
|
||||||
{
|
|
||||||
insert_area_after(Pdst_list, Pdst_list->Phead,
|
|
||||||
math::maximum(x1, Parea2->x1),
|
|
||||||
math::maximum(y1, Parea2->y1),
|
|
||||||
math::minimum(x2, Parea2->x2),
|
|
||||||
math::minimum(y2, Parea2->y2));
|
|
||||||
}
|
|
||||||
|
|
||||||
Parea2 = Parea2->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parea1 = Parea1->Pnext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
void Area_List_intersect_Area_List(Area_List *Pouter_list,
|
|
||||||
Area_List *Pinner_list,
|
|
||||||
Area_List *Pdst_list)
|
|
||||||
{
|
|
||||||
Area *Parea1 = Pouter_list->Phead->Pnext;
|
|
||||||
|
|
||||||
while (Parea1 != Pouter_list->Ptail)
|
|
||||||
{
|
|
||||||
Area *Parea2 = Pinner_list->Phead->Pnext;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
x1 = Parea1->x1; x2 = Parea1->x2;
|
|
||||||
y1 = Parea1->y1; y2 = Parea1->y2;
|
|
||||||
|
|
||||||
while (Parea2 != Pinner_list->Ptail)
|
|
||||||
{
|
|
||||||
if ((x1 <= Parea2->x2) && (x2 >= Parea2->x1) &&
|
|
||||||
(y1 <= Parea2->y2) && (y2 >= Parea2->y1))
|
|
||||||
{
|
|
||||||
int nx1, ny1, nx2, ny2;
|
|
||||||
|
|
||||||
nx1 = math::maximum(x1, Parea2->x1);
|
|
||||||
ny1 = math::maximum(y1, Parea2->y1);
|
|
||||||
nx2 = math::minimum(x2, Parea2->x2);
|
|
||||||
ny2 = math::minimum(y2, Parea2->y2);
|
|
||||||
|
|
||||||
if (Pdst_list->Phead->Pnext == Pdst_list->Ptail)
|
|
||||||
{
|
|
||||||
insert_area_after(Pdst_list, Pdst_list->Phead,
|
|
||||||
nx1, ny1, nx2, ny2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Area_Ptr Ptemp = Pdst_list->Phead->Pnext;
|
|
||||||
if ((Ptemp->x1 == nx1) && (Ptemp->x2 == nx2))
|
|
||||||
{
|
|
||||||
if (Ptemp->y1 == (ny2+1))
|
|
||||||
{
|
|
||||||
Ptemp->y1 = ny1;
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
else if (Ptemp->y2 == (ny1-1))
|
|
||||||
{
|
|
||||||
Ptemp->y2 = ny2;
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((Ptemp->y1 == ny1) && (Ptemp->y2 == ny2))
|
|
||||||
{
|
|
||||||
if (Ptemp->x1 == (nx2+1))
|
|
||||||
{
|
|
||||||
Ptemp->x1 = nx1;
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
else if (Ptemp->x2 == (nx1-1))
|
|
||||||
{
|
|
||||||
Ptemp->x2 = nx2;
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insert_area_after(Pdst_list, Pdst_list->Phead,
|
|
||||||
nx1, ny1, nx2, ny2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next:
|
|
||||||
|
|
||||||
Parea2 = Parea2->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parea1 = Parea1->Pnext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist)
|
|
||||||
{
|
|
||||||
Area_Ptr Parea = Plist->Phead->Pnext, Parea_after;
|
|
||||||
int num = 2;
|
|
||||||
Area_List_Ptr Pnew_list;
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
num++;
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pnew_list = Area_List_init(num);
|
|
||||||
|
|
||||||
Parea = Plist->Phead->Pnext;
|
|
||||||
|
|
||||||
Parea_after = Pnew_list->Phead;
|
|
||||||
|
|
||||||
while (Parea != Plist->Ptail)
|
|
||||||
{
|
|
||||||
Parea_after = insert_area_after(Pnew_list, Parea_after,
|
|
||||||
Parea->x1, Parea->y1,
|
|
||||||
Parea->x2, Parea->y2);
|
|
||||||
|
|
||||||
Parea = Parea->Pnext;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Pnew_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,74 +0,0 @@
|
||||||
// File: crn_arealist.h - 2D shape algebra
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
struct Area
|
|
||||||
{
|
|
||||||
struct Area *Pprev, *Pnext;
|
|
||||||
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
uint get_width() const { return x2 - x1 + 1; }
|
|
||||||
uint get_height() const { return y2 - y1 + 1; }
|
|
||||||
uint get_area() const { return get_width() * get_height(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Area * Area_Ptr;
|
|
||||||
|
|
||||||
struct Area_List
|
|
||||||
{
|
|
||||||
int total_areas;
|
|
||||||
int next_free;
|
|
||||||
|
|
||||||
Area *Phead, *Ptail, *Pfree;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Area_List * Area_List_Ptr;
|
|
||||||
|
|
||||||
Area_List * Area_List_init(int max_areas);
|
|
||||||
void Area_List_deinit(Area_List* Pobj_base);
|
|
||||||
|
|
||||||
void Area_List_print(Area_List *Plist);
|
|
||||||
|
|
||||||
Area_List * Area_List_dup_new(Area_List *Plist,
|
|
||||||
int x_ofs, int y_ofs);
|
|
||||||
|
|
||||||
uint Area_List_get_num(Area_List* Plist);
|
|
||||||
|
|
||||||
// src and dst area lists must have the same number of total areas.
|
|
||||||
void Area_List_dup(Area_List *Psrc_list,
|
|
||||||
Area_List *Pdst_list,
|
|
||||||
int x_ofs, int y_ofs);
|
|
||||||
|
|
||||||
void Area_List_copy(Area_List *Psrc_list,
|
|
||||||
Area_List *Pdst_list,
|
|
||||||
int x_ofs, int y_ofs);
|
|
||||||
|
|
||||||
void Area_List_clear(Area_List *Plist);
|
|
||||||
|
|
||||||
void Area_List_set(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2);
|
|
||||||
|
|
||||||
// logical: x and (not y)
|
|
||||||
void Area_List_remove(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2);
|
|
||||||
|
|
||||||
// logical: x or y
|
|
||||||
void Area_List_insert(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2,
|
|
||||||
bool combine);
|
|
||||||
|
|
||||||
// logical: x and y
|
|
||||||
void Area_List_intersect_area(Area_List *Plist,
|
|
||||||
int x1, int y1, int x2, int y2);
|
|
||||||
|
|
||||||
// logical: x and y
|
|
||||||
void Area_List_intersect_Area_List(Area_List *Pouter_list,
|
|
||||||
Area_List *Pinner_list,
|
|
||||||
Area_List *Pdst_list);
|
|
||||||
|
|
||||||
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist);
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,69 +0,0 @@
|
||||||
// File: crn_assert.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool g_fail_exceptions;
|
|
||||||
static bool g_exit_on_failure = true;
|
|
||||||
|
|
||||||
void crnlib_enable_fail_exceptions(bool enabled)
|
|
||||||
{
|
|
||||||
g_fail_exceptions = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void crnlib_assert(const char* pExp, const char* pFile, unsigned line)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
|
|
||||||
sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
|
|
||||||
|
|
||||||
crnlib_output_debug_string(buf);
|
|
||||||
|
|
||||||
fputs(buf, stderr);
|
|
||||||
|
|
||||||
if (crnlib_is_debugger_present())
|
|
||||||
crnlib_debug_break();
|
|
||||||
}
|
|
||||||
|
|
||||||
void crnlib_fail(const char* pExp, const char* pFile, unsigned line)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
|
|
||||||
sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
|
|
||||||
|
|
||||||
crnlib_output_debug_string(buf);
|
|
||||||
|
|
||||||
fputs(buf, stderr);
|
|
||||||
|
|
||||||
if (crnlib_is_debugger_present())
|
|
||||||
crnlib_debug_break();
|
|
||||||
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
if (g_fail_exceptions)
|
|
||||||
RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (g_exit_on_failure)
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace(const char* pFmt, va_list args)
|
|
||||||
{
|
|
||||||
if (crnlib_is_debugger_present())
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
vsprintf_s(buf, sizeof(buf), pFmt, args);
|
|
||||||
|
|
||||||
crnlib_output_debug_string(buf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void trace(const char* pFmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, pFmt);
|
|
||||||
trace(pFmt, args);
|
|
||||||
va_end(args);
|
|
||||||
};
|
|
|
@ -1,61 +0,0 @@
|
||||||
// File: crn_assert.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
const unsigned int CRNLIB_FAIL_EXCEPTION_CODE = 256U;
|
|
||||||
void crnlib_enable_fail_exceptions(bool enabled);
|
|
||||||
|
|
||||||
void crnlib_assert(const char* pExp, const char* pFile, unsigned line);
|
|
||||||
void crnlib_fail(const char* pExp, const char* pFile, unsigned line);
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define CRNLIB_ASSERT(x) ((void)0)
|
|
||||||
#undef CRNLIB_ASSERTS_ENABLED
|
|
||||||
#else
|
|
||||||
#define CRNLIB_ASSERT(_exp) (void)( (!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0) )
|
|
||||||
#define CRNLIB_ASSERTS_ENABLED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_VERIFY(_exp) (void)( (!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0) )
|
|
||||||
|
|
||||||
#define CRNLIB_FAIL(msg) do { crnlib_fail(#msg, __FILE__, __LINE__); } while(0)
|
|
||||||
|
|
||||||
#define CRNLIB_ASSERT_OPEN_RANGE(x, l, h) CRNLIB_ASSERT((x >= l) && (x < h))
|
|
||||||
#define CRNLIB_ASSERT_CLOSED_RANGE(x, l, h) CRNLIB_ASSERT((x >= l) && (x <= h))
|
|
||||||
|
|
||||||
void trace(const char* pFmt, va_list args);
|
|
||||||
void trace(const char* pFmt, ...);
|
|
||||||
|
|
||||||
// Borrowed from boost libraries.
|
|
||||||
template <bool x> struct crnlib_assume_failure;
|
|
||||||
template <> struct crnlib_assume_failure<true> { enum { blah = 1 }; };
|
|
||||||
template<int x> struct crnlib_assume_try { };
|
|
||||||
|
|
||||||
#define CRNLIB_JOINER_FINAL(a, b) a##b
|
|
||||||
#define CRNLIB_JOINER(a, b) CRNLIB_JOINER_FINAL(a, b)
|
|
||||||
#define CRNLIB_JOIN(a, b) CRNLIB_JOINER(a, b)
|
|
||||||
#define CRNLIB_ASSUME(p) typedef crnlib_assume_try < sizeof(crnlib_assume_failure< (bool)(p) > ) > CRNLIB_JOIN(crnlib_assume_typedef, __COUNTER__)
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
template<typename T> inline T crnlib_assert_range(T i, T m)
|
|
||||||
{
|
|
||||||
m;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
template<typename T> inline T crnlib_assert_range_incl(T i, T m)
|
|
||||||
{
|
|
||||||
m;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template<typename T> inline T crnlib_assert_range(T i, T m)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((i >= 0) && (i < m));
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
template<typename T> inline T crnlib_assert_range_incl(T i, T m)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((i >= 0) && (i <= m));
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,208 +0,0 @@
|
||||||
// File: crn_atomics.h
|
|
||||||
#ifndef CRN_ATOMICS_H
|
|
||||||
#define CRN_ATOMICS_H
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#pragma once
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && CRNLIB_PLATFORM_PC
|
|
||||||
extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) void crnlib_yield_processor()
|
|
||||||
{
|
|
||||||
__asm__ __volatile__("pause");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
CRNLIB_FORCE_INLINE void crnlib_yield_processor()
|
|
||||||
{
|
|
||||||
#if CRNLIB_USE_MSVC_INTRINSICS
|
|
||||||
#if CRNLIB_PLATFORM_PC_X64
|
|
||||||
_mm_pause();
|
|
||||||
#else
|
|
||||||
YieldProcessor();
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
// No implementation
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
|
|
||||||
extern "C" __int64 _InterlockedCompareExchange64(__int64 volatile * Destination, __int64 Exchange, __int64 Comperand);
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#pragma intrinsic(_InterlockedCompareExchange64)
|
|
||||||
#endif
|
|
||||||
#endif // CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
#if CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
|
|
||||||
typedef LONG atomic32_t;
|
|
||||||
typedef LONGLONG atomic64_t;
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return InterlockedCompareExchange(pDest, exchange, comparand);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
|
|
||||||
return _InterlockedCompareExchange64(pDest, exchange, comparand);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resulting incremented value.
|
|
||||||
inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return InterlockedIncrement(pDest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resulting decremented value.
|
|
||||||
inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return InterlockedDecrement(pDest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return InterlockedExchange(pDest, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resulting value.
|
|
||||||
inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return InterlockedExchangeAdd(pDest, val) + val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return InterlockedExchangeAdd(pDest, val);
|
|
||||||
}
|
|
||||||
#elif CRNLIB_USE_GCC_ATOMIC_BUILTINS
|
|
||||||
typedef long atomic32_t;
|
|
||||||
typedef long long atomic64_t;
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return __sync_val_compare_and_swap(pDest, comparand, exchange);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
|
|
||||||
return __sync_val_compare_and_swap(pDest, comparand, exchange);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resulting incremented value.
|
|
||||||
inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return __sync_add_and_fetch(pDest, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resulting decremented value.
|
|
||||||
inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return __sync_sub_and_fetch(pDest, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return __sync_lock_test_and_set(pDest, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resulting value.
|
|
||||||
inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return __sync_add_and_fetch(pDest, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original value.
|
|
||||||
inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return __sync_fetch_and_add(pDest, val);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define CRNLIB_NO_ATOMICS 1
|
|
||||||
|
|
||||||
// Atomic ops not supported - but try to do something reasonable. Assumes no threading at all.
|
|
||||||
typedef long atomic32_t;
|
|
||||||
typedef long long atomic64_t;
|
|
||||||
|
|
||||||
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
atomic32_t cur = *pDest;
|
|
||||||
if (cur == comparand)
|
|
||||||
*pDest = exchange;
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
|
|
||||||
atomic64_t cur = *pDest;
|
|
||||||
if (cur == comparand)
|
|
||||||
*pDest = exchange;
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return (*pDest += 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return (*pDest -= 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
atomic32_t cur = *pDest;
|
|
||||||
*pDest = val;
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
return (*pDest += val);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
|
|
||||||
atomic32_t cur = *pDest;
|
|
||||||
*pDest += val;
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
#endif // CRN_ATOMICS_H
|
|
|
@ -1,196 +0,0 @@
|
||||||
// File: crn_buffer_stream.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_data_stream.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class buffer_stream : public data_stream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
buffer_stream() :
|
|
||||||
data_stream(),
|
|
||||||
m_pBuf(NULL),
|
|
||||||
m_size(0),
|
|
||||||
m_ofs(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_stream(void* p, uint size) :
|
|
||||||
data_stream(),
|
|
||||||
m_pBuf(NULL),
|
|
||||||
m_size(0),
|
|
||||||
m_ofs(0)
|
|
||||||
{
|
|
||||||
open(p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_stream(const void* p, uint size) :
|
|
||||||
data_stream(),
|
|
||||||
m_pBuf(NULL),
|
|
||||||
m_size(0),
|
|
||||||
m_ofs(0)
|
|
||||||
{
|
|
||||||
open(p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~buffer_stream()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const void* p, uint size)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
close();
|
|
||||||
|
|
||||||
if ((!p) || (!size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_opened = true;
|
|
||||||
m_pBuf = (uint8*)(p);
|
|
||||||
m_size = size;
|
|
||||||
m_ofs = 0;
|
|
||||||
m_attribs = cDataStreamSeekable | cDataStreamReadable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(void* p, uint size)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
close();
|
|
||||||
|
|
||||||
if ((!p) || (!size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_opened = true;
|
|
||||||
m_pBuf = static_cast<uint8*>(p);
|
|
||||||
m_size = size;
|
|
||||||
m_ofs = 0;
|
|
||||||
m_attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool close()
|
|
||||||
{
|
|
||||||
if (m_opened)
|
|
||||||
{
|
|
||||||
m_opened = false;
|
|
||||||
m_pBuf = NULL;
|
|
||||||
m_size = 0;
|
|
||||||
m_ofs = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const void* get_buf() const { return m_pBuf; }
|
|
||||||
void* get_buf() { return m_pBuf; }
|
|
||||||
|
|
||||||
virtual const void* get_ptr() const { return m_pBuf; }
|
|
||||||
|
|
||||||
virtual uint read(void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
|
|
||||||
|
|
||||||
if ((!m_opened) || (!is_readable()) || (!len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_size);
|
|
||||||
|
|
||||||
uint bytes_left = m_size - m_ofs;
|
|
||||||
|
|
||||||
len = math::minimum<uint>(len, bytes_left);
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
memcpy(pBuf, &m_pBuf[m_ofs], len);
|
|
||||||
|
|
||||||
m_ofs += len;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint write(const void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
|
|
||||||
|
|
||||||
if ((!m_opened) || (!is_writable()) || (!len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_size);
|
|
||||||
|
|
||||||
uint bytes_left = m_size - m_ofs;
|
|
||||||
|
|
||||||
len = math::minimum<uint>(len, bytes_left);
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
memcpy(&m_pBuf[m_ofs], pBuf, len);
|
|
||||||
|
|
||||||
m_ofs += len;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool flush()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_size()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_remaining()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_size);
|
|
||||||
|
|
||||||
return m_size - m_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_ofs()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool seek(int64 ofs, bool relative)
|
|
||||||
{
|
|
||||||
if ((!m_opened) || (!is_seekable()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
|
|
||||||
|
|
||||||
if (new_ofs < 0)
|
|
||||||
return false;
|
|
||||||
else if (new_ofs > m_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_ofs = static_cast<uint>(new_ofs);
|
|
||||||
|
|
||||||
post_seek();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8* m_pBuf;
|
|
||||||
uint m_size;
|
|
||||||
uint m_ofs;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,241 +0,0 @@
|
||||||
// File: crn_cfile_stream.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_data_stream.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class cfile_stream : public data_stream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cfile_stream() : data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
cfile_stream(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership) :
|
|
||||||
data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
|
|
||||||
{
|
|
||||||
open(pFile, pFilename, attribs, has_ownership);
|
|
||||||
}
|
|
||||||
|
|
||||||
cfile_stream(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false) :
|
|
||||||
data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
|
|
||||||
{
|
|
||||||
open(pFilename, attribs, open_existing);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~cfile_stream()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool close()
|
|
||||||
{
|
|
||||||
clear_error();
|
|
||||||
|
|
||||||
if (m_opened)
|
|
||||||
{
|
|
||||||
bool status = true;
|
|
||||||
if (m_has_ownership)
|
|
||||||
{
|
|
||||||
if (EOF == fclose(m_pFile))
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pFile = NULL;
|
|
||||||
m_opened = false;
|
|
||||||
m_size = 0;
|
|
||||||
m_ofs = 0;
|
|
||||||
m_has_ownership = false;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pFile);
|
|
||||||
CRNLIB_ASSERT(pFilename);
|
|
||||||
|
|
||||||
close();
|
|
||||||
|
|
||||||
set_name(pFilename);
|
|
||||||
m_pFile = pFile;
|
|
||||||
m_has_ownership = has_ownership;
|
|
||||||
m_attribs = static_cast<uint16>(attribs);
|
|
||||||
|
|
||||||
m_ofs = crn_ftell(m_pFile);
|
|
||||||
crn_fseek(m_pFile, 0, SEEK_END);
|
|
||||||
m_size = crn_ftell(m_pFile);
|
|
||||||
crn_fseek(m_pFile, m_ofs, SEEK_SET);
|
|
||||||
|
|
||||||
m_opened = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pFilename);
|
|
||||||
|
|
||||||
close();
|
|
||||||
|
|
||||||
m_attribs = static_cast<uint16>(attribs);
|
|
||||||
|
|
||||||
const char* pMode;
|
|
||||||
if ((is_readable()) && (is_writable()))
|
|
||||||
pMode = open_existing ? "r+b" : "w+b";
|
|
||||||
else if (is_writable())
|
|
||||||
pMode = open_existing ? "ab" : "wb";
|
|
||||||
else if (is_readable())
|
|
||||||
pMode = "rb";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
set_error();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* pFile = NULL;
|
|
||||||
crn_fopen(&pFile, pFilename, pMode);
|
|
||||||
m_has_ownership = true;
|
|
||||||
|
|
||||||
if (!pFile)
|
|
||||||
{
|
|
||||||
set_error();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Change stream class to support UCS2 filenames.
|
|
||||||
|
|
||||||
return open(pFile, pFilename, attribs, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* get_file() const { return m_pFile; }
|
|
||||||
|
|
||||||
virtual uint read(void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
|
|
||||||
|
|
||||||
if (!m_opened || (!is_readable()) || (!len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
len = static_cast<uint>(math::minimum<uint64>(len, get_remaining()));
|
|
||||||
|
|
||||||
if (fread(pBuf, 1, len, m_pFile) != len)
|
|
||||||
{
|
|
||||||
set_error();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ofs += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint write(const void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
|
|
||||||
|
|
||||||
if (!m_opened || (!is_writable()) || (!len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (fwrite(pBuf, 1, len, m_pFile) != len)
|
|
||||||
{
|
|
||||||
set_error();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ofs += len;
|
|
||||||
m_size = math::maximum(m_size, m_ofs);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool flush()
|
|
||||||
{
|
|
||||||
if ((!m_opened) || (!is_writable()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (EOF == fflush(m_pFile))
|
|
||||||
{
|
|
||||||
set_error();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_size()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_remaining()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_size);
|
|
||||||
return m_size - m_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_ofs()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool seek(int64 ofs, bool relative)
|
|
||||||
{
|
|
||||||
if ((!m_opened) || (!is_seekable()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
|
|
||||||
if (new_ofs < 0)
|
|
||||||
return false;
|
|
||||||
else if (static_cast<uint64>(new_ofs) > m_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (static_cast<uint64>(new_ofs) != m_ofs)
|
|
||||||
{
|
|
||||||
if (crn_fseek(m_pFile, new_ofs, SEEK_SET) != 0)
|
|
||||||
{
|
|
||||||
set_error();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ofs = new_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_file_into_array(const char* pFilename, vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
cfile_stream in_stream(pFilename);
|
|
||||||
if (!in_stream.is_opened())
|
|
||||||
return false;
|
|
||||||
return in_stream.read_array(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write_array_to_file(const char* pFilename, const vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
cfile_stream out_stream(pFilename, cDataStreamWritable|cDataStreamSeekable);
|
|
||||||
if (!out_stream.is_opened())
|
|
||||||
return false;
|
|
||||||
return out_stream.write_array(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FILE* m_pFile;
|
|
||||||
uint64 m_size, m_ofs;
|
|
||||||
bool m_has_ownership;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,63 +0,0 @@
|
||||||
// File: crn_checksum.cpp
|
|
||||||
#include "crn_core.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
// From the public domain stb.h header.
|
|
||||||
uint adler32(const void* pBuf, size_t buflen, uint adler32)
|
|
||||||
{
|
|
||||||
const uint8* buffer = static_cast<const uint8*>(pBuf);
|
|
||||||
|
|
||||||
const unsigned long ADLER_MOD = 65521;
|
|
||||||
unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
|
|
||||||
size_t blocklen;
|
|
||||||
unsigned long i;
|
|
||||||
|
|
||||||
blocklen = buflen % 5552;
|
|
||||||
while (buflen) {
|
|
||||||
for (i=0; i + 7 < blocklen; i += 8) {
|
|
||||||
s1 += buffer[0], s2 += s1;
|
|
||||||
s1 += buffer[1], s2 += s1;
|
|
||||||
s1 += buffer[2], s2 += s1;
|
|
||||||
s1 += buffer[3], s2 += s1;
|
|
||||||
s1 += buffer[4], s2 += s1;
|
|
||||||
s1 += buffer[5], s2 += s1;
|
|
||||||
s1 += buffer[6], s2 += s1;
|
|
||||||
s1 += buffer[7], s2 += s1;
|
|
||||||
|
|
||||||
buffer += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < blocklen; ++i)
|
|
||||||
s1 += *buffer++, s2 += s1;
|
|
||||||
|
|
||||||
s1 %= ADLER_MOD, s2 %= ADLER_MOD;
|
|
||||||
buflen -= blocklen;
|
|
||||||
blocklen = 5552;
|
|
||||||
}
|
|
||||||
return (s2 << 16) + s1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 crc16(const void* pBuf, size_t len, uint16 crc)
|
|
||||||
{
|
|
||||||
crc = ~crc;
|
|
||||||
|
|
||||||
const uint8* p = reinterpret_cast<const uint8*>(pBuf);
|
|
||||||
while (len)
|
|
||||||
{
|
|
||||||
const uint16 q = *p++ ^ (crc >> 8);
|
|
||||||
crc <<= 8U;
|
|
||||||
uint16 r = (q >> 4) ^ q;
|
|
||||||
crc ^= r;
|
|
||||||
r <<= 5U;
|
|
||||||
crc ^= r;
|
|
||||||
r <<= 7U;
|
|
||||||
crc ^= r;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<uint16>(~crc);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// File: crn_checksum.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
const uint cInitAdler32 = 1U;
|
|
||||||
uint adler32(const void* pBuf, size_t buflen, uint adler32 = cInitAdler32);
|
|
||||||
|
|
||||||
// crc16() intended for small buffers - doesn't use an acceleration table.
|
|
||||||
const uint cInitCRC16 = 0;
|
|
||||||
uint16 crc16(const void* pBuf, size_t len, uint16 crc = cInitCRC16);
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,764 +0,0 @@
|
||||||
// File: crn_clusterizer.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_matrix.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
template<typename VectorType>
|
|
||||||
class clusterizer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
clusterizer() :
|
|
||||||
m_overall_variance(0.0f),
|
|
||||||
m_split_index(0),
|
|
||||||
m_heap_size(0),
|
|
||||||
m_quick(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_training_vecs.clear();
|
|
||||||
m_codebook.clear();
|
|
||||||
m_nodes.clear();
|
|
||||||
m_overall_variance = 0.0f;
|
|
||||||
m_split_index = 0;
|
|
||||||
m_heap_size = 0;
|
|
||||||
m_quick = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve_training_vecs(uint num_expected)
|
|
||||||
{
|
|
||||||
m_training_vecs.reserve(num_expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_training_vec(const VectorType& v, uint weight)
|
|
||||||
{
|
|
||||||
m_training_vecs.push_back( std::make_pair(v, weight) );
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef bool (*progress_callback_func_ptr)(uint percentage_completed, void* pData);
|
|
||||||
|
|
||||||
bool generate_codebook(uint max_size, progress_callback_func_ptr pProgress_callback = NULL, void* pProgress_data = NULL, bool quick = false)
|
|
||||||
{
|
|
||||||
if (m_training_vecs.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_quick = quick;
|
|
||||||
|
|
||||||
double ttsum = 0.0f;
|
|
||||||
|
|
||||||
vq_node root;
|
|
||||||
root.m_vectors.reserve(m_training_vecs.size());
|
|
||||||
|
|
||||||
for (uint i = 0; i < m_training_vecs.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType& v = m_training_vecs[i].first;
|
|
||||||
const uint weight = m_training_vecs[i].second;
|
|
||||||
|
|
||||||
root.m_centroid += (v * (float)weight);
|
|
||||||
root.m_total_weight += weight;
|
|
||||||
root.m_vectors.push_back(i);
|
|
||||||
|
|
||||||
ttsum += v.dot(v) * weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
root.m_variance = (float)(ttsum - (root.m_centroid.dot(root.m_centroid) / root.m_total_weight));
|
|
||||||
|
|
||||||
root.m_centroid *= (1.0f / root.m_total_weight);
|
|
||||||
|
|
||||||
m_nodes.clear();
|
|
||||||
m_nodes.reserve(max_size * 2 + 1);
|
|
||||||
|
|
||||||
m_nodes.push_back(root);
|
|
||||||
|
|
||||||
m_heap.resize(max_size + 1);
|
|
||||||
m_heap[1] = 0;
|
|
||||||
m_heap_size = 1;
|
|
||||||
|
|
||||||
m_split_index = 0;
|
|
||||||
|
|
||||||
uint total_leaves = 1;
|
|
||||||
|
|
||||||
m_left_children.reserve(m_training_vecs.size() + 1);
|
|
||||||
m_right_children.reserve(m_training_vecs.size() + 1);
|
|
||||||
|
|
||||||
int prev_percentage = -1;
|
|
||||||
while ((total_leaves < max_size) && (m_heap_size))
|
|
||||||
{
|
|
||||||
int worst_node_index = m_heap[1];
|
|
||||||
|
|
||||||
m_heap[1] = m_heap[m_heap_size];
|
|
||||||
m_heap_size--;
|
|
||||||
if (m_heap_size)
|
|
||||||
down_heap(1);
|
|
||||||
|
|
||||||
split_node(worst_node_index);
|
|
||||||
total_leaves++;
|
|
||||||
|
|
||||||
if ((pProgress_callback) && ((total_leaves & 63) == 0) && (max_size))
|
|
||||||
{
|
|
||||||
int cur_percentage = (total_leaves * 100U + (max_size / 2U)) / max_size;
|
|
||||||
if (cur_percentage != prev_percentage)
|
|
||||||
{
|
|
||||||
if (!(*pProgress_callback)(cur_percentage, pProgress_data))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
prev_percentage = cur_percentage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_codebook.clear();
|
|
||||||
|
|
||||||
m_overall_variance = 0.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < m_nodes.size(); i++)
|
|
||||||
{
|
|
||||||
vq_node& node = m_nodes[i];
|
|
||||||
if (node.m_left != -1)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(node.m_right != -1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_ASSERT((node.m_left == -1) && (node.m_right == -1));
|
|
||||||
|
|
||||||
node.m_codebook_index = m_codebook.size();
|
|
||||||
m_codebook.push_back(node.m_centroid);
|
|
||||||
|
|
||||||
m_overall_variance += node.m_variance;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_heap.clear();
|
|
||||||
m_left_children.clear();
|
|
||||||
m_right_children.clear();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_num_training_vecs() const { return m_training_vecs.size(); }
|
|
||||||
const VectorType& get_training_vec(uint index) const { return m_training_vecs[index].first; }
|
|
||||||
uint get_training_vec_weight(uint index) const { return m_training_vecs[index].second; }
|
|
||||||
|
|
||||||
typedef crnlib::vector< std::pair<VectorType, uint> > training_vec_array;
|
|
||||||
|
|
||||||
const training_vec_array& get_training_vecs() const { return m_training_vecs; }
|
|
||||||
training_vec_array& get_training_vecs() { return m_training_vecs; }
|
|
||||||
|
|
||||||
inline float get_overall_variance() const { return m_overall_variance; }
|
|
||||||
|
|
||||||
inline uint get_codebook_size() const
|
|
||||||
{
|
|
||||||
return m_codebook.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const VectorType& get_codebook_entry(uint index) const
|
|
||||||
{
|
|
||||||
return m_codebook[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorType& get_codebook_entry(uint index)
|
|
||||||
{
|
|
||||||
return m_codebook[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef crnlib::vector<VectorType> vector_vec_type;
|
|
||||||
inline const vector_vec_type& get_codebook() const
|
|
||||||
{
|
|
||||||
return m_codebook;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint find_best_codebook_entry(const VectorType& v) const
|
|
||||||
{
|
|
||||||
uint cur_node_index = 0;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
const vq_node& cur_node = m_nodes[cur_node_index];
|
|
||||||
|
|
||||||
if (cur_node.m_left == -1)
|
|
||||||
return cur_node.m_codebook_index;
|
|
||||||
|
|
||||||
const vq_node& left_node = m_nodes[cur_node.m_left];
|
|
||||||
const vq_node& right_node = m_nodes[cur_node.m_right];
|
|
||||||
|
|
||||||
float left_dist = left_node.m_centroid.squared_distance(v);
|
|
||||||
float right_dist = right_node.m_centroid.squared_distance(v);
|
|
||||||
|
|
||||||
if (left_dist < right_dist)
|
|
||||||
cur_node_index = cur_node.m_left;
|
|
||||||
else
|
|
||||||
cur_node_index = cur_node.m_right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const VectorType& find_best_codebook_entry(const VectorType& v, uint max_codebook_size) const
|
|
||||||
{
|
|
||||||
uint cur_node_index = 0;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
const vq_node& cur_node = m_nodes[cur_node_index];
|
|
||||||
|
|
||||||
if ((cur_node.m_left == -1) || ((cur_node.m_codebook_index + 1) >= (int)max_codebook_size))
|
|
||||||
return cur_node.m_centroid;
|
|
||||||
|
|
||||||
const vq_node& left_node = m_nodes[cur_node.m_left];
|
|
||||||
const vq_node& right_node = m_nodes[cur_node.m_right];
|
|
||||||
|
|
||||||
float left_dist = left_node.m_centroid.squared_distance(v);
|
|
||||||
float right_dist = right_node.m_centroid.squared_distance(v);
|
|
||||||
|
|
||||||
if (left_dist < right_dist)
|
|
||||||
cur_node_index = cur_node.m_left;
|
|
||||||
else
|
|
||||||
cur_node_index = cur_node.m_right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint find_best_codebook_entry_fs(const VectorType& v) const
|
|
||||||
{
|
|
||||||
float best_dist = math::cNearlyInfinite;
|
|
||||||
uint best_index = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < m_codebook.size(); i++)
|
|
||||||
{
|
|
||||||
float dist = m_codebook[i].squared_distance(v);
|
|
||||||
if (dist < best_dist)
|
|
||||||
{
|
|
||||||
best_dist = dist;
|
|
||||||
best_index = i;
|
|
||||||
if (best_dist == 0.0f)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return best_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void retrieve_clusters(uint max_clusters, crnlib::vector< crnlib::vector<uint> >& clusters) const
|
|
||||||
{
|
|
||||||
clusters.resize(0);
|
|
||||||
clusters.reserve(max_clusters);
|
|
||||||
|
|
||||||
crnlib::vector<uint> stack;
|
|
||||||
stack.reserve(512);
|
|
||||||
|
|
||||||
uint cur_node_index = 0;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
const vq_node& cur_node = m_nodes[cur_node_index];
|
|
||||||
|
|
||||||
if ( (cur_node.is_leaf()) || ((cur_node.m_codebook_index + 2) > (int)max_clusters) )
|
|
||||||
{
|
|
||||||
clusters.resize(clusters.size() + 1);
|
|
||||||
clusters.back() = cur_node.m_vectors;
|
|
||||||
|
|
||||||
if (stack.empty())
|
|
||||||
break;
|
|
||||||
cur_node_index = stack.back();
|
|
||||||
stack.pop_back();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_node_index = cur_node.m_left;
|
|
||||||
stack.push_back(cur_node.m_right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
training_vec_array m_training_vecs;
|
|
||||||
|
|
||||||
struct vq_node
|
|
||||||
{
|
|
||||||
vq_node() : m_centroid(cClear), m_total_weight(0), m_left(-1), m_right(-1), m_codebook_index(-1), m_unsplittable(false) { }
|
|
||||||
|
|
||||||
VectorType m_centroid;
|
|
||||||
uint64 m_total_weight;
|
|
||||||
|
|
||||||
float m_variance;
|
|
||||||
|
|
||||||
crnlib::vector<uint> m_vectors;
|
|
||||||
|
|
||||||
int m_left;
|
|
||||||
int m_right;
|
|
||||||
|
|
||||||
int m_codebook_index;
|
|
||||||
|
|
||||||
bool m_unsplittable;
|
|
||||||
|
|
||||||
bool is_leaf() const { return m_left < 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<vq_node> node_vec_type;
|
|
||||||
|
|
||||||
node_vec_type m_nodes;
|
|
||||||
|
|
||||||
vector_vec_type m_codebook;
|
|
||||||
|
|
||||||
float m_overall_variance;
|
|
||||||
|
|
||||||
uint m_split_index;
|
|
||||||
|
|
||||||
crnlib::vector<uint> m_heap;
|
|
||||||
uint m_heap_size;
|
|
||||||
|
|
||||||
bool m_quick;
|
|
||||||
|
|
||||||
void insert_heap(uint node_index)
|
|
||||||
{
|
|
||||||
const float variance = m_nodes[node_index].m_variance;
|
|
||||||
uint pos = ++m_heap_size;
|
|
||||||
|
|
||||||
if (m_heap_size >= m_heap.size())
|
|
||||||
m_heap.resize(m_heap_size + 1);
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
uint parent = pos >> 1;
|
|
||||||
if (!parent)
|
|
||||||
break;
|
|
||||||
|
|
||||||
float parent_variance = m_nodes[m_heap[parent]].m_variance;
|
|
||||||
if (parent_variance > variance)
|
|
||||||
break;
|
|
||||||
|
|
||||||
m_heap[pos] = m_heap[parent];
|
|
||||||
|
|
||||||
pos = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_heap[pos] = node_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void down_heap(uint pos)
|
|
||||||
{
|
|
||||||
uint child;
|
|
||||||
uint orig = m_heap[pos];
|
|
||||||
|
|
||||||
const float orig_variance = m_nodes[orig].m_variance;
|
|
||||||
|
|
||||||
while ((child = (pos << 1)) <= m_heap_size)
|
|
||||||
{
|
|
||||||
if (child < m_heap_size)
|
|
||||||
{
|
|
||||||
if (m_nodes[m_heap[child]].m_variance < m_nodes[m_heap[child + 1]].m_variance)
|
|
||||||
child++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orig_variance > m_nodes[m_heap[child]].m_variance)
|
|
||||||
break;
|
|
||||||
|
|
||||||
m_heap[pos] = m_heap[child];
|
|
||||||
|
|
||||||
pos = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_heap[pos] = orig;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compute_split_estimate(VectorType& left_child_res, VectorType& right_child_res, const vq_node& parent_node)
|
|
||||||
{
|
|
||||||
VectorType furthest(0);
|
|
||||||
double furthest_dist = -1.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
|
|
||||||
double dist = v.squared_distance(parent_node.m_centroid);
|
|
||||||
if (dist > furthest_dist)
|
|
||||||
{
|
|
||||||
furthest_dist = dist;
|
|
||||||
furthest = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorType opposite(0);
|
|
||||||
double opposite_dist = -1.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
|
|
||||||
double dist = v.squared_distance(furthest);
|
|
||||||
if (dist > opposite_dist)
|
|
||||||
{
|
|
||||||
opposite_dist = dist;
|
|
||||||
opposite = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
left_child_res = (furthest + parent_node.m_centroid) * .5f;
|
|
||||||
right_child_res = (opposite + parent_node.m_centroid) * .5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compute_split_pca(VectorType& left_child_res, VectorType& right_child_res, const vq_node& parent_node)
|
|
||||||
{
|
|
||||||
if (parent_node.m_vectors.size() == 2)
|
|
||||||
{
|
|
||||||
left_child_res = m_training_vecs[parent_node.m_vectors[0]].first;
|
|
||||||
right_child_res = m_training_vecs[parent_node.m_vectors[1]].first;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint N = VectorType::num_elements;
|
|
||||||
|
|
||||||
matrix<N, N, float> covar;
|
|
||||||
covar.clear();
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType v(m_training_vecs[parent_node.m_vectors[i]].first - parent_node.m_centroid);
|
|
||||||
const VectorType w(v * (float)m_training_vecs[parent_node.m_vectors[i]].second);
|
|
||||||
|
|
||||||
for (uint x = 0; x < N; x++)
|
|
||||||
for (uint y = x; y < N; y++)
|
|
||||||
covar[x][y] = covar[x][y] + v[x] * w[y];
|
|
||||||
}
|
|
||||||
|
|
||||||
float one_over_total_weight = 1.0f / parent_node.m_total_weight;
|
|
||||||
|
|
||||||
for (uint x = 0; x < N; x++)
|
|
||||||
for (uint y = x; y < N; y++)
|
|
||||||
covar[x][y] *= one_over_total_weight;
|
|
||||||
|
|
||||||
for (uint x = 0; x < (N - 1); x++)
|
|
||||||
for (uint y = x + 1; y < N; y++)
|
|
||||||
covar[y][x] = covar[x][y];
|
|
||||||
|
|
||||||
VectorType axis;//(1.0f);
|
|
||||||
if (N == 1)
|
|
||||||
axis.set(1.0f);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < N; i++)
|
|
||||||
axis[i] = math::lerp(.75f, 1.25f, i * (1.0f / math::maximum<int>(N - 1, 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorType prev_axis(axis);
|
|
||||||
|
|
||||||
for (uint iter = 0; iter < 10; iter++)
|
|
||||||
{
|
|
||||||
VectorType x;
|
|
||||||
|
|
||||||
double max_sum = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < N; i++)
|
|
||||||
{
|
|
||||||
double sum = 0;
|
|
||||||
|
|
||||||
for (uint j = 0; j < N; j++)
|
|
||||||
sum += axis[j] * covar[i][j];
|
|
||||||
|
|
||||||
x[i] = static_cast<float>(sum);
|
|
||||||
|
|
||||||
max_sum = math::maximum(max_sum, fabs(sum));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_sum != 0.0f)
|
|
||||||
x *= static_cast<float>(1.0f / max_sum);
|
|
||||||
|
|
||||||
VectorType delta_axis(prev_axis - x);
|
|
||||||
|
|
||||||
prev_axis = axis;
|
|
||||||
axis = x;
|
|
||||||
|
|
||||||
if (delta_axis.norm() < .0025f)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
axis.normalize();
|
|
||||||
|
|
||||||
VectorType left_child(0.0f);
|
|
||||||
VectorType right_child(0.0f);
|
|
||||||
|
|
||||||
double left_weight = 0.0f;
|
|
||||||
double right_weight = 0.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const float weight = (float)m_training_vecs[parent_node.m_vectors[i]].second;
|
|
||||||
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
|
|
||||||
double t = (v - parent_node.m_centroid) * axis;
|
|
||||||
if (t < 0.0f)
|
|
||||||
{
|
|
||||||
left_child += v * weight;
|
|
||||||
left_weight += weight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
right_child += v * weight;
|
|
||||||
right_weight += weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((left_weight > 0.0f) && (right_weight > 0.0f))
|
|
||||||
{
|
|
||||||
left_child_res = left_child * (float)(1.0f / left_weight);
|
|
||||||
right_child_res = right_child * (float)(1.0f / right_weight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
compute_split_estimate(left_child_res, right_child_res, parent_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void compute_split_pca2(VectorType& left_child_res, VectorType& right_child_res, const vq_node& parent_node)
|
|
||||||
{
|
|
||||||
if (parent_node.m_vectors.size() == 2)
|
|
||||||
{
|
|
||||||
left_child_res = m_training_vecs[parent_node.m_vectors[0]].first;
|
|
||||||
right_child_res = m_training_vecs[parent_node.m_vectors[1]].first;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint N = VectorType::num_elements;
|
|
||||||
|
|
||||||
VectorType furthest;
|
|
||||||
double furthest_dist = -1.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
|
|
||||||
double dist = v.squared_distance(parent_node.m_centroid);
|
|
||||||
if (dist > furthest_dist)
|
|
||||||
{
|
|
||||||
furthest_dist = dist;
|
|
||||||
furthest = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorType opposite;
|
|
||||||
double opposite_dist = -1.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
|
|
||||||
double dist = v.squared_distance(furthest);
|
|
||||||
if (dist > opposite_dist)
|
|
||||||
{
|
|
||||||
opposite_dist = dist;
|
|
||||||
opposite = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorType axis(opposite - furthest);
|
|
||||||
if (axis.normalize() < .000125f)
|
|
||||||
{
|
|
||||||
left_child_res = (furthest + parent_node.m_centroid) * .5f;
|
|
||||||
right_child_res = (opposite + parent_node.m_centroid) * .5f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint iter = 0; iter < 2; iter++)
|
|
||||||
{
|
|
||||||
double next_axis[N];
|
|
||||||
utils::zero_object(next_axis);
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const double weight = m_training_vecs[parent_node.m_vectors[i]].second;
|
|
||||||
|
|
||||||
VectorType v(m_training_vecs[parent_node.m_vectors[i]].first - parent_node.m_centroid);
|
|
||||||
|
|
||||||
double dot = (v * axis) * weight;
|
|
||||||
|
|
||||||
for (uint j = 0; j < N; j++)
|
|
||||||
next_axis[j] += dot * v[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
double w = 0.0f;
|
|
||||||
for (uint j = 0; j < N; j++)
|
|
||||||
w += next_axis[j] * next_axis[j];
|
|
||||||
|
|
||||||
if (w > 0.0f)
|
|
||||||
{
|
|
||||||
w = 1.0f / sqrt(w);
|
|
||||||
for (uint j = 0; j < N; j++)
|
|
||||||
axis[j] = static_cast<float>(next_axis[j] * w);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorType left_child(0.0f);
|
|
||||||
VectorType right_child(0.0f);
|
|
||||||
|
|
||||||
double left_weight = 0.0f;
|
|
||||||
double right_weight = 0.0f;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const float weight = (float)m_training_vecs[parent_node.m_vectors[i]].second;
|
|
||||||
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
|
|
||||||
double t = (v - parent_node.m_centroid) * axis;
|
|
||||||
if (t < 0.0f)
|
|
||||||
{
|
|
||||||
left_child += v * weight;
|
|
||||||
left_weight += weight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
right_child += v * weight;
|
|
||||||
right_weight += weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((left_weight > 0.0f) && (right_weight > 0.0f))
|
|
||||||
{
|
|
||||||
left_child_res = left_child * (float)(1.0f / left_weight);
|
|
||||||
right_child_res = right_child * (float)(1.0f / right_weight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
left_child_res = (furthest + parent_node.m_centroid) * .5f;
|
|
||||||
right_child_res = (opposite + parent_node.m_centroid) * .5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// thread safety warning: shared state!
|
|
||||||
crnlib::vector<uint> m_left_children;
|
|
||||||
crnlib::vector<uint> m_right_children;
|
|
||||||
|
|
||||||
void split_node(uint index)
|
|
||||||
{
|
|
||||||
vq_node& parent_node = m_nodes[index];
|
|
||||||
|
|
||||||
if (parent_node.m_vectors.size() == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
VectorType left_child, right_child;
|
|
||||||
if (m_quick)
|
|
||||||
compute_split_estimate(left_child, right_child, parent_node);
|
|
||||||
else
|
|
||||||
compute_split_pca(left_child, right_child, parent_node);
|
|
||||||
|
|
||||||
uint64 left_weight = 0;
|
|
||||||
uint64 right_weight = 0;
|
|
||||||
|
|
||||||
float prev_total_variance = 1e+10f;
|
|
||||||
|
|
||||||
float left_variance = 0.0f;
|
|
||||||
float right_variance = 0.0f;
|
|
||||||
|
|
||||||
const uint cMaxLoops = m_quick ? 2 : 8;
|
|
||||||
for (uint total_loops = 0; total_loops < cMaxLoops; total_loops++)
|
|
||||||
{
|
|
||||||
m_left_children.resize(0);
|
|
||||||
m_right_children.resize(0);
|
|
||||||
|
|
||||||
VectorType new_left_child(cClear);
|
|
||||||
VectorType new_right_child(cClear);
|
|
||||||
|
|
||||||
double left_ttsum = 0.0f;
|
|
||||||
double right_ttsum = 0.0f;
|
|
||||||
|
|
||||||
left_weight = 0;
|
|
||||||
right_weight = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
|
|
||||||
{
|
|
||||||
const VectorType& v = m_training_vecs[parent_node.m_vectors[i]].first;
|
|
||||||
const uint weight = m_training_vecs[parent_node.m_vectors[i]].second;
|
|
||||||
|
|
||||||
double left_dist2 = left_child.squared_distance(v);
|
|
||||||
double right_dist2 = right_child.squared_distance(v);
|
|
||||||
|
|
||||||
if (left_dist2 < right_dist2)
|
|
||||||
{
|
|
||||||
m_left_children.push_back(parent_node.m_vectors[i]);
|
|
||||||
|
|
||||||
new_left_child += (v * (float)weight);
|
|
||||||
left_weight += weight;
|
|
||||||
|
|
||||||
left_ttsum += v.dot(v) * weight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_right_children.push_back(parent_node.m_vectors[i]);
|
|
||||||
|
|
||||||
new_right_child += (v * (float)weight);
|
|
||||||
right_weight += weight;
|
|
||||||
|
|
||||||
right_ttsum += v.dot(v) * weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!left_weight) || (!right_weight))
|
|
||||||
{
|
|
||||||
parent_node.m_unsplittable = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
left_variance = (float)(left_ttsum - (new_left_child.dot(new_left_child) / left_weight));
|
|
||||||
right_variance = (float)(right_ttsum - (new_right_child.dot(new_right_child) / right_weight));
|
|
||||||
|
|
||||||
new_left_child *= (1.0f / left_weight);
|
|
||||||
new_right_child *= (1.0f / right_weight);
|
|
||||||
|
|
||||||
left_child = new_left_child;
|
|
||||||
left_weight = left_weight;
|
|
||||||
|
|
||||||
right_child = new_right_child;
|
|
||||||
right_weight = right_weight;
|
|
||||||
|
|
||||||
float total_variance = left_variance + right_variance;
|
|
||||||
if (total_variance < .00001f)
|
|
||||||
break;
|
|
||||||
|
|
||||||
//const float variance_delta_thresh = .00001f;
|
|
||||||
const float variance_delta_thresh = .00125f;
|
|
||||||
if (((prev_total_variance - total_variance) / total_variance) < variance_delta_thresh)
|
|
||||||
break;
|
|
||||||
|
|
||||||
prev_total_variance = total_variance;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint left_child_index = m_nodes.size();
|
|
||||||
const uint right_child_index = m_nodes.size() + 1;
|
|
||||||
|
|
||||||
parent_node.m_left = m_nodes.size();
|
|
||||||
parent_node.m_right = m_nodes.size() + 1;
|
|
||||||
parent_node.m_codebook_index = m_split_index;
|
|
||||||
m_split_index++;
|
|
||||||
|
|
||||||
m_nodes.resize(m_nodes.size() + 2);
|
|
||||||
|
|
||||||
// parent_node is invalid now, because m_nodes has been changed
|
|
||||||
|
|
||||||
vq_node& left_child_node = m_nodes[left_child_index];
|
|
||||||
vq_node& right_child_node = m_nodes[right_child_index];
|
|
||||||
|
|
||||||
left_child_node.m_centroid = left_child;
|
|
||||||
left_child_node.m_total_weight = left_weight;
|
|
||||||
left_child_node.m_vectors.swap(m_left_children);
|
|
||||||
left_child_node.m_variance = left_variance;
|
|
||||||
if ((left_child_node.m_vectors.size() > 1) && (left_child_node.m_variance > 0.0f))
|
|
||||||
insert_heap(left_child_index);
|
|
||||||
|
|
||||||
right_child_node.m_centroid = right_child;
|
|
||||||
right_child_node.m_total_weight = right_weight;
|
|
||||||
right_child_node.m_vectors.swap(m_right_children);
|
|
||||||
right_child_node.m_variance = right_variance;
|
|
||||||
if ((right_child_node.m_vectors.size() > 1) && (right_child_node.m_variance > 0.0f))
|
|
||||||
insert_heap(right_child_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,994 +0,0 @@
|
||||||
// File: crn_color.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_core.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
template<typename component_type> struct color_quad_component_traits
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = false,
|
|
||||||
cFloat = false,
|
|
||||||
cMin = cUINT8_MIN,
|
|
||||||
cMax = cUINT8_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<int8>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = true,
|
|
||||||
cFloat = false,
|
|
||||||
cMin = cINT8_MIN,
|
|
||||||
cMax = cINT8_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<int16>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = true,
|
|
||||||
cFloat = false,
|
|
||||||
cMin = cINT16_MIN,
|
|
||||||
cMax = cINT16_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<uint16>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = false,
|
|
||||||
cFloat = false,
|
|
||||||
cMin = cUINT16_MIN,
|
|
||||||
cMax = cUINT16_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<int32>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = true,
|
|
||||||
cFloat = false,
|
|
||||||
cMin = cINT32_MIN,
|
|
||||||
cMax = cINT32_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<uint32>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = false,
|
|
||||||
cFloat = false,
|
|
||||||
cMin = cUINT32_MIN,
|
|
||||||
cMax = cUINT32_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<float>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = false,
|
|
||||||
cFloat = true,
|
|
||||||
cMin = cINT32_MIN,
|
|
||||||
cMax = cINT32_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct color_quad_component_traits<double>
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cSigned = false,
|
|
||||||
cFloat = true,
|
|
||||||
cMin = cINT32_MIN,
|
|
||||||
cMax = cINT32_MAX
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename component_type, typename parameter_type>
|
|
||||||
class color_quad : public helpers::rel_ops<color_quad<component_type, parameter_type> >
|
|
||||||
{
|
|
||||||
template<typename T>
|
|
||||||
static inline parameter_type clamp(T v)
|
|
||||||
{
|
|
||||||
parameter_type result = static_cast<parameter_type>(v);
|
|
||||||
if (!component_traits::cFloat)
|
|
||||||
{
|
|
||||||
if (v < component_traits::cMin)
|
|
||||||
result = static_cast<parameter_type>(component_traits::cMin);
|
|
||||||
else if (v > component_traits::cMax)
|
|
||||||
result = static_cast<parameter_type>(component_traits::cMax);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
template<>
|
|
||||||
static inline parameter_type clamp(int v)
|
|
||||||
{
|
|
||||||
if (!component_traits::cFloat)
|
|
||||||
{
|
|
||||||
if ((!component_traits::cSigned) && (component_traits::cMin == 0) && (component_traits::cMax == 0xFF))
|
|
||||||
{
|
|
||||||
if (v & 0xFFFFFF00U)
|
|
||||||
v = (~(static_cast<int>(v) >> 31)) & 0xFF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (v < component_traits::cMin)
|
|
||||||
v = component_traits::cMin;
|
|
||||||
else if (v > component_traits::cMax)
|
|
||||||
v = component_traits::cMax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return static_cast<parameter_type>(v);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef component_type component_t;
|
|
||||||
typedef parameter_type parameter_t;
|
|
||||||
typedef color_quad_component_traits<component_type> component_traits;
|
|
||||||
|
|
||||||
enum { cNumComps = 4 };
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
component_type r;
|
|
||||||
component_type g;
|
|
||||||
component_type b;
|
|
||||||
component_type a;
|
|
||||||
};
|
|
||||||
|
|
||||||
component_type c[cNumComps];
|
|
||||||
|
|
||||||
uint32 m_u32;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline color_quad()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad(eClear) :
|
|
||||||
r(0), g(0), b(0), a(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad(const color_quad& other) :
|
|
||||||
r(other.r), g(other.g), b(other.b), a(other.a)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit inline color_quad(parameter_type y, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
set(y, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad(parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
set(red, green, blue, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit inline color_quad(eNoClamp, parameter_type y, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
set_noclamp_y_alpha(y, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad(eNoClamp, parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
set_noclamp_rgba(red, green, blue, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename other_component_type, typename other_parameter_type>
|
|
||||||
inline color_quad(const color_quad<other_component_type, other_parameter_type>& other) :
|
|
||||||
r(static_cast<component_type>(clamp(other.r))), g(static_cast<component_type>(clamp(other.g))), b(static_cast<component_type>(clamp(other.b))), a(static_cast<component_type>(clamp(other.a)))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
r = 0;
|
|
||||||
g = 0;
|
|
||||||
b = 0;
|
|
||||||
a = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& operator= (const color_quad& other)
|
|
||||||
{
|
|
||||||
r = other.r;
|
|
||||||
g = other.g;
|
|
||||||
b = other.b;
|
|
||||||
a = other.a;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set_rgb(const color_quad& other)
|
|
||||||
{
|
|
||||||
r = other.r;
|
|
||||||
g = other.g;
|
|
||||||
b = other.b;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename other_component_type, typename other_parameter_type>
|
|
||||||
inline color_quad& operator=(const color_quad<other_component_type, other_parameter_type>& other)
|
|
||||||
{
|
|
||||||
r = static_cast<component_type>(clamp(other.r));
|
|
||||||
g = static_cast<component_type>(clamp(other.g));
|
|
||||||
b = static_cast<component_type>(clamp(other.b));
|
|
||||||
a = static_cast<component_type>(clamp(other.a));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& operator= (parameter_type y)
|
|
||||||
{
|
|
||||||
set(y, component_traits::cMax);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set(parameter_type y, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
y = clamp(y);
|
|
||||||
alpha = clamp(alpha);
|
|
||||||
r = static_cast<component_type>(y);
|
|
||||||
g = static_cast<component_type>(y);
|
|
||||||
b = static_cast<component_type>(y);
|
|
||||||
a = static_cast<component_type>(alpha);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set_noclamp_y_alpha(parameter_type y, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT( (y >= component_traits::cMin) && (y <= component_traits::cMax) );
|
|
||||||
CRNLIB_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
|
|
||||||
|
|
||||||
r = static_cast<component_type>(y);
|
|
||||||
g = static_cast<component_type>(y);
|
|
||||||
b = static_cast<component_type>(y);
|
|
||||||
a = static_cast<component_type>(alpha);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set(parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha = component_traits::cMax)
|
|
||||||
{
|
|
||||||
r = static_cast<component_type>(clamp(red));
|
|
||||||
g = static_cast<component_type>(clamp(green));
|
|
||||||
b = static_cast<component_type>(clamp(blue));
|
|
||||||
a = static_cast<component_type>(clamp(alpha));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set_noclamp_rgba(parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
|
|
||||||
CRNLIB_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
|
|
||||||
CRNLIB_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
|
|
||||||
CRNLIB_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
|
|
||||||
|
|
||||||
r = static_cast<component_type>(red);
|
|
||||||
g = static_cast<component_type>(green);
|
|
||||||
b = static_cast<component_type>(blue);
|
|
||||||
a = static_cast<component_type>(alpha);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set_noclamp_rgb(parameter_type red, parameter_type green, parameter_type blue)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
|
|
||||||
CRNLIB_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
|
|
||||||
CRNLIB_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
|
|
||||||
|
|
||||||
r = static_cast<component_type>(red);
|
|
||||||
g = static_cast<component_type>(green);
|
|
||||||
b = static_cast<component_type>(blue);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline parameter_type get_min_comp() { return component_traits::cMin; }
|
|
||||||
static inline parameter_type get_max_comp() { return component_traits::cMax; }
|
|
||||||
static inline bool get_comps_are_signed() { return component_traits::cSigned; }
|
|
||||||
|
|
||||||
inline component_type operator[] (uint i) const { CRNLIB_ASSERT(i < cNumComps); return c[i]; }
|
|
||||||
inline component_type& operator[] (uint i) { CRNLIB_ASSERT(i < cNumComps); return c[i]; }
|
|
||||||
|
|
||||||
inline color_quad& set_component(uint i, parameter_type f)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(i < cNumComps);
|
|
||||||
|
|
||||||
c[i] = static_cast<component_type>(clamp(f));
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& set_grayscale(parameter_t l)
|
|
||||||
{
|
|
||||||
component_t x = static_cast<component_t>(clamp(l));
|
|
||||||
c[0] = x;
|
|
||||||
c[1] = x;
|
|
||||||
c[2] = x;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& clamp(const color_quad& l, const color_quad& h)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < cNumComps; i++)
|
|
||||||
c[i] = static_cast<component_type>(math::clamp<parameter_type>(c[i], l[i], h[i]));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad& clamp(parameter_type l, parameter_type h)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < cNumComps; i++)
|
|
||||||
c[i] = static_cast<component_type>(math::clamp<parameter_type>(c[i], l, h));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y).
|
|
||||||
inline parameter_type get_luma() const
|
|
||||||
{
|
|
||||||
return static_cast<parameter_type>((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns REC 709 luma.
|
|
||||||
inline parameter_type get_luma_rec709() const
|
|
||||||
{
|
|
||||||
return static_cast<parameter_type>((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Beware of endianness!
|
|
||||||
inline uint32 get_uint32() const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(sizeof(*this) == sizeof(uint32));
|
|
||||||
return *reinterpret_cast<const uint32*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Beware of endianness!
|
|
||||||
inline uint64 get_uint64() const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(sizeof(*this) == sizeof(uint64));
|
|
||||||
return *reinterpret_cast<const uint64*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint squared_distance(const color_quad& c, bool alpha = true) const
|
|
||||||
{
|
|
||||||
return math::square(r - c.r) + math::square(g - c.g) + math::square(b - c.b) + (alpha ? math::square(a - c.a) : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool rgb_equals(const color_quad& rhs) const
|
|
||||||
{
|
|
||||||
return (r == rhs.r) && (g == rhs.g) && (b == rhs.b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator== (const color_quad& rhs) const
|
|
||||||
{
|
|
||||||
if (sizeof(color_quad) == sizeof(uint32))
|
|
||||||
return m_u32 == rhs.m_u32;
|
|
||||||
else
|
|
||||||
return (r == rhs.r) && (g == rhs.g) && (b == rhs.b) && (a == rhs.a);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator< (const color_quad& rhs) const
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < cNumComps; i++)
|
|
||||||
{
|
|
||||||
if (c[i] < rhs.c[i])
|
|
||||||
return true;
|
|
||||||
else if (!(c[i] == rhs.c[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad& operator+= (const color_quad& other)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
c[i] = static_cast<component_type>(clamp(c[i] + other.c[i]));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad& operator-= (const color_quad& other)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
c[i] = static_cast<component_type>(clamp(c[i] - other.c[i]));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad& operator*= (parameter_type v)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
c[i] = static_cast<component_type>(clamp(c[i] * v));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad& operator/= (parameter_type v)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
c[i] = static_cast<component_type>(c[i] / v);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad get_swizzled(uint x, uint y, uint z, uint w) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x | y | z | w) < 4);
|
|
||||||
return color_quad(c[x], c[y], c[z], c[w]);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend color_quad operator+ (const color_quad& lhs, const color_quad& rhs)
|
|
||||||
{
|
|
||||||
color_quad result(lhs);
|
|
||||||
result += rhs;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend color_quad operator- (const color_quad& lhs, const color_quad& rhs)
|
|
||||||
{
|
|
||||||
color_quad result(lhs);
|
|
||||||
result -= rhs;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend color_quad operator* (const color_quad& lhs, parameter_type v)
|
|
||||||
{
|
|
||||||
color_quad result(lhs);
|
|
||||||
result *= v;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend color_quad operator/ (const color_quad& lhs, parameter_type v)
|
|
||||||
{
|
|
||||||
color_quad result(lhs);
|
|
||||||
result /= v;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend color_quad operator* (parameter_type v, const color_quad& rhs)
|
|
||||||
{
|
|
||||||
color_quad result(rhs);
|
|
||||||
result *= v;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_grayscale() const
|
|
||||||
{
|
|
||||||
return (c[0] == c[1]) && (c[1] == c[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_min_component_index(bool alpha = true) const
|
|
||||||
{
|
|
||||||
uint index = 0;
|
|
||||||
uint limit = alpha ? cNumComps : (cNumComps - 1);
|
|
||||||
for (uint i = 1; i < limit; i++)
|
|
||||||
if (c[i] < c[index])
|
|
||||||
index = i;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_max_component_index(bool alpha = true) const
|
|
||||||
{
|
|
||||||
uint index = 0;
|
|
||||||
uint limit = alpha ? cNumComps : (cNumComps - 1);
|
|
||||||
for (uint i = 1; i < limit; i++)
|
|
||||||
if (c[i] > c[index])
|
|
||||||
index = i;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator size_t() const
|
|
||||||
{
|
|
||||||
return (size_t)fast_hash(this, sizeof(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_float4(float* pDst)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
pDst[i] = ((*this)[i] - component_traits::cMin) / float(component_traits::cMax - component_traits::cMin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_float3(float* pDst)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < 3; i++)
|
|
||||||
pDst[i] = ((*this)[i] - component_traits::cMin) / float(component_traits::cMax - component_traits::cMin);
|
|
||||||
}
|
|
||||||
|
|
||||||
static color_quad component_min(const color_quad& a, const color_quad& b)
|
|
||||||
{
|
|
||||||
color_quad result;
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
result[i] = static_cast<component_type>(math::minimum(a[i], b[i]));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static color_quad component_max(const color_quad& a, const color_quad& b)
|
|
||||||
{
|
|
||||||
color_quad result;
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
result[i] = static_cast<component_type>(math::maximum(a[i], b[i]));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static color_quad make_black()
|
|
||||||
{
|
|
||||||
return color_quad(0, 0, 0, component_traits::cMax);
|
|
||||||
}
|
|
||||||
|
|
||||||
static color_quad make_white()
|
|
||||||
{
|
|
||||||
return color_quad(component_traits::cMax, component_traits::cMax, component_traits::cMax, component_traits::cMax);
|
|
||||||
}
|
|
||||||
}; // class color_quad
|
|
||||||
|
|
||||||
template<typename c, typename q>
|
|
||||||
struct scalar_type< color_quad<c, q> >
|
|
||||||
{
|
|
||||||
enum { cFlag = true };
|
|
||||||
static inline void construct(color_quad<c, q>* p) { }
|
|
||||||
static inline void construct(color_quad<c, q>* p, const color_quad<c, q>& init) { memcpy(p, &init, sizeof(color_quad<c, q>)); }
|
|
||||||
static inline void construct_array(color_quad<c, q>* p, uint n) { p, n; }
|
|
||||||
static inline void destruct(color_quad<c, q>* p) { p; }
|
|
||||||
static inline void destruct_array(color_quad<c, q>* p, uint n) { p, n; }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef color_quad<uint8, int> color_quad_u8;
|
|
||||||
typedef color_quad<int8, int> color_quad_i8;
|
|
||||||
typedef color_quad<int16, int> color_quad_i16;
|
|
||||||
typedef color_quad<uint16, int> color_quad_u16;
|
|
||||||
typedef color_quad<int32, int> color_quad_i32;
|
|
||||||
typedef color_quad<uint32, uint> color_quad_u32;
|
|
||||||
typedef color_quad<float, float> color_quad_f;
|
|
||||||
typedef color_quad<double, double> color_quad_d;
|
|
||||||
|
|
||||||
namespace color
|
|
||||||
{
|
|
||||||
inline uint elucidian_distance(uint r0, uint g0, uint b0, uint r1, uint g1, uint b1)
|
|
||||||
{
|
|
||||||
int dr = (int)r0 - (int)r1;
|
|
||||||
int dg = (int)g0 - (int)g1;
|
|
||||||
int db = (int)b0 - (int)b1;
|
|
||||||
|
|
||||||
return static_cast<uint>(dr * dr + dg * dg + db * db);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint elucidian_distance(uint r0, uint g0, uint b0, uint a0, uint r1, uint g1, uint b1, uint a1)
|
|
||||||
{
|
|
||||||
int dr = (int)r0 - (int)r1;
|
|
||||||
int dg = (int)g0 - (int)g1;
|
|
||||||
int db = (int)b0 - (int)b1;
|
|
||||||
int da = (int)a0 - (int)a1;
|
|
||||||
|
|
||||||
return static_cast<uint>(dr * dr + dg * dg + db * db + da * da);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint elucidian_distance(const color_quad_u8& c0, const color_quad_u8& c1, bool alpha)
|
|
||||||
{
|
|
||||||
if (alpha)
|
|
||||||
return elucidian_distance(c0.r, c0.g, c0.b, c0.a, c1.r, c1.g, c1.b, c1.a);
|
|
||||||
else
|
|
||||||
return elucidian_distance(c0.r, c0.g, c0.b, c1.r, c1.g, c1.b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint weighted_elucidian_distance(uint r0, uint g0, uint b0, uint r1, uint g1, uint b1, uint wr, uint wg, uint wb)
|
|
||||||
{
|
|
||||||
int dr = (int)r0 - (int)r1;
|
|
||||||
int dg = (int)g0 - (int)g1;
|
|
||||||
int db = (int)b0 - (int)b1;
|
|
||||||
|
|
||||||
return static_cast<uint>((wr * dr * dr) + (wg * dg * dg) + (wb * db * db));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint weighted_elucidian_distance(
|
|
||||||
uint r0, uint g0, uint b0, uint a0,
|
|
||||||
uint r1, uint g1, uint b1, uint a1,
|
|
||||||
uint wr, uint wg, uint wb, uint wa)
|
|
||||||
{
|
|
||||||
int dr = (int)r0 - (int)r1;
|
|
||||||
int dg = (int)g0 - (int)g1;
|
|
||||||
int db = (int)b0 - (int)b1;
|
|
||||||
int da = (int)a0 - (int)a1;
|
|
||||||
|
|
||||||
return static_cast<uint>((wr * dr * dr) + (wg * dg * dg) + (wb * db * db) + (wa * da * da));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint weighted_elucidian_distance(const color_quad_u8& c0, const color_quad_u8& c1, uint wr, uint wg, uint wb, uint wa)
|
|
||||||
{
|
|
||||||
return weighted_elucidian_distance(c0.r, c0.g, c0.b, c0.a, c1.r, c1.g, c1.b, c1.a, wr, wg, wb, wa);
|
|
||||||
}
|
|
||||||
|
|
||||||
//const uint cRWeight = 8;//24;
|
|
||||||
//const uint cGWeight = 24;//73;
|
|
||||||
//const uint cBWeight = 1;//3;
|
|
||||||
|
|
||||||
const uint cRWeight = 8;//24;
|
|
||||||
const uint cGWeight = 25;//73;
|
|
||||||
const uint cBWeight = 1;//3;
|
|
||||||
|
|
||||||
inline uint color_distance(bool perceptual, const color_quad_u8& e1, const color_quad_u8& e2, bool alpha)
|
|
||||||
{
|
|
||||||
if (perceptual)
|
|
||||||
{
|
|
||||||
if (alpha)
|
|
||||||
return weighted_elucidian_distance(e1, e2, cRWeight, cGWeight, cBWeight, cRWeight+cGWeight+cBWeight);
|
|
||||||
else
|
|
||||||
return weighted_elucidian_distance(e1, e2, cRWeight, cGWeight, cBWeight, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return elucidian_distance(e1, e2, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint peak_color_error(const color_quad_u8& e1, const color_quad_u8& e2)
|
|
||||||
{
|
|
||||||
return math::maximum<uint>(labs(e1[0] - e2[0]), labs(e1[1] - e2[1]), labs(e1[2] - e2[2]));
|
|
||||||
//return math::square<int>(e1[0] - e2[0]) + math::square<int>(e1[1] - e2[1]) + math::square<int>(e1[2] - e2[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// y - [0,255]
|
|
||||||
// co - [-127,127]
|
|
||||||
// cg - [-126,127]
|
|
||||||
inline void RGB_to_YCoCg(int r, int g, int b, int& y, int& co, int& cg)
|
|
||||||
{
|
|
||||||
y = (r >> 2) + (g >> 1) + (b >> 2);
|
|
||||||
co = (r >> 1) - (b >> 1);
|
|
||||||
cg = -(r >> 2) + (g >> 1) - (b >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void YCoCg_to_RGB(int y, int co, int cg, int& r, int& g, int& b)
|
|
||||||
{
|
|
||||||
int tmp = y - cg;
|
|
||||||
g = y + cg;
|
|
||||||
r = tmp + co;
|
|
||||||
b = tmp - co;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8 clamp_component(int i) { if (static_cast<uint>(i) > 255U) { if (i < 0) i = 0; else if (i > 255) i = 255; } return static_cast<uint8>(i); }
|
|
||||||
|
|
||||||
// RGB->YCbCr constants, scaled by 2^16
|
|
||||||
const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329;
|
|
||||||
// YCbCr->RGB constants, scaled by 2^16
|
|
||||||
const int R_CR = 91881, B_CB = 116130, G_CR = -46802, G_CB = -22554;
|
|
||||||
|
|
||||||
inline int RGB_to_Y(const color_quad_u8& rgb)
|
|
||||||
{
|
|
||||||
const int r = rgb[0], g = rgb[1], b = rgb[2];
|
|
||||||
return (r * YR + g * YG + b * YB + 32768) >> 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RGB to YCbCr (same as JFIF JPEG).
|
|
||||||
// Odd default biases account for 565 endpoint packing.
|
|
||||||
inline void RGB_to_YCC(color_quad_u8& ycc, const color_quad_u8& rgb, int cb_bias = 123, int cr_bias = 125)
|
|
||||||
{
|
|
||||||
const int r = rgb[0], g = rgb[1], b = rgb[2];
|
|
||||||
ycc.a = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
|
||||||
ycc.r = clamp_component(cb_bias + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
|
|
||||||
ycc.g = clamp_component(cr_bias + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
|
|
||||||
ycc.b = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// YCbCr to RGB.
|
|
||||||
// Odd biases account for 565 endpoint packing.
|
|
||||||
inline void YCC_to_RGB(color_quad_u8& rgb, const color_quad_u8& ycc, int cb_bias = 123, int cr_bias = 125)
|
|
||||||
{
|
|
||||||
const int y = ycc.a;
|
|
||||||
const int cb = ycc.r - cb_bias;
|
|
||||||
const int cr = ycc.g - cr_bias;
|
|
||||||
rgb.r = clamp_component(y + ((R_CR * cr + 32768) >> 16));
|
|
||||||
rgb.g = clamp_component(y + ((G_CR * cr + G_CB * cb + 32768) >> 16));
|
|
||||||
rgb.b = clamp_component(y + ((B_CB * cb + 32768) >> 16));
|
|
||||||
rgb.a = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float RGB->YCbCr constants
|
|
||||||
const float S = 1.0f/65536.0f;
|
|
||||||
const float F_YR = S*YR, F_YG = S*YG, F_YB = S*YB, F_CB_R = S*CB_R, F_CB_G = S*CB_G, F_CB_B = S*CB_B, F_CR_R = S*CR_R, F_CR_G = S*CR_G, F_CR_B = S*CR_B;
|
|
||||||
// Float YCbCr->RGB constants
|
|
||||||
const float F_R_CR = S*R_CR, F_B_CB = S*B_CB, F_G_CR = S*G_CR, F_G_CB = S*G_CB;
|
|
||||||
|
|
||||||
inline void RGB_to_YCC_float(color_quad_f& ycc, const color_quad_u8& rgb)
|
|
||||||
{
|
|
||||||
const int r = rgb[0], g = rgb[1], b = rgb[2];
|
|
||||||
ycc.a = r * F_YR + g * F_YG + b * F_YB;
|
|
||||||
ycc.r = r * F_CB_R + g * F_CB_G + b * F_CB_B;
|
|
||||||
ycc.g = r * F_CR_R + g * F_CR_G + b * F_CR_B;
|
|
||||||
ycc.b = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void YCC_float_to_RGB(color_quad_u8& rgb, const color_quad_f& ycc)
|
|
||||||
{
|
|
||||||
float y = ycc.a, cb = ycc.r, cr = ycc.g;
|
|
||||||
rgb.r = color::clamp_component(static_cast<int>(.5f + y + F_R_CR * cr));
|
|
||||||
rgb.g = color::clamp_component(static_cast<int>(.5f + y + F_G_CR * cr + F_G_CB * cb));
|
|
||||||
rgb.b = color::clamp_component(static_cast<int>(.5f + y + F_B_CB * cb));
|
|
||||||
rgb.a = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace color
|
|
||||||
|
|
||||||
// This class purposely trades off speed for extremely flexibility. It can handle any component swizzle, any pixel type from 1-4 components and 1-32 bits/component,
|
|
||||||
// any pixel size between 1-16 bytes/pixel, any pixel stride, any color_quad data type (signed/unsigned/float 8/16/32 bits/component), and scaled/non-scaled components.
|
|
||||||
// On the downside, it's freaking slow.
|
|
||||||
class pixel_packer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
pixel_packer()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pixel_packer(uint num_comps, uint bits_per_comp, int pixel_stride = -1, bool reversed = false)
|
|
||||||
{
|
|
||||||
init(num_comps, bits_per_comp, pixel_stride, reversed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pixel_packer(const char* pComp_map, int pixel_stride = -1, int force_comp_size = -1)
|
|
||||||
{
|
|
||||||
init(pComp_map, pixel_stride, force_comp_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
utils::zero_this(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_valid() const { return m_pixel_stride > 0; }
|
|
||||||
|
|
||||||
inline uint get_pixel_stride() const { return m_pixel_stride; }
|
|
||||||
void set_pixel_stride(uint n) { m_pixel_stride = n; }
|
|
||||||
|
|
||||||
uint get_num_comps() const { return m_num_comps; }
|
|
||||||
uint get_comp_size(uint index) const { CRNLIB_ASSERT(index < 4); return m_comp_size[index]; }
|
|
||||||
uint get_comp_ofs(uint index) const { CRNLIB_ASSERT(index < 4); return m_comp_ofs[index]; }
|
|
||||||
uint get_comp_max(uint index) const { CRNLIB_ASSERT(index < 4); return m_comp_max[index]; }
|
|
||||||
bool get_rgb_is_luma() const { return m_rgb_is_luma; }
|
|
||||||
|
|
||||||
template<typename color_quad_type>
|
|
||||||
const void* unpack(const void* p, color_quad_type& color, bool rescale = true) const
|
|
||||||
{
|
|
||||||
const uint8* pSrc = static_cast<const uint8*>(p);
|
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
const uint comp_size = m_comp_size[i];
|
|
||||||
if (!comp_size)
|
|
||||||
{
|
|
||||||
if (color_quad_type::component_traits::cFloat)
|
|
||||||
color[i] = static_cast< typename color_quad_type::parameter_t >((i == 3) ? 1 : 0);
|
|
||||||
else
|
|
||||||
color[i] = static_cast< typename color_quad_type::parameter_t >((i == 3) ? color_quad_type::component_traits::cMax : 0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint n = 0, dst_bit_ofs = 0;
|
|
||||||
uint src_bit_ofs = m_comp_ofs[i];
|
|
||||||
while (dst_bit_ofs < comp_size)
|
|
||||||
{
|
|
||||||
const uint byte_bit_ofs = src_bit_ofs & 7;
|
|
||||||
n |= ((pSrc[src_bit_ofs >> 3] >> byte_bit_ofs) << dst_bit_ofs);
|
|
||||||
|
|
||||||
const uint bits_read = 8 - byte_bit_ofs;
|
|
||||||
src_bit_ofs += bits_read;
|
|
||||||
dst_bit_ofs += bits_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 mx = m_comp_max[i];
|
|
||||||
n &= mx;
|
|
||||||
|
|
||||||
const uint32 h = static_cast<uint32>(color_quad_type::component_traits::cMax);
|
|
||||||
|
|
||||||
if (color_quad_type::component_traits::cFloat)
|
|
||||||
color.set_component(i, static_cast<typename color_quad_type::parameter_t>(n));
|
|
||||||
else if (rescale)
|
|
||||||
color.set_component(i, static_cast<typename color_quad_type::parameter_t>( (static_cast<uint64>(n) * h + (mx >> 1U)) / mx ) );
|
|
||||||
else if (color_quad_type::component_traits::cSigned)
|
|
||||||
color.set_component(i, static_cast<typename color_quad_type::parameter_t>(math::minimum<uint32>(n, h)));
|
|
||||||
else
|
|
||||||
color.set_component(i, static_cast<typename color_quad_type::parameter_t>(n));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_rgb_is_luma)
|
|
||||||
{
|
|
||||||
color[0] = color[1];
|
|
||||||
color[2] = color[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return pSrc + m_pixel_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename color_quad_type>
|
|
||||||
void* pack(const color_quad_type& color, void* p, bool rescale = true) const
|
|
||||||
{
|
|
||||||
uint8* pDst = static_cast<uint8*>(p);
|
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
const uint comp_size = m_comp_size[i];
|
|
||||||
if (!comp_size)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint32 mx = m_comp_max[i];
|
|
||||||
|
|
||||||
uint32 n;
|
|
||||||
if (color_quad_type::component_traits::cFloat)
|
|
||||||
{
|
|
||||||
typename color_quad_type::parameter_t t = color[i];
|
|
||||||
if (t < 0.0f)
|
|
||||||
n = 0;
|
|
||||||
else if (t > static_cast<typename color_quad_type::parameter_t>(mx))
|
|
||||||
n = mx;
|
|
||||||
else
|
|
||||||
n = math::minimum<uint32>(static_cast<uint32>(floor(t + .5f)), mx);
|
|
||||||
}
|
|
||||||
else if (rescale)
|
|
||||||
{
|
|
||||||
if (color_quad_type::component_traits::cSigned)
|
|
||||||
n = math::maximum<int>(static_cast<int>(color[i]), 0);
|
|
||||||
else
|
|
||||||
n = static_cast<uint32>(color[i]);
|
|
||||||
|
|
||||||
const uint32 h = static_cast<uint32>(color_quad_type::component_traits::cMax);
|
|
||||||
n = static_cast<uint32>((static_cast<uint64>(n) * mx + (h >> 1)) / h);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (color_quad_type::component_traits::cSigned)
|
|
||||||
n = math::minimum<uint32>(static_cast<uint32>(math::maximum<int>(static_cast<int>(color[i]), 0)), mx);
|
|
||||||
else
|
|
||||||
n = math::minimum<uint32>(static_cast<uint32>(color[i]), mx);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint src_bit_ofs = 0;
|
|
||||||
uint dst_bit_ofs = m_comp_ofs[i];
|
|
||||||
while (src_bit_ofs < comp_size)
|
|
||||||
{
|
|
||||||
const uint cur_byte_bit_ofs = (dst_bit_ofs & 7);
|
|
||||||
const uint cur_byte_bits = 8 - cur_byte_bit_ofs;
|
|
||||||
|
|
||||||
uint byte_val = pDst[dst_bit_ofs >> 3];
|
|
||||||
uint bit_mask = (mx << cur_byte_bit_ofs) & 0xFF;
|
|
||||||
byte_val &= ~bit_mask;
|
|
||||||
byte_val |= (n << cur_byte_bit_ofs);
|
|
||||||
pDst[dst_bit_ofs >> 3] = static_cast<uint8>(byte_val);
|
|
||||||
|
|
||||||
mx >>= cur_byte_bits;
|
|
||||||
n >>= cur_byte_bits;
|
|
||||||
|
|
||||||
dst_bit_ofs += cur_byte_bits;
|
|
||||||
src_bit_ofs += cur_byte_bits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pDst + m_pixel_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(uint num_comps, uint bits_per_comp, int pixel_stride = -1, bool reversed = false)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if ((num_comps < 1) || (num_comps > 4) || (bits_per_comp < 1) || (bits_per_comp > 32))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint i = 0; i < num_comps; i++)
|
|
||||||
{
|
|
||||||
m_comp_size[i] = bits_per_comp;
|
|
||||||
m_comp_ofs[i] = i * bits_per_comp;
|
|
||||||
if (reversed)
|
|
||||||
m_comp_ofs[i] = ((num_comps - 1) * bits_per_comp) - m_comp_ofs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
m_comp_max[i] = static_cast<uint32>((1ULL << m_comp_size[i]) - 1ULL);
|
|
||||||
|
|
||||||
m_pixel_stride = (pixel_stride >= 0) ? pixel_stride : (num_comps * bits_per_comp + 7) / 8;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format examples:
|
|
||||||
// R16G16B16
|
|
||||||
// B5G6R5
|
|
||||||
// B5G5R5x1
|
|
||||||
// Y8A8
|
|
||||||
// A8R8G8B8
|
|
||||||
// First component is at LSB in memory. Assumes unsigned integer components, 1-32bits each.
|
|
||||||
bool init(const char* pComp_map, int pixel_stride = -1, int force_comp_size = -1)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
uint cur_bit_ofs = 0;
|
|
||||||
|
|
||||||
while (*pComp_map)
|
|
||||||
{
|
|
||||||
char c = *pComp_map++;
|
|
||||||
|
|
||||||
int comp_index = -1;
|
|
||||||
if (c == 'R')
|
|
||||||
comp_index = 0;
|
|
||||||
else if (c == 'G')
|
|
||||||
comp_index = 1;
|
|
||||||
else if (c == 'B')
|
|
||||||
comp_index = 2;
|
|
||||||
else if (c == 'A')
|
|
||||||
comp_index = 3;
|
|
||||||
else if (c == 'Y')
|
|
||||||
comp_index = 4;
|
|
||||||
else if (c != 'x')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint comp_size = 0;
|
|
||||||
|
|
||||||
uint n = *pComp_map;
|
|
||||||
if ((n >= '0') && (n <= '9'))
|
|
||||||
{
|
|
||||||
comp_size = n - '0';
|
|
||||||
pComp_map++;
|
|
||||||
|
|
||||||
n = *pComp_map;
|
|
||||||
if ((n >= '0') && (n <= '9'))
|
|
||||||
{
|
|
||||||
comp_size = (comp_size * 10) + (n - '0');
|
|
||||||
pComp_map++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force_comp_size != -1)
|
|
||||||
comp_size = force_comp_size;
|
|
||||||
|
|
||||||
if ((!comp_size) || (comp_size > 32))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (comp_index == 4)
|
|
||||||
{
|
|
||||||
if (m_comp_size[0] || m_comp_size[1] || m_comp_size[2])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//m_comp_ofs[0] = m_comp_ofs[1] = m_comp_ofs[2] = cur_bit_ofs;
|
|
||||||
//m_comp_size[0] = m_comp_size[1] = m_comp_size[2] = comp_size;
|
|
||||||
m_comp_ofs[1] = cur_bit_ofs;
|
|
||||||
m_comp_size[1] = comp_size;
|
|
||||||
m_rgb_is_luma = true;
|
|
||||||
m_num_comps++;
|
|
||||||
}
|
|
||||||
else if (comp_index >= 0)
|
|
||||||
{
|
|
||||||
if (m_comp_size[comp_index])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_comp_ofs[comp_index] = cur_bit_ofs;
|
|
||||||
m_comp_size[comp_index] = comp_size;
|
|
||||||
m_num_comps++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_bit_ofs += comp_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
m_comp_max[i] = static_cast<uint32>((1ULL << m_comp_size[i]) - 1ULL);
|
|
||||||
|
|
||||||
if (pixel_stride >= 0)
|
|
||||||
m_pixel_stride = pixel_stride;
|
|
||||||
else
|
|
||||||
m_pixel_stride = (cur_bit_ofs + 7) / 8;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint m_pixel_stride;
|
|
||||||
uint m_num_comps;
|
|
||||||
uint m_comp_size[4];
|
|
||||||
uint m_comp_ofs[4];
|
|
||||||
uint m_comp_max[4];
|
|
||||||
bool m_rgb_is_luma;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
// File: crn_colorized_console.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_colorized_console.h"
|
|
||||||
#ifdef CRNLIB_USE_WIN32_API
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
void colorized_console::init()
|
|
||||||
{
|
|
||||||
console::init();
|
|
||||||
console::add_console_output_func(console_output_func, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void colorized_console::deinit()
|
|
||||||
{
|
|
||||||
console::remove_console_output_func(console_output_func);
|
|
||||||
console::deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void colorized_console::tick()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CRNLIB_USE_WIN32_API
|
|
||||||
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
|
|
||||||
{
|
|
||||||
pData;
|
|
||||||
|
|
||||||
if (console::get_output_disabled())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
HANDLE cons = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
|
|
||||||
DWORD attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case cDebugConsoleMessage: attr = FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
|
||||||
case cMessageConsoleMessage: attr = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
|
||||||
case cWarningConsoleMessage: attr = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break;
|
|
||||||
case cErrorConsoleMessage: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (INVALID_HANDLE_VALUE != cons)
|
|
||||||
SetConsoleTextAttribute(cons, (WORD)attr);
|
|
||||||
|
|
||||||
if ((console::get_prefixes()) && (console::get_at_beginning_of_line()))
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case cDebugConsoleMessage:
|
|
||||||
printf("Debug: %s", pMsg);
|
|
||||||
break;
|
|
||||||
case cWarningConsoleMessage:
|
|
||||||
printf("Warning: %s", pMsg);
|
|
||||||
break;
|
|
||||||
case cErrorConsoleMessage:
|
|
||||||
printf("Error: %s", pMsg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("%s", pMsg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", pMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (console::get_crlf())
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
if (INVALID_HANDLE_VALUE != cons)
|
|
||||||
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
|
|
||||||
{
|
|
||||||
pData;
|
|
||||||
if (console::get_output_disabled())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ((console::get_prefixes()) && (console::get_at_beginning_of_line()))
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case cDebugConsoleMessage:
|
|
||||||
printf("Debug: %s", pMsg);
|
|
||||||
break;
|
|
||||||
case cWarningConsoleMessage:
|
|
||||||
printf("Warning: %s", pMsg);
|
|
||||||
break;
|
|
||||||
case cErrorConsoleMessage:
|
|
||||||
printf("Error: %s", pMsg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("%s", pMsg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", pMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (console::get_crlf())
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
// File: crn_colorized_console.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_console.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class colorized_console
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void init();
|
|
||||||
static void deinit();
|
|
||||||
static void tick();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool console_output_func(eConsoleMessageType type, const char* pMsg, void* pData);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,472 +0,0 @@
|
||||||
// File: crn_command_line_params.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_command_line_params.h"
|
|
||||||
#include "crn_console.h"
|
|
||||||
#include "crn_cfile_stream.h"
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#define CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
#endif
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
argc, argv;
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
cmd_line.set(GetCommandLineA());
|
|
||||||
#else
|
|
||||||
cmd_line.clear();
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
dynamic_string tmp(argv[i]);
|
|
||||||
if ((tmp.front() != '"') && (tmp.front() != '-') && (tmp.front() != '@'))
|
|
||||||
tmp = "\"" + tmp + "\"";
|
|
||||||
if (cmd_line.get_len())
|
|
||||||
cmd_line += " ";
|
|
||||||
cmd_line += tmp;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
command_line_params::command_line_params()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_line_params::clear()
|
|
||||||
{
|
|
||||||
m_params.clear();
|
|
||||||
|
|
||||||
m_param_map.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::split_params(const char* p, dynamic_string_array& params)
|
|
||||||
{
|
|
||||||
bool within_param = false;
|
|
||||||
bool within_quote = false;
|
|
||||||
|
|
||||||
uint ofs = 0;
|
|
||||||
dynamic_string str;
|
|
||||||
|
|
||||||
while (p[ofs])
|
|
||||||
{
|
|
||||||
const char c = p[ofs];
|
|
||||||
|
|
||||||
if (within_param)
|
|
||||||
{
|
|
||||||
if (within_quote)
|
|
||||||
{
|
|
||||||
if (c == '"')
|
|
||||||
within_quote = false;
|
|
||||||
|
|
||||||
str.append_char(c);
|
|
||||||
}
|
|
||||||
else if ((c == ' ') || (c == '\t'))
|
|
||||||
{
|
|
||||||
if (!str.is_empty())
|
|
||||||
{
|
|
||||||
params.push_back(str);
|
|
||||||
str.clear();
|
|
||||||
}
|
|
||||||
within_param = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (c == '"')
|
|
||||||
within_quote = true;
|
|
||||||
|
|
||||||
str.append_char(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((c != ' ') && (c != '\t'))
|
|
||||||
{
|
|
||||||
within_param = true;
|
|
||||||
|
|
||||||
if (c == '"')
|
|
||||||
within_quote = true;
|
|
||||||
|
|
||||||
str.append_char(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
ofs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (within_quote)
|
|
||||||
{
|
|
||||||
console::error("Unmatched quote in command line \"%s\"", p);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!str.is_empty())
|
|
||||||
params.push_back(str);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::load_string_file(const char* pFilename, dynamic_string_array& strings)
|
|
||||||
{
|
|
||||||
cfile_stream in_stream;
|
|
||||||
if (!in_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable))
|
|
||||||
{
|
|
||||||
console::error("Unable to open file \"%s\" for reading!", pFilename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string ansi_str;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if (!in_stream.read_line(ansi_str))
|
|
||||||
break;
|
|
||||||
|
|
||||||
ansi_str.trim();
|
|
||||||
if (ansi_str.is_empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
strings.push_back(dynamic_string(ansi_str.get_ptr()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(n && pParam_desc);
|
|
||||||
|
|
||||||
m_params = params;
|
|
||||||
|
|
||||||
uint arg_index = 0;
|
|
||||||
while (arg_index < params.size())
|
|
||||||
{
|
|
||||||
const uint cur_arg_index = arg_index;
|
|
||||||
const dynamic_string& src_param = params[arg_index++];
|
|
||||||
|
|
||||||
if (src_param.is_empty())
|
|
||||||
continue;
|
|
||||||
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
|
|
||||||
if ((src_param[0] == '/') || (src_param[0] == '-'))
|
|
||||||
#else
|
|
||||||
if (src_param[0] == '-')
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (src_param.get_len() < 2)
|
|
||||||
{
|
|
||||||
console::error("Invalid command line parameter: \"%s\"", src_param.get_ptr());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string key_str(src_param);
|
|
||||||
|
|
||||||
key_str.right(1);
|
|
||||||
|
|
||||||
int modifier = 0;
|
|
||||||
char c = key_str[key_str.get_len() - 1];
|
|
||||||
if (c == '+')
|
|
||||||
modifier = 1;
|
|
||||||
else if (c == '-')
|
|
||||||
modifier = -1;
|
|
||||||
|
|
||||||
if (modifier)
|
|
||||||
key_str.left(key_str.get_len() - 1);
|
|
||||||
|
|
||||||
uint param_index;
|
|
||||||
for (param_index = 0; param_index < n; param_index++)
|
|
||||||
if (key_str == pParam_desc[param_index].m_pName)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (param_index == n)
|
|
||||||
{
|
|
||||||
console::error("Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const param_desc& desc = pParam_desc[param_index];
|
|
||||||
|
|
||||||
const uint cMaxValues = 16;
|
|
||||||
dynamic_string val_str[cMaxValues];
|
|
||||||
uint num_val_strs = 0;
|
|
||||||
if (desc.m_num_values)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(desc.m_num_values <= cMaxValues);
|
|
||||||
|
|
||||||
if ((arg_index + desc.m_num_values) > params.size())
|
|
||||||
{
|
|
||||||
console::error("Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint v = 0; v < desc.m_num_values; v++)
|
|
||||||
val_str[num_val_strs++] = params[arg_index++];
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string_array strings;
|
|
||||||
|
|
||||||
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == '@'))
|
|
||||||
{
|
|
||||||
dynamic_string filename(val_str[0]);
|
|
||||||
filename.right(1);
|
|
||||||
filename.unquote();
|
|
||||||
|
|
||||||
if (!load_string_file(filename.get_ptr(), strings))
|
|
||||||
{
|
|
||||||
console::error("Failed loading listing file \"%s\"!", filename.get_ptr());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (uint v = 0; v < num_val_strs; v++)
|
|
||||||
{
|
|
||||||
val_str[v].unquote();
|
|
||||||
strings.push_back(val_str[v]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
param_value pv;
|
|
||||||
pv.m_values.swap(strings);
|
|
||||||
pv.m_index = cur_arg_index;
|
|
||||||
pv.m_modifier = (int8)modifier;
|
|
||||||
m_param_map.insert(std::make_pair(key_str, pv));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
param_value pv;
|
|
||||||
pv.m_values.push_back(src_param);
|
|
||||||
pv.m_values.back().unquote();
|
|
||||||
pv.m_index = cur_arg_index;
|
|
||||||
m_param_map.insert(std::make_pair(g_empty_dynamic_string, pv));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(n && pParam_desc);
|
|
||||||
|
|
||||||
dynamic_string_array p;
|
|
||||||
if (!split_params(pCmd_line, p))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (p.empty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (skip_first_param)
|
|
||||||
p.erase(0U);
|
|
||||||
|
|
||||||
return parse(p, n, pParam_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::is_param(uint index) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(index < m_params.size());
|
|
||||||
if (index >= m_params.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const dynamic_string& w = m_params[index];
|
|
||||||
if (w.is_empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
|
|
||||||
return (w.get_len() >= 2) && ((w[0] == '-') || (w[0] == '/'));
|
|
||||||
#else
|
|
||||||
return (w.get_len() >= 2) && (w[0] == '-');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint command_line_params::find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(ppKeys);
|
|
||||||
|
|
||||||
if (pUnmatched_indices)
|
|
||||||
{
|
|
||||||
pUnmatched_indices->resize(m_params.size());
|
|
||||||
for (uint i = 0; i < m_params.size(); i++)
|
|
||||||
(*pUnmatched_indices)[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint n = 0;
|
|
||||||
for (uint i = 0; i < num_keys; i++)
|
|
||||||
{
|
|
||||||
const char* pKey = ppKeys[i];
|
|
||||||
|
|
||||||
param_map_const_iterator begin, end;
|
|
||||||
find(pKey, begin, end);
|
|
||||||
|
|
||||||
while (begin != end)
|
|
||||||
{
|
|
||||||
if (pIterators)
|
|
||||||
pIterators->push_back(begin);
|
|
||||||
|
|
||||||
if (pUnmatched_indices)
|
|
||||||
{
|
|
||||||
int k = pUnmatched_indices->find(begin->second.m_index);
|
|
||||||
if (k >= 0)
|
|
||||||
pUnmatched_indices->erase_unordered(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
n++;
|
|
||||||
begin++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_line_params::find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const
|
|
||||||
{
|
|
||||||
dynamic_string key(pKey);
|
|
||||||
begin = m_param_map.lower_bound(key);
|
|
||||||
end = m_param_map.upper_bound(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint command_line_params::get_count(const char* pKey) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator begin, end;
|
|
||||||
find(pKey, begin, end);
|
|
||||||
|
|
||||||
uint n = 0;
|
|
||||||
|
|
||||||
while (begin != end)
|
|
||||||
{
|
|
||||||
n++;
|
|
||||||
begin++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
command_line_params::param_map_const_iterator command_line_params::get_param(const char* pKey, uint index) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator begin, end;
|
|
||||||
find(pKey, begin, end);
|
|
||||||
|
|
||||||
if (begin == end)
|
|
||||||
return m_param_map.end();
|
|
||||||
|
|
||||||
uint n = 0;
|
|
||||||
|
|
||||||
while ((begin != end) && (n != index))
|
|
||||||
{
|
|
||||||
n++;
|
|
||||||
begin++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (begin == end)
|
|
||||||
return m_param_map.end();
|
|
||||||
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::has_value(const char* pKey, uint index) const
|
|
||||||
{
|
|
||||||
return get_num_values(pKey, index) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint command_line_params::get_num_values(const char* pKey, uint index) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator it = get_param(pKey, index);
|
|
||||||
|
|
||||||
if (it == end())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return it->second.m_values.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::get_value_as_bool(const char* pKey, uint index, bool def) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator it = get_param(pKey, index);
|
|
||||||
if (it == end())
|
|
||||||
return def;
|
|
||||||
|
|
||||||
if (it->second.m_modifier)
|
|
||||||
return it->second.m_modifier > 0;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int command_line_params::get_value_as_int(const char* pKey, uint index, int def, int l, int h, uint value_index) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator it = get_param(pKey, index);
|
|
||||||
if ((it == end()) || (value_index >= it->second.m_values.size()))
|
|
||||||
return def;
|
|
||||||
|
|
||||||
int val;
|
|
||||||
const char* p = it->second.m_values[value_index].get_ptr();
|
|
||||||
if (!string_to_int(p, val))
|
|
||||||
{
|
|
||||||
crnlib::console::warning("Invalid value specified for parameter \"%s\", using default value of %i", pKey, def);
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val < l)
|
|
||||||
{
|
|
||||||
crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, l);
|
|
||||||
val = l;
|
|
||||||
}
|
|
||||||
else if (val > h)
|
|
||||||
{
|
|
||||||
crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, h);
|
|
||||||
val = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
float command_line_params::get_value_as_float(const char* pKey, uint index, float def, float l, float h, uint value_index) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator it = get_param(pKey, index);
|
|
||||||
if ((it == end()) || (value_index >= it->second.m_values.size()))
|
|
||||||
return def;
|
|
||||||
|
|
||||||
float val;
|
|
||||||
const char* p = it->second.m_values[value_index].get_ptr();
|
|
||||||
if (!string_to_float(p, val))
|
|
||||||
{
|
|
||||||
crnlib::console::warning("Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val < l)
|
|
||||||
{
|
|
||||||
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l);
|
|
||||||
val = l;
|
|
||||||
}
|
|
||||||
else if (val > h)
|
|
||||||
{
|
|
||||||
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h);
|
|
||||||
val = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool command_line_params::get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator it = get_param(pKey, index);
|
|
||||||
if ((it == end()) || (value_index >= it->second.m_values.size()))
|
|
||||||
{
|
|
||||||
value.empty();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = it->second.m_values[value_index];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dynamic_string& command_line_params::get_value_as_string_or_empty(const char* pKey, uint index, uint value_index) const
|
|
||||||
{
|
|
||||||
param_map_const_iterator it = get_param(pKey, index);
|
|
||||||
if ((it == end()) || (value_index >= it->second.m_values.size()))
|
|
||||||
return g_empty_dynamic_string;
|
|
||||||
|
|
||||||
return it->second.m_values[value_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
// File: crn_command_line_params.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_value.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
// Returns the command line passed to the app as a string.
|
|
||||||
// On systems where this isn't trivial, this function combines together the separate arguments, quoting and adding spaces as needed.
|
|
||||||
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char *argv[]);
|
|
||||||
|
|
||||||
class command_line_params
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct param_value
|
|
||||||
{
|
|
||||||
inline param_value() : m_index(0), m_modifier(0) { }
|
|
||||||
|
|
||||||
dynamic_string_array m_values;
|
|
||||||
uint m_index;
|
|
||||||
int8 m_modifier;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::multimap<dynamic_string, param_value> param_map;
|
|
||||||
typedef param_map::const_iterator param_map_const_iterator;
|
|
||||||
typedef param_map::iterator param_map_iterator;
|
|
||||||
|
|
||||||
command_line_params();
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
static bool split_params(const char* p, dynamic_string_array& params);
|
|
||||||
|
|
||||||
struct param_desc
|
|
||||||
{
|
|
||||||
const char* m_pName;
|
|
||||||
uint m_num_values;
|
|
||||||
bool m_support_listing_file;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc);
|
|
||||||
bool parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true);
|
|
||||||
|
|
||||||
const dynamic_string_array& get_array() const { return m_params; }
|
|
||||||
|
|
||||||
bool is_param(uint index) const;
|
|
||||||
|
|
||||||
const param_map& get_map() const { return m_param_map; }
|
|
||||||
|
|
||||||
uint get_num_params() const { return static_cast<uint>(m_param_map.size()); }
|
|
||||||
|
|
||||||
param_map_const_iterator begin() const { return m_param_map.begin(); }
|
|
||||||
param_map_const_iterator end() const { return m_param_map.end(); }
|
|
||||||
|
|
||||||
uint find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const;
|
|
||||||
|
|
||||||
void find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const;
|
|
||||||
|
|
||||||
uint get_count(const char* pKey) const;
|
|
||||||
|
|
||||||
// Returns end() if param cannot be found, or index is out of range.
|
|
||||||
param_map_const_iterator get_param(const char* pKey, uint index) const;
|
|
||||||
|
|
||||||
bool has_key(const char* pKey) const { return get_param(pKey, 0) != end(); }
|
|
||||||
|
|
||||||
bool has_value(const char* pKey, uint index) const;
|
|
||||||
uint get_num_values(const char* pKey, uint index) const;
|
|
||||||
|
|
||||||
bool get_value_as_bool(const char* pKey, uint index = 0, bool def = false) const;
|
|
||||||
|
|
||||||
int get_value_as_int(const char* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
|
|
||||||
float get_value_as_float(const char* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const;
|
|
||||||
|
|
||||||
bool get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index = 0) const;
|
|
||||||
const dynamic_string& get_value_as_string_or_empty(const char* pKey, uint index = 0, uint value_index = 0) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
dynamic_string_array m_params;
|
|
||||||
|
|
||||||
param_map m_param_map;
|
|
||||||
|
|
||||||
static bool load_string_file(const char* pFilename, dynamic_string_array& strings);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,181 +0,0 @@
|
||||||
// File: crn_comp.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define CRND_HEADER_FILE_ONLY
|
|
||||||
#include "../inc/crn_decomp.h"
|
|
||||||
#undef CRND_HEADER_FILE_ONLY
|
|
||||||
|
|
||||||
#include "../inc/crnlib.h"
|
|
||||||
#include "crn_symbol_codec.h"
|
|
||||||
#include "crn_dxt_hc.h"
|
|
||||||
#include "crn_image.h"
|
|
||||||
#include "crn_image_utils.h"
|
|
||||||
#include "crn_texture_comp.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class crn_comp : public itexture_comp
|
|
||||||
{
|
|
||||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp);
|
|
||||||
|
|
||||||
public:
|
|
||||||
crn_comp();
|
|
||||||
virtual ~crn_comp();
|
|
||||||
|
|
||||||
virtual const char *get_ext() const { return "CRN"; }
|
|
||||||
|
|
||||||
virtual bool compress_init(const crn_comp_params& params);
|
|
||||||
virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate);
|
|
||||||
virtual void compress_deinit();
|
|
||||||
|
|
||||||
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
|
|
||||||
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
|
|
||||||
|
|
||||||
uint get_comp_data_size() const { return m_comp_data.size(); }
|
|
||||||
const uint8* get_comp_data_ptr() const { return m_comp_data.size() ? &m_comp_data[0] : NULL; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
task_pool m_task_pool;
|
|
||||||
const crn_comp_params* m_pParams;
|
|
||||||
|
|
||||||
image_u8 m_images[cCRNMaxFaces][cCRNMaxLevels];
|
|
||||||
|
|
||||||
struct level_tag
|
|
||||||
{
|
|
||||||
uint m_width, m_height;
|
|
||||||
uint m_chunk_width, m_chunk_height;
|
|
||||||
uint m_group_index;
|
|
||||||
uint m_num_chunks;
|
|
||||||
uint m_first_chunk;
|
|
||||||
uint m_group_first_chunk;
|
|
||||||
} m_levels[cCRNMaxLevels];
|
|
||||||
|
|
||||||
struct mip_group
|
|
||||||
{
|
|
||||||
mip_group() : m_first_chunk(0), m_num_chunks(0) { }
|
|
||||||
|
|
||||||
uint m_first_chunk;
|
|
||||||
uint m_num_chunks;
|
|
||||||
};
|
|
||||||
crnlib::vector<mip_group> m_mip_groups;
|
|
||||||
|
|
||||||
enum comp
|
|
||||||
{
|
|
||||||
cColor,
|
|
||||||
cAlpha0,
|
|
||||||
cAlpha1,
|
|
||||||
cNumComps
|
|
||||||
};
|
|
||||||
|
|
||||||
bool m_has_comp[cNumComps];
|
|
||||||
|
|
||||||
struct chunk_detail
|
|
||||||
{
|
|
||||||
chunk_detail() { utils::zero_object(*this); }
|
|
||||||
|
|
||||||
uint m_first_endpoint_index;
|
|
||||||
uint m_first_selector_index;
|
|
||||||
};
|
|
||||||
typedef crnlib::vector<chunk_detail> chunk_detail_vec;
|
|
||||||
chunk_detail_vec m_chunk_details;
|
|
||||||
|
|
||||||
crnlib::vector<uint> m_endpoint_indices[cNumComps];
|
|
||||||
crnlib::vector<uint> m_selector_indices[cNumComps];
|
|
||||||
|
|
||||||
uint m_total_chunks;
|
|
||||||
dxt_hc::pixel_chunk_vec m_chunks;
|
|
||||||
|
|
||||||
crnd::crn_header m_crn_header;
|
|
||||||
crnlib::vector<uint8> m_comp_data;
|
|
||||||
|
|
||||||
dxt_hc m_hvq;
|
|
||||||
|
|
||||||
symbol_histogram m_chunk_encoding_hist;
|
|
||||||
static_huffman_data_model m_chunk_encoding_dm;
|
|
||||||
|
|
||||||
symbol_histogram m_endpoint_index_hist[2];
|
|
||||||
static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha
|
|
||||||
|
|
||||||
symbol_histogram m_selector_index_hist[2];
|
|
||||||
static_huffman_data_model m_selector_index_dm[2]; // color, alpha
|
|
||||||
|
|
||||||
crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels];
|
|
||||||
crnlib::vector<uint8> m_packed_data_models;
|
|
||||||
crnlib::vector<uint8> m_packed_color_endpoints;
|
|
||||||
crnlib::vector<uint8> m_packed_color_selectors;
|
|
||||||
crnlib::vector<uint8> m_packed_alpha_endpoints;
|
|
||||||
crnlib::vector<uint8> m_packed_alpha_selectors;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
void append_chunks(const image_u8& img, uint num_chunks_x, uint num_chunks_y, dxt_hc::pixel_chunk_vec& chunks, float weight);
|
|
||||||
|
|
||||||
static float color_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
|
|
||||||
static float alpha_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
|
|
||||||
void sort_color_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
|
|
||||||
void sort_alpha_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
|
|
||||||
|
|
||||||
bool pack_color_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
|
|
||||||
bool pack_alpha_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
|
|
||||||
|
|
||||||
static float color_selector_similarity_func(uint index_a, uint index_b, void* pContext);
|
|
||||||
static float alpha_selector_similarity_func(uint index_a, uint index_b, void* pContext);
|
|
||||||
void sort_selector_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<dxt_hc::selectors>& selectors, const uint8* pTo_linear);
|
|
||||||
|
|
||||||
bool pack_selectors(
|
|
||||||
crnlib::vector<uint8>& packed_data,
|
|
||||||
const crnlib::vector<uint>& selector_indices,
|
|
||||||
const crnlib::vector<dxt_hc::selectors>& selectors,
|
|
||||||
const crnlib::vector<uint>& remapping,
|
|
||||||
uint max_selector_value,
|
|
||||||
const uint8* pTo_linear,
|
|
||||||
uint trial_index);
|
|
||||||
|
|
||||||
bool alias_images();
|
|
||||||
void create_chunks();
|
|
||||||
bool quantize_chunks();
|
|
||||||
void create_chunk_indices();
|
|
||||||
|
|
||||||
bool pack_chunks(
|
|
||||||
uint first_chunk, uint num_chunks,
|
|
||||||
bool clear_histograms,
|
|
||||||
symbol_codec* pCodec,
|
|
||||||
const crnlib::vector<uint>* pColor_endpoint_remap,
|
|
||||||
const crnlib::vector<uint>* pColor_selector_remap,
|
|
||||||
const crnlib::vector<uint>* pAlpha_endpoint_remap,
|
|
||||||
const crnlib::vector<uint>* pAlpha_selector_remap);
|
|
||||||
|
|
||||||
bool pack_chunks_simulation(
|
|
||||||
uint first_chunk, uint num_chunks,
|
|
||||||
uint& total_bits,
|
|
||||||
const crnlib::vector<uint>* pColor_endpoint_remap,
|
|
||||||
const crnlib::vector<uint>* pColor_selector_remap,
|
|
||||||
const crnlib::vector<uint>* pAlpha_endpoint_remap,
|
|
||||||
const crnlib::vector<uint>* pAlpha_selector_remap);
|
|
||||||
|
|
||||||
void optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping);
|
|
||||||
|
|
||||||
void optimize_color_selector_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool optimize_color_selector_codebook(crnlib::vector<uint>& remapping);
|
|
||||||
|
|
||||||
void optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping);
|
|
||||||
|
|
||||||
void optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping);
|
|
||||||
|
|
||||||
bool create_comp_data();
|
|
||||||
|
|
||||||
bool pack_data_models();
|
|
||||||
|
|
||||||
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
|
|
||||||
|
|
||||||
bool compress_internal();
|
|
||||||
|
|
||||||
static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size);
|
|
||||||
static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,222 +0,0 @@
|
||||||
// File: crn_console.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_console.h"
|
|
||||||
#include "crn_data_stream.h"
|
|
||||||
#include "crn_threading.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
eConsoleMessageType console::m_default_category = cInfoConsoleMessage;
|
|
||||||
crnlib::vector<console::console_func> console::m_output_funcs;
|
|
||||||
bool console::m_crlf = true;
|
|
||||||
bool console::m_prefixes = true;
|
|
||||||
bool console::m_output_disabled;
|
|
||||||
data_stream* console::m_pLog_stream;
|
|
||||||
mutex* console::m_pMutex;
|
|
||||||
uint console::m_num_messages[cCMTTotal];
|
|
||||||
bool console::m_at_beginning_of_line = true;
|
|
||||||
|
|
||||||
const uint cConsoleBufSize = 4096;
|
|
||||||
|
|
||||||
void console::init()
|
|
||||||
{
|
|
||||||
if (!m_pMutex)
|
|
||||||
{
|
|
||||||
m_pMutex = crnlib_new<mutex>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::deinit()
|
|
||||||
{
|
|
||||||
if (m_pMutex)
|
|
||||||
{
|
|
||||||
crnlib_delete(m_pMutex);
|
|
||||||
m_pMutex = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::disable_crlf()
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
m_crlf = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::enable_crlf()
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
m_crlf = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::vprintf(eConsoleMessageType type, const char* p, va_list args)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
scoped_mutex lock(*m_pMutex);
|
|
||||||
|
|
||||||
m_num_messages[type]++;
|
|
||||||
|
|
||||||
char buf[cConsoleBufSize];
|
|
||||||
vsprintf_s(buf, cConsoleBufSize, p, args);
|
|
||||||
|
|
||||||
bool handled = false;
|
|
||||||
|
|
||||||
if (m_output_funcs.size())
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_output_funcs.size(); i++)
|
|
||||||
if (m_output_funcs[i].m_func(type, buf, m_output_funcs[i].m_pData))
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* pPrefix = NULL;
|
|
||||||
if ((m_prefixes) && (m_at_beginning_of_line))
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case cDebugConsoleMessage: pPrefix = "Debug: "; break;
|
|
||||||
case cWarningConsoleMessage: pPrefix = "Warning: "; break;
|
|
||||||
case cErrorConsoleMessage: pPrefix = "Error: "; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!m_output_disabled) && (!handled))
|
|
||||||
{
|
|
||||||
if (pPrefix)
|
|
||||||
::printf("%s", pPrefix);
|
|
||||||
::printf(m_crlf ? "%s\n" : "%s", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint n = strlen(buf);
|
|
||||||
m_at_beginning_of_line = (m_crlf) || ((n) && (buf[n - 1] == '\n'));
|
|
||||||
|
|
||||||
if ((type != cProgressConsoleMessage) && (m_pLog_stream))
|
|
||||||
{
|
|
||||||
// Yes this is bad.
|
|
||||||
dynamic_string tmp_buf(buf);
|
|
||||||
|
|
||||||
tmp_buf.translate_lf_to_crlf();
|
|
||||||
|
|
||||||
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr());
|
|
||||||
m_pLog_stream->flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::printf(eConsoleMessageType type, const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(type, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::printf(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(m_default_category, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::set_default_category(eConsoleMessageType category)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
m_default_category = category;
|
|
||||||
}
|
|
||||||
|
|
||||||
eConsoleMessageType console::get_default_category()
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
return m_default_category;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::add_console_output_func(console_output_func pFunc, void* pData)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
scoped_mutex lock(*m_pMutex);
|
|
||||||
|
|
||||||
m_output_funcs.push_back(console_func(pFunc, pData));
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::remove_console_output_func(console_output_func pFunc)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
scoped_mutex lock(*m_pMutex);
|
|
||||||
|
|
||||||
for (int i = m_output_funcs.size() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (m_output_funcs[i].m_func == pFunc)
|
|
||||||
{
|
|
||||||
m_output_funcs.erase(m_output_funcs.begin() + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_output_funcs.size())
|
|
||||||
{
|
|
||||||
m_output_funcs.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::progress(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cProgressConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::info(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cInfoConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::message(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cMessageConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::cons(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cConsoleConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::debug(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cDebugConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::warning(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cWarningConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::error(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
vprintf(cErrorConsoleMessage, p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,128 +0,0 @@
|
||||||
// File: crn_console.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_dynamic_string.h"
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <tchar.h>
|
|
||||||
#include <conio.h>
|
|
||||||
#endif
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class dynamic_string;
|
|
||||||
class data_stream;
|
|
||||||
class mutex;
|
|
||||||
|
|
||||||
enum eConsoleMessageType
|
|
||||||
{
|
|
||||||
cDebugConsoleMessage, // debugging messages
|
|
||||||
cProgressConsoleMessage, // progress messages
|
|
||||||
cInfoConsoleMessage, // ordinary messages
|
|
||||||
cConsoleConsoleMessage, // user console output
|
|
||||||
cMessageConsoleMessage, // high importance messages
|
|
||||||
cWarningConsoleMessage, // warnings
|
|
||||||
cErrorConsoleMessage, // errors
|
|
||||||
|
|
||||||
cCMTTotal
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef bool (*console_output_func)(eConsoleMessageType type, const char* pMsg, void* pData);
|
|
||||||
|
|
||||||
class console
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void init();
|
|
||||||
static void deinit();
|
|
||||||
|
|
||||||
static bool is_initialized() { return m_pMutex != NULL; }
|
|
||||||
|
|
||||||
static void set_default_category(eConsoleMessageType category);
|
|
||||||
static eConsoleMessageType get_default_category();
|
|
||||||
|
|
||||||
static void add_console_output_func(console_output_func pFunc, void* pData);
|
|
||||||
static void remove_console_output_func(console_output_func pFunc);
|
|
||||||
|
|
||||||
static void printf(const char* p, ...);
|
|
||||||
|
|
||||||
static void vprintf(eConsoleMessageType type, const char* p, va_list args);
|
|
||||||
static void printf(eConsoleMessageType type, const char* p, ...);
|
|
||||||
|
|
||||||
static void cons(const char* p, ...);
|
|
||||||
static void debug(const char* p, ...);
|
|
||||||
static void progress(const char* p, ...);
|
|
||||||
static void info(const char* p, ...);
|
|
||||||
static void message(const char* p, ...);
|
|
||||||
static void warning(const char* p, ...);
|
|
||||||
static void error(const char* p, ...);
|
|
||||||
|
|
||||||
// FIXME: All console state is currently global!
|
|
||||||
static void disable_prefixes();
|
|
||||||
static void enable_prefixes();
|
|
||||||
static bool get_prefixes() { return m_prefixes; }
|
|
||||||
static bool get_at_beginning_of_line() { return m_at_beginning_of_line; }
|
|
||||||
|
|
||||||
static void disable_crlf();
|
|
||||||
static void enable_crlf();
|
|
||||||
static bool get_crlf() { return m_crlf; }
|
|
||||||
|
|
||||||
static void disable_output() { m_output_disabled = true; }
|
|
||||||
static void enable_output() { m_output_disabled = false; }
|
|
||||||
static bool get_output_disabled() { return m_output_disabled; }
|
|
||||||
|
|
||||||
static void set_log_stream(data_stream* pStream) { m_pLog_stream = pStream; }
|
|
||||||
static data_stream* get_log_stream() { return m_pLog_stream; }
|
|
||||||
|
|
||||||
static uint get_num_messages(eConsoleMessageType type) { return m_num_messages[type]; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static eConsoleMessageType m_default_category;
|
|
||||||
|
|
||||||
struct console_func
|
|
||||||
{
|
|
||||||
console_func(console_output_func func = NULL, void* pData = NULL) : m_func(func), m_pData(pData) { }
|
|
||||||
|
|
||||||
console_output_func m_func;
|
|
||||||
void* m_pData;
|
|
||||||
};
|
|
||||||
static crnlib::vector<console_func> m_output_funcs;
|
|
||||||
|
|
||||||
static bool m_crlf, m_prefixes, m_output_disabled;
|
|
||||||
|
|
||||||
static data_stream* m_pLog_stream;
|
|
||||||
|
|
||||||
static mutex* m_pMutex;
|
|
||||||
|
|
||||||
static uint m_num_messages[cCMTTotal];
|
|
||||||
|
|
||||||
static bool m_at_beginning_of_line;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
inline int crn_getch()
|
|
||||||
{
|
|
||||||
return _getch();
|
|
||||||
}
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#include <termios.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
inline int crn_getch()
|
|
||||||
{
|
|
||||||
struct termios oldt, newt;
|
|
||||||
int ch;
|
|
||||||
tcgetattr(STDIN_FILENO, &oldt);
|
|
||||||
newt = oldt;
|
|
||||||
newt.c_lflag &= ~(ICANON | ECHO);
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
|
||||||
ch = getchar();
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
inline int crn_getch()
|
|
||||||
{
|
|
||||||
printf("crn_getch: Unimplemented");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
// File: crn_core.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
const char *g_copyright_str = "Copyright (c) 2010-2012 Rich Geldreich and Tenacious Software LLC";
|
|
||||||
const char *g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,178 +0,0 @@
|
||||||
// File: crn_core.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(WIN32) && defined(_MSC_VER)
|
|
||||||
#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
|
|
||||||
#pragma warning (disable: 4127) // conditional expression is constant
|
|
||||||
#pragma warning (disable: 4793) // function compiled as native
|
|
||||||
#pragma warning (disable: 4324) // structure was padded due to __declspec(align())
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(CRNLIB_ANSI_CPLUSPLUS)
|
|
||||||
// MSVC or MinGW, x86 or x64, Win32 API's for threading and Win32 Interlocked API's or GCC built-ins for atomic ops.
|
|
||||||
#ifdef NDEBUG
|
|
||||||
// Ensure checked iterators are disabled. Note: Be sure anything else that links against this lib also #define's this stuff, or remove this crap!
|
|
||||||
#define _SECURE_SCL 0
|
|
||||||
#define _HAS_ITERATOR_DEBUGGING 0
|
|
||||||
#endif
|
|
||||||
#ifndef _DLL
|
|
||||||
// If we're using the DLL form of the run-time libs, we're also going to be enabling exceptions because we'll be building CLR apps.
|
|
||||||
// Otherwise, we disable exceptions for a small speed boost.
|
|
||||||
#define _HAS_EXCEPTIONS 0
|
|
||||||
#endif
|
|
||||||
#define NOMINMAX
|
|
||||||
|
|
||||||
#define CRNLIB_USE_WIN32_API 1
|
|
||||||
|
|
||||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
|
||||||
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
|
|
||||||
#else
|
|
||||||
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_PLATFORM_PC 1
|
|
||||||
|
|
||||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
|
||||||
#define CRNLIB_PLATFORM_PC_X64 1
|
|
||||||
#define CRNLIB_64BIT_POINTERS 1
|
|
||||||
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
|
|
||||||
#define CRNLIB_LITTLE_ENDIAN_CPU 1
|
|
||||||
#else
|
|
||||||
#define CRNLIB_PLATFORM_PC_X86 1
|
|
||||||
#define CRNLIB_64BIT_POINTERS 0
|
|
||||||
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
|
|
||||||
#define CRNLIB_LITTLE_ENDIAN_CPU 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
|
|
||||||
#define CRNLIB_RESTRICT __restrict
|
|
||||||
#define CRNLIB_FORCE_INLINE __forceinline
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
|
|
||||||
#define CRNLIB_USE_MSVC_INTRINSICS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
|
|
||||||
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
|
|
||||||
|
|
||||||
#define CRNLIB_STDCALL __stdcall
|
|
||||||
#define CRNLIB_MEMORY_IMPORT_BARRIER
|
|
||||||
#define CRNLIB_MEMORY_EXPORT_BARRIER
|
|
||||||
#elif defined(__GNUC__) && !defined(CRNLIB_ANSI_CPLUSPLUS)
|
|
||||||
// GCC x86 or x64, pthreads for threading and GCC built-ins for atomic ops.
|
|
||||||
#define CRNLIB_PLATFORM_PC 1
|
|
||||||
|
|
||||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
|
||||||
#define CRNLIB_PLATFORM_PC_X64 1
|
|
||||||
#define CRNLIB_64BIT_POINTERS 1
|
|
||||||
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
|
|
||||||
#else
|
|
||||||
#define CRNLIB_PLATFORM_PC_X86 1
|
|
||||||
#define CRNLIB_64BIT_POINTERS 0
|
|
||||||
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
|
|
||||||
|
|
||||||
#define CRNLIB_LITTLE_ENDIAN_CPU 1
|
|
||||||
|
|
||||||
#define CRNLIB_USE_PTHREADS_API 1
|
|
||||||
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
|
|
||||||
|
|
||||||
#define CRNLIB_RESTRICT
|
|
||||||
|
|
||||||
#define CRNLIB_FORCE_INLINE inline __attribute__((__always_inline__,__gnu_inline__))
|
|
||||||
|
|
||||||
#define CRNLIB_INT64_FORMAT_SPECIFIER "%lli"
|
|
||||||
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%llu"
|
|
||||||
|
|
||||||
#define CRNLIB_STDCALL
|
|
||||||
#define CRNLIB_MEMORY_IMPORT_BARRIER
|
|
||||||
#define CRNLIB_MEMORY_EXPORT_BARRIER
|
|
||||||
#else
|
|
||||||
// Vanilla ANSI-C/C++
|
|
||||||
// No threading support, unaligned loads are NOT okay.
|
|
||||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
|
||||||
#define CRNLIB_64BIT_POINTERS 1
|
|
||||||
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
|
|
||||||
#else
|
|
||||||
#define CRNLIB_64BIT_POINTERS 0
|
|
||||||
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_USE_UNALIGNED_INT_LOADS 0
|
|
||||||
|
|
||||||
#if __BIG_ENDIAN__
|
|
||||||
#define CRNLIB_BIG_ENDIAN_CPU 1
|
|
||||||
#else
|
|
||||||
#define CRNLIB_LITTLE_ENDIAN_CPU 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 0
|
|
||||||
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 0
|
|
||||||
|
|
||||||
#define CRNLIB_RESTRICT
|
|
||||||
#define CRNLIB_FORCE_INLINE inline
|
|
||||||
|
|
||||||
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
|
|
||||||
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
|
|
||||||
|
|
||||||
#define CRNLIB_STDCALL
|
|
||||||
#define CRNLIB_MEMORY_IMPORT_BARRIER
|
|
||||||
#define CRNLIB_MEMORY_EXPORT_BARRIER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_SLOW_STRING_LEN_CHECKS 1
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <locale>
|
|
||||||
#include <memory.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#ifdef min
|
|
||||||
#undef min
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef max
|
|
||||||
#undef max
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRNLIB_FALSE (0)
|
|
||||||
#define CRNLIB_TRUE (1)
|
|
||||||
#define CRNLIB_MAX_PATH (260)
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define CRNLIB_BUILD_DEBUG
|
|
||||||
#else
|
|
||||||
#define CRNLIB_BUILD_RELEASE
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#error DEBUG cannot be defined in CRNLIB_BUILD_RELEASE
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "crn_types.h"
|
|
||||||
#include "crn_assert.h"
|
|
||||||
#include "crn_platform.h"
|
|
||||||
#include "crn_helpers.h"
|
|
||||||
#include "crn_traits.h"
|
|
||||||
#include "crn_mem.h"
|
|
||||||
#include "crn_math.h"
|
|
||||||
#include "crn_utils.h"
|
|
||||||
#include "crn_hash.h"
|
|
||||||
#include "crn_vector.h"
|
|
||||||
#include "crn_timer.h"
|
|
||||||
#include "crn_dynamic_string.h"
|
|
|
@ -1,128 +0,0 @@
|
||||||
// File: crn_data_stream.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_data_stream.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
data_stream::data_stream() :
|
|
||||||
m_attribs(0),
|
|
||||||
m_opened(false), m_error(false), m_got_cr(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
data_stream::data_stream(const char* pName, uint attribs) :
|
|
||||||
m_name(pName),
|
|
||||||
m_attribs(static_cast<uint16>(attribs)),
|
|
||||||
m_opened(false), m_error(false), m_got_cr(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64 data_stream::skip(uint64 len)
|
|
||||||
{
|
|
||||||
uint64 total_bytes_read = 0;
|
|
||||||
|
|
||||||
const uint cBufSize = 1024;
|
|
||||||
uint8 buf[cBufSize];
|
|
||||||
|
|
||||||
while (len)
|
|
||||||
{
|
|
||||||
const uint64 bytes_to_read = math::minimum<uint64>(sizeof(buf), len);
|
|
||||||
const uint64 bytes_read = read(buf, static_cast<uint>(bytes_to_read));
|
|
||||||
total_bytes_read += bytes_read;
|
|
||||||
|
|
||||||
if (bytes_read != bytes_to_read)
|
|
||||||
break;
|
|
||||||
|
|
||||||
len -= bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
return total_bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool data_stream::read_line(dynamic_string& str)
|
|
||||||
{
|
|
||||||
str.empty();
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
const int c = read_byte();
|
|
||||||
|
|
||||||
const bool prev_got_cr = m_got_cr;
|
|
||||||
m_got_cr = false;
|
|
||||||
|
|
||||||
if (c < 0)
|
|
||||||
{
|
|
||||||
if (!str.is_empty())
|
|
||||||
break;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if ((26 == c) || (!c))
|
|
||||||
continue;
|
|
||||||
else if (13 == c)
|
|
||||||
{
|
|
||||||
m_got_cr = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (10 == c)
|
|
||||||
{
|
|
||||||
if (prev_got_cr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
str.append_char(static_cast<char>(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool data_stream::printf(const char* p, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, p);
|
|
||||||
dynamic_string buf;
|
|
||||||
buf.format_args(p, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool data_stream::write_line(const dynamic_string& str)
|
|
||||||
{
|
|
||||||
if (!str.is_empty())
|
|
||||||
return write(str.get_ptr(), str.get_len()) == str.get_len();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool data_stream::read_array(vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
if (buf.size() < get_remaining())
|
|
||||||
{
|
|
||||||
if (get_remaining() > 1024U*1024U*1024U)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
buf.resize((uint)get_remaining());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_remaining())
|
|
||||||
{
|
|
||||||
buf.resize(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return read(&buf[0], buf.size()) == buf.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool data_stream::write_array(const vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
if (!buf.empty())
|
|
||||||
return write(&buf[0], buf.size()) == buf.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,89 +0,0 @@
|
||||||
// File: crn_data_stream.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
enum data_stream_attribs
|
|
||||||
{
|
|
||||||
cDataStreamReadable = 1,
|
|
||||||
cDataStreamWritable = 2,
|
|
||||||
cDataStreamSeekable = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX;
|
|
||||||
const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX;
|
|
||||||
|
|
||||||
class data_stream
|
|
||||||
{
|
|
||||||
data_stream(const data_stream&);
|
|
||||||
data_stream& operator= (const data_stream&);
|
|
||||||
|
|
||||||
public:
|
|
||||||
data_stream();
|
|
||||||
data_stream(const char* pName, uint attribs);
|
|
||||||
|
|
||||||
virtual ~data_stream() { }
|
|
||||||
|
|
||||||
virtual data_stream *get_parent() { return NULL; }
|
|
||||||
|
|
||||||
virtual bool close() { m_opened = false; m_error = false; m_got_cr = false; return true; }
|
|
||||||
|
|
||||||
typedef uint16 attribs_t;
|
|
||||||
inline attribs_t get_attribs() const { return m_attribs; }
|
|
||||||
|
|
||||||
inline bool is_opened() const { return m_opened; }
|
|
||||||
|
|
||||||
inline bool is_readable() const { return utils::is_bit_set(m_attribs, cDataStreamReadable); }
|
|
||||||
inline bool is_writable() const { return utils::is_bit_set(m_attribs, cDataStreamWritable); }
|
|
||||||
inline bool is_seekable() const { return utils::is_bit_set(m_attribs, cDataStreamSeekable); }
|
|
||||||
|
|
||||||
inline bool get_error() const { return m_error; }
|
|
||||||
|
|
||||||
inline const dynamic_string& get_name() const { return m_name; }
|
|
||||||
inline void set_name(const char* pName) { m_name.set(pName); }
|
|
||||||
|
|
||||||
virtual uint read(void* pBuf, uint len) = 0;
|
|
||||||
virtual uint64 skip(uint64 len);
|
|
||||||
|
|
||||||
virtual uint write(const void* pBuf, uint len) = 0;
|
|
||||||
virtual bool flush() = 0;
|
|
||||||
|
|
||||||
virtual bool is_size_known() const { return true; }
|
|
||||||
|
|
||||||
// Returns DATA_STREAM_SIZE_UNKNOWN if size hasn't been determined yet, or DATA_STREAM_SIZE_INFINITE for infinite streams.
|
|
||||||
virtual uint64 get_size() = 0;
|
|
||||||
virtual uint64 get_remaining() = 0;
|
|
||||||
|
|
||||||
virtual uint64 get_ofs() = 0;
|
|
||||||
virtual bool seek(int64 ofs, bool relative) = 0;
|
|
||||||
|
|
||||||
virtual const void* get_ptr() const { return NULL; }
|
|
||||||
|
|
||||||
inline int read_byte() { uint8 c; if (read(&c, 1) != 1) return -1; return c; }
|
|
||||||
inline bool write_byte(uint8 c) { return write(&c, 1) == 1; }
|
|
||||||
|
|
||||||
bool read_line(dynamic_string& str);
|
|
||||||
bool printf(const char* p, ...);
|
|
||||||
bool write_line(const dynamic_string& str);
|
|
||||||
bool write_bom() { uint16 bom = 0xFEFF; return write(&bom, sizeof(bom)) == sizeof(bom); }
|
|
||||||
|
|
||||||
bool read_array(vector<uint8>& buf);
|
|
||||||
bool write_array(const vector<uint8>& buf);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
dynamic_string m_name;
|
|
||||||
|
|
||||||
attribs_t m_attribs;
|
|
||||||
bool m_opened : 1;
|
|
||||||
bool m_error : 1;
|
|
||||||
bool m_got_cr : 1;
|
|
||||||
|
|
||||||
inline void set_error() { m_error = true; }
|
|
||||||
inline void clear_error() { m_error = false; }
|
|
||||||
|
|
||||||
inline void post_seek() { m_got_cr = false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,468 +0,0 @@
|
||||||
// File: data_stream_serializer.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_data_stream.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
// Defaults to little endian mode.
|
|
||||||
class data_stream_serializer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
data_stream_serializer() : m_pStream(NULL), m_little_endian(true) { }
|
|
||||||
data_stream_serializer(data_stream* pStream) : m_pStream(pStream), m_little_endian(true) { }
|
|
||||||
data_stream_serializer(data_stream& stream) : m_pStream(&stream), m_little_endian(true) { }
|
|
||||||
data_stream_serializer(const data_stream_serializer& other) : m_pStream(other.m_pStream), m_little_endian(other.m_little_endian) { }
|
|
||||||
|
|
||||||
data_stream_serializer& operator= (const data_stream_serializer& rhs) { m_pStream = rhs.m_pStream; m_little_endian = rhs.m_little_endian; return *this; }
|
|
||||||
|
|
||||||
data_stream* get_stream() const { return m_pStream; }
|
|
||||||
void set_stream(data_stream* pStream) { m_pStream = pStream; }
|
|
||||||
|
|
||||||
const dynamic_string& get_name() const { return m_pStream ? m_pStream->get_name() : g_empty_dynamic_string; }
|
|
||||||
|
|
||||||
bool get_error() { return m_pStream ? m_pStream->get_error() : false; }
|
|
||||||
|
|
||||||
bool get_little_endian() const { return m_little_endian; }
|
|
||||||
void set_little_endian(bool little_endian) { m_little_endian = little_endian; }
|
|
||||||
|
|
||||||
bool write(const void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
return m_pStream->write(pBuf, len) == len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool read(void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
return m_pStream->read(pBuf, len) == len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// size = size of each element, count = number of elements, returns actual count of elements written
|
|
||||||
uint write(const void* pBuf, uint size, uint count)
|
|
||||||
{
|
|
||||||
uint actual_size = size * count;
|
|
||||||
if (!actual_size)
|
|
||||||
return 0;
|
|
||||||
uint n = m_pStream->write(pBuf, actual_size);
|
|
||||||
if (n == actual_size)
|
|
||||||
return count;
|
|
||||||
return n / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// size = size of each element, count = number of elements, returns actual count of elements read
|
|
||||||
uint read(void* pBuf, uint size, uint count)
|
|
||||||
{
|
|
||||||
uint actual_size = size * count;
|
|
||||||
if (!actual_size)
|
|
||||||
return 0;
|
|
||||||
uint n = m_pStream->read(pBuf, actual_size);
|
|
||||||
if (n == actual_size)
|
|
||||||
return count;
|
|
||||||
return n / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write_chars(const char* pBuf, uint len)
|
|
||||||
{
|
|
||||||
return write(pBuf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool read_chars(char* pBuf, uint len)
|
|
||||||
{
|
|
||||||
return read(pBuf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skip(uint len)
|
|
||||||
{
|
|
||||||
return m_pStream->skip(len) == len;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool write_object(const T& obj)
|
|
||||||
{
|
|
||||||
if (m_little_endian == c_crnlib_little_endian_platform)
|
|
||||||
return write(&obj, sizeof(obj));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8 buf[sizeof(T)];
|
|
||||||
uint buf_size = sizeof(T);
|
|
||||||
void* pBuf = buf;
|
|
||||||
utils::write_obj(obj, pBuf, buf_size, m_little_endian);
|
|
||||||
|
|
||||||
return write(buf, sizeof(T));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool read_object(T& obj)
|
|
||||||
{
|
|
||||||
if (m_little_endian == c_crnlib_little_endian_platform)
|
|
||||||
return read(&obj, sizeof(obj));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8 buf[sizeof(T)];
|
|
||||||
if (!read(buf, sizeof(T)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint buf_size = sizeof(T);
|
|
||||||
const void* pBuf = buf;
|
|
||||||
utils::read_obj(obj, pBuf, buf_size, m_little_endian);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool write_value(T value)
|
|
||||||
{
|
|
||||||
return write_object(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T read_value(const T& on_error_value = T())
|
|
||||||
{
|
|
||||||
T result;
|
|
||||||
if (!read_object(result))
|
|
||||||
result = on_error_value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool write_enum(T e)
|
|
||||||
{
|
|
||||||
int val = static_cast<int>(e);
|
|
||||||
return write_object(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T read_enum()
|
|
||||||
{
|
|
||||||
return static_cast<T>(read_value<int>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes uint using a simple variable length code (VLC).
|
|
||||||
bool write_uint_vlc(uint val)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint8 c = static_cast<uint8>(val) & 0x7F;
|
|
||||||
if (val <= 0x7F)
|
|
||||||
c |= 0x80;
|
|
||||||
|
|
||||||
if (!write_value(c))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
val >>= 7;
|
|
||||||
} while (val);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads uint using a simple variable length code (VLC).
|
|
||||||
bool read_uint_vlc(uint& val)
|
|
||||||
{
|
|
||||||
val = 0;
|
|
||||||
uint shift = 0;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if (shift >= 32)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint8 c;
|
|
||||||
if (!read_object(c))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
val |= ((c & 0x7F) << shift);
|
|
||||||
shift += 7;
|
|
||||||
|
|
||||||
if (c & 0x80)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write_c_str(const char* p)
|
|
||||||
{
|
|
||||||
uint len = static_cast<uint>(strlen(p));
|
|
||||||
if (!write_uint_vlc(len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return write_chars(p, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool read_c_str(char* pBuf, uint buf_size)
|
|
||||||
{
|
|
||||||
uint len;
|
|
||||||
if (!read_uint_vlc(len))
|
|
||||||
return false;
|
|
||||||
if ((len + 1) > buf_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pBuf[len] = '\0';
|
|
||||||
|
|
||||||
return read_chars(pBuf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write_string(const dynamic_string& str)
|
|
||||||
{
|
|
||||||
if (!write_uint_vlc(str.get_len()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return write_chars(str.get_ptr(), str.get_len());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool read_string(dynamic_string& str)
|
|
||||||
{
|
|
||||||
uint len;
|
|
||||||
if (!read_uint_vlc(len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!str.set_len(len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
|
||||||
if (!read_chars(str.get_ptr_raw(), len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (memchr(str.get_ptr(), 0, len) != NULL)
|
|
||||||
{
|
|
||||||
str.truncate(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool write_vector(const T& vec)
|
|
||||||
{
|
|
||||||
if (!write_uint_vlc(vec.size()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (uint i = 0; i < vec.size(); i++)
|
|
||||||
{
|
|
||||||
*this << vec[i];
|
|
||||||
if (get_error())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool read_vector(T& vec, uint num_expected = UINT_MAX)
|
|
||||||
{
|
|
||||||
uint size;
|
|
||||||
if (!read_uint_vlc(size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((size * sizeof(T::value_type)) >= 2U*1024U*1024U*1024U)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((num_expected != UINT_MAX) && (size != num_expected))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
vec.resize(size);
|
|
||||||
for (uint i = 0; i < vec.size(); i++)
|
|
||||||
{
|
|
||||||
*this >> vec[i];
|
|
||||||
|
|
||||||
if (get_error())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool read_entire_file(crnlib::vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
return m_pStream->read_array(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write_entire_file(const crnlib::vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
return m_pStream->write_array(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Got this idea from the Molly Rocket forums.
|
|
||||||
// fmt may contain the characters "1", "2", or "4".
|
|
||||||
bool writef(char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list v;
|
|
||||||
va_start(v, fmt);
|
|
||||||
|
|
||||||
while (*fmt)
|
|
||||||
{
|
|
||||||
switch (*fmt++)
|
|
||||||
{
|
|
||||||
case '1':
|
|
||||||
{
|
|
||||||
const uint8 x = static_cast<uint8>(va_arg(v, uint));
|
|
||||||
if (!write_value(x))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case '2':
|
|
||||||
{
|
|
||||||
const uint16 x = static_cast<uint16>(va_arg(v, uint));
|
|
||||||
if (!write_value(x))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case '4':
|
|
||||||
{
|
|
||||||
const uint32 x = static_cast<uint32>(va_arg(v, uint));
|
|
||||||
if (!write_value(x))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case ' ':
|
|
||||||
case ',':
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(v);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Got this idea from the Molly Rocket forums.
|
|
||||||
// fmt may contain the characters "1", "2", or "4".
|
|
||||||
bool readf(char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list v;
|
|
||||||
va_start(v, fmt);
|
|
||||||
|
|
||||||
while (*fmt)
|
|
||||||
{
|
|
||||||
switch (*fmt++)
|
|
||||||
{
|
|
||||||
case '1':
|
|
||||||
{
|
|
||||||
uint8* x = va_arg(v, uint8*);
|
|
||||||
CRNLIB_ASSERT(x);
|
|
||||||
if (!read_object(*x))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case '2':
|
|
||||||
{
|
|
||||||
uint16* x = va_arg(v, uint16*);
|
|
||||||
CRNLIB_ASSERT(x);
|
|
||||||
if (!read_object(*x))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case '4':
|
|
||||||
{
|
|
||||||
uint32* x = va_arg(v, uint32*);
|
|
||||||
CRNLIB_ASSERT(x);
|
|
||||||
if (!read_object(*x))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case ' ':
|
|
||||||
case ',':
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(v);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
data_stream* m_pStream;
|
|
||||||
|
|
||||||
bool m_little_endian;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Write operators
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, bool val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int8 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint8 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int16 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint16 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int32 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint32 val) { serializer.write_uint_vlc(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int64 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint64 val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, long val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, unsigned long val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, float val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, double val) { serializer.write_value(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const char* p) { serializer.write_c_str(p); return serializer; }
|
|
||||||
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const dynamic_string& str)
|
|
||||||
{
|
|
||||||
serializer.write_string(str);
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const crnlib::vector<T>& vec)
|
|
||||||
{
|
|
||||||
serializer.write_vector(vec);
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const T* p)
|
|
||||||
{
|
|
||||||
serializer.write_object(*p);
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read operators
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, bool& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int8& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint8& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int16& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint16& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int32& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint32& val) { serializer.read_uint_vlc(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int64& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint64& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, long& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, unsigned long& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, float& val) { serializer.read_object(val); return serializer; }
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, double& val) { serializer.read_object(val); return serializer; }
|
|
||||||
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, dynamic_string& str)
|
|
||||||
{
|
|
||||||
serializer.read_string(str);
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, crnlib::vector<T>& vec)
|
|
||||||
{
|
|
||||||
serializer.read_vector(vec);
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, T* p)
|
|
||||||
{
|
|
||||||
serializer.read_object(*p);
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,259 +0,0 @@
|
||||||
// File: crn_dds_comp.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_dds_comp.h"
|
|
||||||
#include "crn_dynamic_stream.h"
|
|
||||||
#include "crn_lzma_codec.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
dds_comp::dds_comp() :
|
|
||||||
m_pParams(NULL),
|
|
||||||
m_pixel_fmt(PIXEL_FMT_INVALID),
|
|
||||||
m_pQDXT_state(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
dds_comp::~dds_comp()
|
|
||||||
{
|
|
||||||
crnlib_delete(m_pQDXT_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dds_comp::clear()
|
|
||||||
{
|
|
||||||
m_src_tex.clear();
|
|
||||||
m_packed_tex.clear();
|
|
||||||
m_comp_data.clear();
|
|
||||||
m_pParams = NULL;
|
|
||||||
m_pixel_fmt = PIXEL_FMT_INVALID;
|
|
||||||
m_task_pool.deinit();
|
|
||||||
if (m_pQDXT_state)
|
|
||||||
{
|
|
||||||
crnlib_delete(m_pQDXT_state);
|
|
||||||
m_pQDXT_state = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dds_comp::create_dds_tex(mipmapped_texture &dds_tex)
|
|
||||||
{
|
|
||||||
image_u8 images[cCRNMaxFaces][cCRNMaxLevels];
|
|
||||||
|
|
||||||
bool has_alpha = false;
|
|
||||||
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
|
|
||||||
{
|
|
||||||
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
|
|
||||||
{
|
|
||||||
const uint width = math::maximum(1U, m_pParams->m_width >> level_index);
|
|
||||||
const uint height = math::maximum(1U, m_pParams->m_height >> level_index);
|
|
||||||
|
|
||||||
if (!m_pParams->m_pImages[face_index][level_index])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
images[face_index][level_index].alias((color_quad_u8*)m_pParams->m_pImages[face_index][level_index], width, height);
|
|
||||||
if (!has_alpha)
|
|
||||||
has_alpha = image_utils::has_alpha(images[face_index][level_index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
|
|
||||||
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
|
|
||||||
images[face_index][level_index].set_component_valid(3, has_alpha);
|
|
||||||
|
|
||||||
image_utils::conversion_type conv_type = image_utils::get_image_conversion_type_from_crn_format((crn_format)m_pParams->m_format);
|
|
||||||
if (conv_type != image_utils::cConversion_Invalid)
|
|
||||||
{
|
|
||||||
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
|
|
||||||
{
|
|
||||||
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
|
|
||||||
{
|
|
||||||
image_u8 cooked_image(images[face_index][level_index]);
|
|
||||||
|
|
||||||
image_utils::convert_image(cooked_image, conv_type);
|
|
||||||
|
|
||||||
images[face_index][level_index].swap(cooked_image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
face_vec faces(m_pParams->m_faces);
|
|
||||||
|
|
||||||
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
|
|
||||||
{
|
|
||||||
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
|
|
||||||
{
|
|
||||||
mip_level *pMip = crnlib_new<mip_level>();
|
|
||||||
|
|
||||||
image_u8 *pImage = crnlib_new<image_u8>();
|
|
||||||
pImage->swap(images[face_index][level_index]);
|
|
||||||
pMip->assign(pImage);
|
|
||||||
|
|
||||||
faces[face_index].push_back(pMip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dds_tex.assign(faces);
|
|
||||||
#ifdef CRNLIB_BUILD_DEBUG
|
|
||||||
CRNLIB_ASSERT(dds_tex.check());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool progress_callback_func(uint percentage_complete, void* pUser_data_ptr)
|
|
||||||
{
|
|
||||||
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
|
|
||||||
return params.m_pProgress_func(0, 1, percentage_complete, 100, params.m_pProgress_func_data) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool progress_callback_func_phase_0(uint percentage_complete, void* pUser_data_ptr)
|
|
||||||
{
|
|
||||||
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
|
|
||||||
return params.m_pProgress_func(0, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool progress_callback_func_phase_1(uint percentage_complete, void* pUser_data_ptr)
|
|
||||||
{
|
|
||||||
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
|
|
||||||
return params.m_pProgress_func(1, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dds_comp::convert_to_dxt(const crn_comp_params& params)
|
|
||||||
{
|
|
||||||
if ((params.m_quality_level == cCRNMaxQualityLevel) || (params.m_format == cCRNFmtDXT3))
|
|
||||||
{
|
|
||||||
m_packed_tex = m_src_tex;
|
|
||||||
if (!m_packed_tex.convert(m_pixel_fmt, false, m_pack_params))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
|
|
||||||
|
|
||||||
m_q1_params.m_quality_level = params.m_quality_level;
|
|
||||||
m_q1_params.m_hierarchical = hierarchical;
|
|
||||||
|
|
||||||
m_q5_params.m_quality_level = params.m_quality_level;
|
|
||||||
m_q5_params.m_hierarchical = hierarchical;
|
|
||||||
|
|
||||||
if (!m_pQDXT_state)
|
|
||||||
{
|
|
||||||
m_pQDXT_state = crnlib_new<mipmapped_texture::qdxt_state>(m_task_pool);
|
|
||||||
|
|
||||||
if (params.m_pProgress_func)
|
|
||||||
{
|
|
||||||
m_q1_params.m_pProgress_func = progress_callback_func_phase_0;
|
|
||||||
m_q1_params.m_pProgress_data = (void*)¶ms;
|
|
||||||
m_q5_params.m_pProgress_func = progress_callback_func_phase_0;
|
|
||||||
m_q5_params.m_pProgress_data = (void*)¶ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_src_tex.qdxt_pack_init(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params, m_pixel_fmt, false))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (params.m_pProgress_func)
|
|
||||||
{
|
|
||||||
m_q1_params.m_pProgress_func = progress_callback_func_phase_1;
|
|
||||||
m_q5_params.m_pProgress_func = progress_callback_func_phase_1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (params.m_pProgress_func)
|
|
||||||
{
|
|
||||||
m_q1_params.m_pProgress_func = progress_callback_func;
|
|
||||||
m_q1_params.m_pProgress_data = (void*)¶ms;
|
|
||||||
m_q5_params.m_pProgress_func = progress_callback_func;
|
|
||||||
m_q5_params.m_pProgress_data = (void*)¶ms;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_src_tex.qdxt_pack(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dds_comp::compress_init(const crn_comp_params& params)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_pParams = ¶ms;
|
|
||||||
|
|
||||||
if ((math::minimum(m_pParams->m_width, m_pParams->m_height) < 1) || (math::maximum(m_pParams->m_width, m_pParams->m_height) > cCRNMaxLevelResolution))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (math::minimum(m_pParams->m_faces, m_pParams->m_levels) < 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!create_dds_tex(m_src_tex))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_pack_params.init(*m_pParams);
|
|
||||||
if (params.m_pProgress_func)
|
|
||||||
{
|
|
||||||
m_pack_params.m_pProgress_callback = progress_callback_func;
|
|
||||||
m_pack_params.m_pProgress_callback_user_data_ptr = (void*)¶ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pixel_fmt = pixel_format_helpers::convert_crn_format_to_pixel_format(static_cast<crn_format>(m_pParams->m_format));
|
|
||||||
if (m_pixel_fmt == PIXEL_FMT_INVALID)
|
|
||||||
return false;
|
|
||||||
if ((m_pixel_fmt == PIXEL_FMT_DXT1) && (m_src_tex.has_alpha()) && (m_pack_params.m_use_both_block_types) && (m_pParams->m_flags & cCRNCompFlagDXT1AForTransparency))
|
|
||||||
m_pixel_fmt = PIXEL_FMT_DXT1A;
|
|
||||||
|
|
||||||
if (!m_task_pool.init(m_pParams->m_num_helper_threads))
|
|
||||||
return false;
|
|
||||||
m_pack_params.m_pTask_pool = &m_task_pool;
|
|
||||||
|
|
||||||
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
|
|
||||||
m_q1_params.init(m_pack_params, params.m_quality_level, hierarchical);
|
|
||||||
m_q5_params.init(m_pack_params, params.m_quality_level, hierarchical);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dds_comp::compress_pass(const crn_comp_params& params, float *pEffective_bitrate)
|
|
||||||
{
|
|
||||||
if (pEffective_bitrate) *pEffective_bitrate = 0.0f;
|
|
||||||
|
|
||||||
if (!m_pParams)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!convert_to_dxt(params))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dynamic_stream out_stream;
|
|
||||||
out_stream.reserve(512*1024);
|
|
||||||
data_stream_serializer serializer(out_stream);
|
|
||||||
|
|
||||||
if (!m_packed_tex.write_dds(serializer))
|
|
||||||
return false;
|
|
||||||
out_stream.reserve(0);
|
|
||||||
|
|
||||||
m_comp_data.swap(out_stream.get_buf());
|
|
||||||
|
|
||||||
if (pEffective_bitrate)
|
|
||||||
{
|
|
||||||
lzma_codec lossless_codec;
|
|
||||||
|
|
||||||
crnlib::vector<uint8> cmp_tex_bytes;
|
|
||||||
if (lossless_codec.pack(m_comp_data.get_ptr(), m_comp_data.size(), cmp_tex_bytes))
|
|
||||||
{
|
|
||||||
uint comp_size = cmp_tex_bytes.size();
|
|
||||||
if (comp_size)
|
|
||||||
{
|
|
||||||
*pEffective_bitrate = (comp_size * 8.0f) / m_src_tex.get_total_pixels_in_all_faces_and_mips();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dds_comp::compress_deinit()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,48 +0,0 @@
|
||||||
// File: crn_comp.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_comp.h"
|
|
||||||
#include "crn_mipmapped_texture.h"
|
|
||||||
#include "crn_texture_comp.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class dds_comp : public itexture_comp
|
|
||||||
{
|
|
||||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(dds_comp);
|
|
||||||
|
|
||||||
public:
|
|
||||||
dds_comp();
|
|
||||||
virtual ~dds_comp();
|
|
||||||
|
|
||||||
virtual const char *get_ext() const { return "DDS"; }
|
|
||||||
|
|
||||||
virtual bool compress_init(const crn_comp_params& params);
|
|
||||||
virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate);
|
|
||||||
virtual void compress_deinit();
|
|
||||||
|
|
||||||
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
|
|
||||||
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
mipmapped_texture m_src_tex;
|
|
||||||
mipmapped_texture m_packed_tex;
|
|
||||||
|
|
||||||
crnlib::vector<uint8> m_comp_data;
|
|
||||||
|
|
||||||
const crn_comp_params* m_pParams;
|
|
||||||
|
|
||||||
pixel_format m_pixel_fmt;
|
|
||||||
dxt_image::pack_params m_pack_params;
|
|
||||||
|
|
||||||
task_pool m_task_pool;
|
|
||||||
qdxt1_params m_q1_params;
|
|
||||||
qdxt5_params m_q5_params;
|
|
||||||
mipmapped_texture::qdxt_state *m_pQDXT_state;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
bool create_dds_tex(mipmapped_texture &dds_tex);
|
|
||||||
bool convert_to_dxt(const crn_comp_params& params);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,6 +0,0 @@
|
||||||
// File: crn_decomp.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
|
|
||||||
// Include the single-file header library with no defines, which brings in the full CRN decompressor.
|
|
||||||
#include "../inc/crn_decomp.h"
|
|
|
@ -1,386 +0,0 @@
|
||||||
// File: crn_dxt.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
#include "crn_dxt1.h"
|
|
||||||
#include "crn_ryg_dxt.hpp"
|
|
||||||
#include "crn_dxt_fast.h"
|
|
||||||
#include "crn_intersect.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
const uint8 g_dxt5_from_linear[cDXT5SelectorValues] = { 0U, 2U, 3U, 4U, 5U, 6U, 7U, 1U };
|
|
||||||
const uint8 g_dxt5_to_linear[cDXT5SelectorValues] = { 0U, 7U, 1U, 2U, 3U, 4U, 5U, 6U };
|
|
||||||
|
|
||||||
const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues] = { 0U, 5U, 1U, 2U, 3U, 4U, 0U, 0U };
|
|
||||||
|
|
||||||
const uint8 g_dxt1_from_linear[cDXT1SelectorValues] = { 0U, 2U, 3U, 1U };
|
|
||||||
const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = { 0U, 3U, 1U, 2U };
|
|
||||||
|
|
||||||
const uint8 g_six_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 5, 4, 3, 2, 6, 7 };
|
|
||||||
const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 7, 6, 5, 4, 3, 2 };
|
|
||||||
|
|
||||||
const char* get_dxt_format_string(dxt_format fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case cDXT1: return "DXT1";
|
|
||||||
case cDXT1A: return "DXT1A";
|
|
||||||
case cDXT3: return "DXT3";
|
|
||||||
case cDXT5: return "DXT5";
|
|
||||||
case cDXT5A: return "DXT5A";
|
|
||||||
case cDXN_XY: return "DXN_XY";
|
|
||||||
case cDXN_YX: return "DXN_YX";
|
|
||||||
case cETC1: return "ETC1";
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
CRNLIB_ASSERT(false);
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* get_dxt_compressor_name(crn_dxt_compressor_type c)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case cCRNDXTCompressorCRN: return "CRN";
|
|
||||||
case cCRNDXTCompressorCRNF: return "CRNF";
|
|
||||||
case cCRNDXTCompressorRYG: return "RYG";
|
|
||||||
#if CRNLIB_SUPPORT_ATI_COMPRESS
|
|
||||||
case cCRNDXTCompressorATI: return "ATI";
|
|
||||||
#endif
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
CRNLIB_ASSERT(false);
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_dxt_format_bits_per_pixel(dxt_format fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case cDXT1:
|
|
||||||
case cDXT1A:
|
|
||||||
case cDXT5A:
|
|
||||||
case cETC1:
|
|
||||||
return 4;
|
|
||||||
case cDXT3:
|
|
||||||
case cDXT5:
|
|
||||||
case cDXN_XY:
|
|
||||||
case cDXN_YX:
|
|
||||||
return 8;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
CRNLIB_ASSERT(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_dxt_format_has_alpha(dxt_format fmt)
|
|
||||||
{
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case cDXT1A:
|
|
||||||
case cDXT3:
|
|
||||||
case cDXT5:
|
|
||||||
case cDXT5A:
|
|
||||||
return true;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 dxt1_block::pack_color(const color_quad_u8& color, bool scaled, uint bias)
|
|
||||||
{
|
|
||||||
uint r = color.r;
|
|
||||||
uint g = color.g;
|
|
||||||
uint b = color.b;
|
|
||||||
|
|
||||||
if (scaled)
|
|
||||||
{
|
|
||||||
r = (r * 31U + bias) / 255U;
|
|
||||||
g = (g * 63U + bias) / 255U;
|
|
||||||
b = (b * 31U + bias) / 255U;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = math::minimum(r, 31U);
|
|
||||||
g = math::minimum(g, 63U);
|
|
||||||
b = math::minimum(b, 31U);
|
|
||||||
|
|
||||||
return static_cast<uint16>(b | (g << 5U) | (r << 11U));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 dxt1_block::pack_color(uint r, uint g, uint b, bool scaled, uint bias)
|
|
||||||
{
|
|
||||||
return pack_color(color_quad_u8(r, g, b, 0), scaled, bias);
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8 dxt1_block::unpack_color(uint16 packed_color, bool scaled, uint alpha)
|
|
||||||
{
|
|
||||||
uint b = packed_color & 31U;
|
|
||||||
uint g = (packed_color >> 5U) & 63U;
|
|
||||||
uint r = (packed_color >> 11U) & 31U;
|
|
||||||
|
|
||||||
if (scaled)
|
|
||||||
{
|
|
||||||
b = (b << 3U) | (b >> 2U);
|
|
||||||
g = (g << 2U) | (g >> 4U);
|
|
||||||
r = (r << 3U) | (r >> 2U);
|
|
||||||
}
|
|
||||||
|
|
||||||
return color_quad_u8(cNoClamp, r, g, b, math::minimum(alpha, 255U));
|
|
||||||
}
|
|
||||||
|
|
||||||
void dxt1_block::unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled)
|
|
||||||
{
|
|
||||||
color_quad_u8 c(unpack_color(packed_color, scaled, 0));
|
|
||||||
r = c.r;
|
|
||||||
g = c.g;
|
|
||||||
b = c.b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dxt1_block::get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4)
|
|
||||||
{
|
|
||||||
color_quad_u8 col0(unpack_color(packed_col0, false));
|
|
||||||
color_quad_u8 col1(unpack_color(packed_col1, false));
|
|
||||||
|
|
||||||
pDst[0].r = (3 * col0.r * 22) / 8;
|
|
||||||
pDst[0].b = (3 * col0.b * 22) / 8;
|
|
||||||
pDst[0].g = (col0.g << 2) | (col0.g >> 4);
|
|
||||||
pDst[0].a = 0xFF;
|
|
||||||
|
|
||||||
pDst[1].r = (3 * col1.r * 22) / 8;
|
|
||||||
pDst[1].g = (col1.g << 2) | (col1.g >> 4);
|
|
||||||
pDst[1].b = (3 * col1.b * 22) / 8;
|
|
||||||
pDst[1].a = 0xFF;
|
|
||||||
|
|
||||||
int gdiff = pDst[1].g - pDst[0].g;
|
|
||||||
|
|
||||||
if (color4) //(packed_col0 > packed_col1)
|
|
||||||
{
|
|
||||||
pDst[2].r = static_cast<uint8>(((2 * col0.r + col1.r) * 22) / 8);
|
|
||||||
pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff/4 + 128 + gdiff * 80) / 256);
|
|
||||||
pDst[2].b = static_cast<uint8>(((2 * col0.b + col1.b) * 22) / 8);
|
|
||||||
pDst[2].a = 0xFF;
|
|
||||||
|
|
||||||
pDst[3].r = static_cast<uint8>(((2 * col1.r + col0.r) * 22) / 8);
|
|
||||||
pDst[3].g = static_cast<uint8>((256 * pDst[1].g - gdiff/4 + 128 - gdiff * 80) / 256);
|
|
||||||
pDst[3].b = static_cast<uint8>(((2 * col1.b + col0.b) * 22) / 8);
|
|
||||||
pDst[3].a = 0xFF;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pDst[2].r = static_cast<uint8>(((col0.r + col1.r) * 33) / 8);
|
|
||||||
pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff/4 + 128 + gdiff * 128) / 256);
|
|
||||||
pDst[2].b = static_cast<uint8>(((col0.b + col1.b) * 33) / 8);
|
|
||||||
pDst[2].a = 0xFF;
|
|
||||||
|
|
||||||
pDst[3].r = 0x00;
|
|
||||||
pDst[3].g = 0x00;
|
|
||||||
pDst[3].b = 0x00;
|
|
||||||
pDst[3].a = 0x00;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1)
|
|
||||||
{
|
|
||||||
color_quad_u8 c0(unpack_color(color0, true));
|
|
||||||
color_quad_u8 c1(unpack_color(color1, true));
|
|
||||||
|
|
||||||
pDst[0] = c0;
|
|
||||||
pDst[1] = c1;
|
|
||||||
pDst[2].set_noclamp_rgba( (c0.r + c1.r) >> 1U, (c0.g + c1.g) >> 1U, (c0.b + c1.b) >> 1U, 255U);
|
|
||||||
pDst[3].set_noclamp_rgba(0, 0, 0, 0);
|
|
||||||
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1)
|
|
||||||
{
|
|
||||||
color_quad_u8 c0(unpack_color(color0, true));
|
|
||||||
color_quad_u8 c1(unpack_color(color1, true));
|
|
||||||
|
|
||||||
pDst[0] = c0;
|
|
||||||
pDst[1] = c1;
|
|
||||||
|
|
||||||
// The compiler changes the div3 into a mul by recip+shift.
|
|
||||||
pDst[2].set_noclamp_rgba( (c0.r * 2 + c1.r) / 3, (c0.g * 2 + c1.g) / 3, (c0.b * 2 + c1.b) / 3, 255U);
|
|
||||||
pDst[3].set_noclamp_rgba( (c1.r * 2 + c0.r) / 3, (c1.g * 2 + c0.g) / 3, (c1.b * 2 + c0.b) / 3, 255U);
|
|
||||||
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
|
|
||||||
{
|
|
||||||
color_quad_u8 c0(unpack_color(color0, true));
|
|
||||||
color_quad_u8 c1(unpack_color(color1, true));
|
|
||||||
|
|
||||||
pDst[0] = c0;
|
|
||||||
pDst[1] = c1;
|
|
||||||
pDst[2].set_noclamp_rgba( (c0.r + c1.r + 1) >> 1U, (c0.g + c1.g + 1) >> 1U, (c0.b + c1.b + 1) >> 1U, 255U);
|
|
||||||
pDst[3].set_noclamp_rgba(0, 0, 0, 0);
|
|
||||||
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
|
|
||||||
{
|
|
||||||
color_quad_u8 c0(unpack_color(color0, true));
|
|
||||||
color_quad_u8 c1(unpack_color(color1, true));
|
|
||||||
|
|
||||||
pDst[0] = c0;
|
|
||||||
pDst[1] = c1;
|
|
||||||
|
|
||||||
// 12/14/08 - Supposed to round according to DX docs, but this conflicts with the OpenGL S3TC spec. ?
|
|
||||||
// The compiler changes the div3 into a mul by recip+shift.
|
|
||||||
pDst[2].set_noclamp_rgba( (c0.r * 2 + c1.r + 1) / 3, (c0.g * 2 + c1.g + 1) / 3, (c0.b * 2 + c1.b + 1) / 3, 255U);
|
|
||||||
pDst[3].set_noclamp_rgba( (c1.r * 2 + c0.r + 1) / 3, (c1.g * 2 + c0.g + 1) / 3, (c1.b * 2 + c0.b + 1) / 3, 255U);
|
|
||||||
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1)
|
|
||||||
{
|
|
||||||
if (color0 > color1)
|
|
||||||
return get_block_colors4(pDst, color0, color1);
|
|
||||||
else
|
|
||||||
return get_block_colors3(pDst, color0, color1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
|
|
||||||
{
|
|
||||||
if (color0 > color1)
|
|
||||||
return get_block_colors4_round(pDst, color0, color1);
|
|
||||||
else
|
|
||||||
return get_block_colors3_round(pDst, color0, color1);
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8 dxt1_block::unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(index < 2);
|
|
||||||
return unpack_color( static_cast<uint16>((endpoints >> (index * 16U)) & 0xFFFFU), scaled, alpha );
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt1_block::pack_endpoints(uint lo, uint hi)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((lo <= 0xFFFFU) && (hi <= 0xFFFFU));
|
|
||||||
return lo | (hi << 16U);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dxt3_block::set_alpha(uint x, uint y, uint value, bool scaled)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
|
|
||||||
|
|
||||||
if (scaled)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(value <= 0xFF);
|
|
||||||
value = (value * 15U + 128U) / 255U;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(value <= 0xF);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint ofs = (y << 1U) + (x >> 1U);
|
|
||||||
uint c = m_alpha[ofs];
|
|
||||||
|
|
||||||
c &= ~(0xF << ((x & 1U) << 2U));
|
|
||||||
c |= (value << ((x & 1U) << 2U));
|
|
||||||
|
|
||||||
m_alpha[ofs] = static_cast<uint8>(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt3_block::get_alpha(uint x, uint y, bool scaled) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
|
|
||||||
|
|
||||||
uint value = m_alpha[(y << 1U) + (x >> 1U)];
|
|
||||||
if (x & 1)
|
|
||||||
value >>= 4;
|
|
||||||
value &= 0xF;
|
|
||||||
|
|
||||||
if (scaled)
|
|
||||||
value = (value << 4U) | value;
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::get_block_values6(color_quad_u8* pDst, uint l, uint h)
|
|
||||||
{
|
|
||||||
pDst[0].a = static_cast<uint8>(l);
|
|
||||||
pDst[1].a = static_cast<uint8>(h);
|
|
||||||
pDst[2].a = static_cast<uint8>((l * 4 + h ) / 5);
|
|
||||||
pDst[3].a = static_cast<uint8>((l * 3 + h * 2) / 5);
|
|
||||||
pDst[4].a = static_cast<uint8>((l * 2 + h * 3) / 5);
|
|
||||||
pDst[5].a = static_cast<uint8>((l + h * 4) / 5);
|
|
||||||
pDst[6].a = 0;
|
|
||||||
pDst[7].a = 255;
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::get_block_values8(color_quad_u8* pDst, uint l, uint h)
|
|
||||||
{
|
|
||||||
pDst[0].a = static_cast<uint8>(l);
|
|
||||||
pDst[1].a = static_cast<uint8>(h);
|
|
||||||
pDst[2].a = static_cast<uint8>((l * 6 + h ) / 7);
|
|
||||||
pDst[3].a = static_cast<uint8>((l * 5 + h * 2) / 7);
|
|
||||||
pDst[4].a = static_cast<uint8>((l * 4 + h * 3) / 7);
|
|
||||||
pDst[5].a = static_cast<uint8>((l * 3 + h * 4) / 7);
|
|
||||||
pDst[6].a = static_cast<uint8>((l * 2 + h * 5) / 7);
|
|
||||||
pDst[7].a = static_cast<uint8>((l + h * 6) / 7);
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::get_block_values(color_quad_u8* pDst, uint l, uint h)
|
|
||||||
{
|
|
||||||
if (l > h)
|
|
||||||
return get_block_values8(pDst, l, h);
|
|
||||||
else
|
|
||||||
return get_block_values6(pDst, l, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::get_block_values6(uint* pDst, uint l, uint h)
|
|
||||||
{
|
|
||||||
pDst[0] = l;
|
|
||||||
pDst[1] = h;
|
|
||||||
pDst[2] = (l * 4 + h ) / 5;
|
|
||||||
pDst[3] = (l * 3 + h * 2) / 5;
|
|
||||||
pDst[4] = (l * 2 + h * 3) / 5;
|
|
||||||
pDst[5] = (l + h * 4) / 5;
|
|
||||||
pDst[6] = 0;
|
|
||||||
pDst[7] = 255;
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::get_block_values8(uint* pDst, uint l, uint h)
|
|
||||||
{
|
|
||||||
pDst[0] = l;
|
|
||||||
pDst[1] = h;
|
|
||||||
pDst[2] = (l * 6 + h ) / 7;
|
|
||||||
pDst[3] = (l * 5 + h * 2) / 7;
|
|
||||||
pDst[4] = (l * 4 + h * 3) / 7;
|
|
||||||
pDst[5] = (l * 3 + h * 4) / 7;
|
|
||||||
pDst[6] = (l * 2 + h * 5) / 7;
|
|
||||||
pDst[7] = (l + h * 6) / 7;
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::unpack_endpoint(uint packed, uint index)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(index < 2);
|
|
||||||
return (packed >> (8 * index)) & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::pack_endpoints(uint lo, uint hi)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((lo <= 0xFF) && (hi <= 0xFF));
|
|
||||||
return lo | (hi << 8U);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dxt5_block::get_block_values(uint* pDst, uint l, uint h)
|
|
||||||
{
|
|
||||||
if (l > h)
|
|
||||||
return get_block_values8(pDst, l, h);
|
|
||||||
else
|
|
||||||
return get_block_values6(pDst, l, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,361 +0,0 @@
|
||||||
// File: crn_dxt.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "../inc/crnlib.h"
|
|
||||||
#include "crn_color.h"
|
|
||||||
#include "crn_vec.h"
|
|
||||||
#include "crn_rand.h"
|
|
||||||
#include "crn_sparse_bit_array.h"
|
|
||||||
#include "crn_hash_map.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#define CRNLIB_DXT_ALT_ROUNDING 1
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
enum dxt_constants
|
|
||||||
{
|
|
||||||
cDXT1BytesPerBlock = 8U,
|
|
||||||
cDXT5NBytesPerBlock = 16U,
|
|
||||||
|
|
||||||
cDXT5SelectorBits = 3U,
|
|
||||||
cDXT5SelectorValues = 1U << cDXT5SelectorBits,
|
|
||||||
cDXT5SelectorMask = cDXT5SelectorValues - 1U,
|
|
||||||
|
|
||||||
cDXT1SelectorBits = 2U,
|
|
||||||
cDXT1SelectorValues = 1U << cDXT1SelectorBits,
|
|
||||||
cDXT1SelectorMask = cDXT1SelectorValues - 1U,
|
|
||||||
|
|
||||||
cDXTBlockShift = 2U,
|
|
||||||
cDXTBlockSize = 1U << cDXTBlockShift
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dxt_format
|
|
||||||
{
|
|
||||||
cDXTInvalid = -1,
|
|
||||||
|
|
||||||
// cDXT1/1A must appear first!
|
|
||||||
cDXT1,
|
|
||||||
cDXT1A,
|
|
||||||
|
|
||||||
cDXT3,
|
|
||||||
cDXT5,
|
|
||||||
cDXT5A,
|
|
||||||
|
|
||||||
cDXN_XY, // inverted relative to standard ATI2, 360's DXN
|
|
||||||
cDXN_YX, // standard ATI2,
|
|
||||||
|
|
||||||
cETC1 // Ericsson texture compression (color only, 4x4 blocks, 4bpp, 64-bits/block)
|
|
||||||
};
|
|
||||||
|
|
||||||
const float cDXT1MaxLinearValue = 3.0f;
|
|
||||||
const float cDXT1InvMaxLinearValue = 1.0f/3.0f;
|
|
||||||
|
|
||||||
const float cDXT5MaxLinearValue = 7.0f;
|
|
||||||
const float cDXT5InvMaxLinearValue = 1.0f/7.0f;
|
|
||||||
|
|
||||||
// Converts DXT1 raw color selector index to a linear value.
|
|
||||||
extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
|
|
||||||
|
|
||||||
// Converts DXT5 raw alpha selector index to a linear value.
|
|
||||||
extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
|
|
||||||
|
|
||||||
// Converts DXT1 linear color selector index to a raw value (inverse of g_dxt1_to_linear).
|
|
||||||
extern const uint8 g_dxt1_from_linear[cDXT1SelectorValues];
|
|
||||||
|
|
||||||
// Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear).
|
|
||||||
extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues];
|
|
||||||
|
|
||||||
extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
|
|
||||||
|
|
||||||
extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
|
|
||||||
extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
|
|
||||||
|
|
||||||
const char* get_dxt_format_string(dxt_format fmt);
|
|
||||||
uint get_dxt_format_bits_per_pixel(dxt_format fmt);
|
|
||||||
bool get_dxt_format_has_alpha(dxt_format fmt);
|
|
||||||
|
|
||||||
const char* get_dxt_quality_string(crn_dxt_quality q);
|
|
||||||
|
|
||||||
const char* get_dxt_compressor_name(crn_dxt_compressor_type c);
|
|
||||||
|
|
||||||
struct dxt1_block
|
|
||||||
{
|
|
||||||
uint8 m_low_color[2];
|
|
||||||
uint8 m_high_color[2];
|
|
||||||
|
|
||||||
enum { cNumSelectorBytes = 4 };
|
|
||||||
uint8 m_selectors[cNumSelectorBytes];
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
utils::zero_this(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// These methods assume the in-memory rep is in LE byte order.
|
|
||||||
inline uint get_low_color() const
|
|
||||||
{
|
|
||||||
return m_low_color[0] | (m_low_color[1] << 8U);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_high_color() const
|
|
||||||
{
|
|
||||||
return m_high_color[0] | (m_high_color[1] << 8U);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_low_color(uint16 c)
|
|
||||||
{
|
|
||||||
m_low_color[0] = static_cast<uint8>(c & 0xFF);
|
|
||||||
m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_high_color(uint16 c)
|
|
||||||
{
|
|
||||||
m_high_color[0] = static_cast<uint8>(c & 0xFF);
|
|
||||||
m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_constant_color_block() const { return get_low_color() == get_high_color(); }
|
|
||||||
inline bool is_alpha_block() const { return get_low_color() <= get_high_color(); }
|
|
||||||
inline bool is_non_alpha_block() const { return !is_alpha_block(); }
|
|
||||||
|
|
||||||
inline uint get_selector(uint x, uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < 4U) && (y < 4U));
|
|
||||||
return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_selector(uint x, uint y, uint val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
|
|
||||||
|
|
||||||
m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
|
|
||||||
m_selectors[y] |= (val << (x * cDXT1SelectorBits));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void flip_x(uint w = 4, uint h = 4)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < (w / 2); x++)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < h; y++)
|
|
||||||
{
|
|
||||||
const uint c = get_selector(x, y);
|
|
||||||
set_selector(x, y, get_selector((w - 1) - x, y));
|
|
||||||
set_selector((w - 1) - x, y, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void flip_y(uint w = 4, uint h = 4)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < (h / 2); y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < w; x++)
|
|
||||||
{
|
|
||||||
const uint c = get_selector(x, y);
|
|
||||||
set_selector(x, y, get_selector(x, (h - 1) - y));
|
|
||||||
set_selector(x, (h - 1) - y, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U);
|
|
||||||
static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
|
|
||||||
|
|
||||||
static color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U);
|
|
||||||
static void unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
|
|
||||||
|
|
||||||
static uint get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1);
|
|
||||||
static uint get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
|
|
||||||
|
|
||||||
static uint get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1);
|
|
||||||
static uint get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
|
|
||||||
|
|
||||||
// pDst must point to an array at least cDXT1SelectorValues long.
|
|
||||||
static uint get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1);
|
|
||||||
|
|
||||||
static uint get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
|
|
||||||
|
|
||||||
static color_quad_u8 unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha = 255U);
|
|
||||||
static uint pack_endpoints(uint lo, uint hi);
|
|
||||||
|
|
||||||
static void get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_block);
|
|
||||||
|
|
||||||
struct dxt3_block
|
|
||||||
{
|
|
||||||
enum { cNumAlphaBytes = 8 };
|
|
||||||
uint8 m_alpha[cNumAlphaBytes];
|
|
||||||
|
|
||||||
void set_alpha(uint x, uint y, uint value, bool scaled);
|
|
||||||
uint get_alpha(uint x, uint y, bool scaled) const;
|
|
||||||
|
|
||||||
inline void flip_x(uint w = 4, uint h = 4)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < (w / 2); x++)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < h; y++)
|
|
||||||
{
|
|
||||||
const uint c = get_alpha(x, y, false);
|
|
||||||
set_alpha(x, y, get_alpha((w - 1) - x, y, false), false);
|
|
||||||
set_alpha((w - 1) - x, y, c, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void flip_y(uint w = 4, uint h = 4)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < (h / 2); y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < w; x++)
|
|
||||||
{
|
|
||||||
const uint c = get_alpha(x, y, false);
|
|
||||||
set_alpha(x, y, get_alpha(x, (h - 1) - y, false), false);
|
|
||||||
set_alpha(x, (h - 1) - y, c, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt3_block);
|
|
||||||
|
|
||||||
struct dxt5_block
|
|
||||||
{
|
|
||||||
uint8 m_endpoints[2];
|
|
||||||
|
|
||||||
enum { cNumSelectorBytes = 6 };
|
|
||||||
uint8 m_selectors[cNumSelectorBytes];
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
utils::zero_this(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_low_alpha() const
|
|
||||||
{
|
|
||||||
return m_endpoints[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_high_alpha() const
|
|
||||||
{
|
|
||||||
return m_endpoints[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_low_alpha(uint i)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(i <= cUINT8_MAX);
|
|
||||||
m_endpoints[0] = static_cast<uint8>(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_high_alpha(uint i)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(i <= cUINT8_MAX);
|
|
||||||
m_endpoints[1] = static_cast<uint8>(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); }
|
|
||||||
|
|
||||||
uint get_endpoints_as_word() const { return m_endpoints[0] | (m_endpoints[1] << 8); }
|
|
||||||
uint get_selectors_as_word(uint index) { CRNLIB_ASSERT(index < 3); return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8); }
|
|
||||||
|
|
||||||
inline uint get_selector(uint x, uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < 4U) && (y < 4U));
|
|
||||||
|
|
||||||
uint selector_index = (y * 4) + x;
|
|
||||||
uint bit_index = selector_index * cDXT5SelectorBits;
|
|
||||||
|
|
||||||
uint byte_index = bit_index >> 3;
|
|
||||||
uint bit_ofs = bit_index & 7;
|
|
||||||
|
|
||||||
uint v = m_selectors[byte_index];
|
|
||||||
if (byte_index < (cNumSelectorBytes - 1))
|
|
||||||
v |= (m_selectors[byte_index + 1] << 8);
|
|
||||||
|
|
||||||
return (v >> bit_ofs) & 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_selector(uint x, uint y, uint val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 8U));
|
|
||||||
|
|
||||||
uint selector_index = (y * 4) + x;
|
|
||||||
uint bit_index = selector_index * cDXT5SelectorBits;
|
|
||||||
|
|
||||||
uint byte_index = bit_index >> 3;
|
|
||||||
uint bit_ofs = bit_index & 7;
|
|
||||||
|
|
||||||
uint v = m_selectors[byte_index];
|
|
||||||
if (byte_index < (cNumSelectorBytes - 1))
|
|
||||||
v |= (m_selectors[byte_index + 1] << 8);
|
|
||||||
|
|
||||||
v &= (~(7 << bit_ofs));
|
|
||||||
v |= (val << bit_ofs);
|
|
||||||
|
|
||||||
m_selectors[byte_index] = static_cast<uint8>(v);
|
|
||||||
if (byte_index < (cNumSelectorBytes - 1))
|
|
||||||
m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void flip_x(uint w = 4, uint h = 4)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < (w / 2); x++)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < h; y++)
|
|
||||||
{
|
|
||||||
const uint c = get_selector(x, y);
|
|
||||||
set_selector(x, y, get_selector((w - 1) - x, y));
|
|
||||||
set_selector((w - 1) - x, y, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void flip_y(uint w = 4, uint h = 4)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < (h / 2); y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < w; x++)
|
|
||||||
{
|
|
||||||
const uint c = get_selector(x, y);
|
|
||||||
set_selector(x, y, get_selector(x, (h - 1) - y));
|
|
||||||
set_selector(x, (h - 1) - y, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { cMaxSelectorValues = 8 };
|
|
||||||
|
|
||||||
// Results written to alpha channel.
|
|
||||||
static uint get_block_values6(color_quad_u8* pDst, uint l, uint h);
|
|
||||||
static uint get_block_values8(color_quad_u8* pDst, uint l, uint h);
|
|
||||||
static uint get_block_values(color_quad_u8* pDst, uint l, uint h);
|
|
||||||
|
|
||||||
static uint get_block_values6(uint* pDst, uint l, uint h);
|
|
||||||
static uint get_block_values8(uint* pDst, uint l, uint h);
|
|
||||||
// pDst must point to an array at least cDXT5SelectorValues long.
|
|
||||||
static uint get_block_values(uint* pDst, uint l, uint h);
|
|
||||||
|
|
||||||
static uint unpack_endpoint(uint packed, uint index);
|
|
||||||
static uint pack_endpoints(uint lo, uint hi);
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt5_block);
|
|
||||||
|
|
||||||
struct dxt_pixel_block
|
|
||||||
{
|
|
||||||
color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
utils::zero_object(*this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,352 +0,0 @@
|
||||||
// File: crn_dxt1.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
struct dxt1_solution_coordinates
|
|
||||||
{
|
|
||||||
inline dxt1_solution_coordinates() : m_low_color(0), m_high_color(0){ }
|
|
||||||
|
|
||||||
inline dxt1_solution_coordinates(uint16 l, uint16 h) : m_low_color(l), m_high_color(h) { }
|
|
||||||
|
|
||||||
inline dxt1_solution_coordinates(const color_quad_u8& l, const color_quad_u8& h, bool scaled = true) :
|
|
||||||
m_low_color(dxt1_block::pack_color(l, scaled)),
|
|
||||||
m_high_color(dxt1_block::pack_color(h, scaled))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline dxt1_solution_coordinates(vec3F nl, vec3F nh)
|
|
||||||
{
|
|
||||||
#if CRNLIB_DXT_ALT_ROUNDING
|
|
||||||
// Umm, wtf?
|
|
||||||
nl.clamp(0.0f, .999f);
|
|
||||||
nh.clamp(0.0f, .999f);
|
|
||||||
color_quad_u8 l( (int)floor(nl[0] * 32.0f), (int)floor(nl[1] * 64.0f), (int)floor(nl[2] * 32.0f), 255);
|
|
||||||
color_quad_u8 h( (int)floor(nh[0] * 32.0f), (int)floor(nh[1] * 64.0f), (int)floor(nh[2] * 32.0f), 255);
|
|
||||||
#else
|
|
||||||
// Fixes the bins
|
|
||||||
color_quad_u8 l( (int)floor(.5f + nl[0] * 31.0f), (int)floor(.5f + nl[1] * 63.0f), (int)floor(.5f + nl[2] * 31.0f), 255);
|
|
||||||
color_quad_u8 h( (int)floor(.5f + nh[0] * 31.0f), (int)floor(.5f + nh[1] * 63.0f), (int)floor(.5f + nh[2] * 31.0f), 255);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_low_color = dxt1_block::pack_color(l, false);
|
|
||||||
m_high_color = dxt1_block::pack_color(h, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 m_low_color;
|
|
||||||
uint16 m_high_color;
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
m_low_color = 0;
|
|
||||||
m_high_color = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline dxt1_solution_coordinates& canonicalize()
|
|
||||||
{
|
|
||||||
if (m_low_color < m_high_color)
|
|
||||||
utils::swap(m_low_color, m_high_color);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator size_t() const { return fast_hash(this, sizeof(*this)); }
|
|
||||||
|
|
||||||
inline bool operator== (const dxt1_solution_coordinates& other) const
|
|
||||||
{
|
|
||||||
uint16 l0 = math::minimum(m_low_color, m_high_color);
|
|
||||||
uint16 h0 = math::maximum(m_low_color, m_high_color);
|
|
||||||
|
|
||||||
uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
|
|
||||||
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
|
|
||||||
|
|
||||||
return (l0 == l1) && (h0 == h1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator!= (const dxt1_solution_coordinates& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator< (const dxt1_solution_coordinates& other) const
|
|
||||||
{
|
|
||||||
uint16 l0 = math::minimum(m_low_color, m_high_color);
|
|
||||||
uint16 h0 = math::maximum(m_low_color, m_high_color);
|
|
||||||
|
|
||||||
uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
|
|
||||||
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
|
|
||||||
|
|
||||||
if (l0 < l1)
|
|
||||||
return true;
|
|
||||||
else if (l0 == l1)
|
|
||||||
{
|
|
||||||
if (h0 < h1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec;
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates);
|
|
||||||
|
|
||||||
struct unique_color
|
|
||||||
{
|
|
||||||
inline unique_color() { }
|
|
||||||
inline unique_color(const color_quad_u8& color, uint weight) : m_color(color), m_weight(weight) { }
|
|
||||||
|
|
||||||
color_quad_u8 m_color;
|
|
||||||
uint m_weight;
|
|
||||||
|
|
||||||
inline bool operator< (const unique_color& c) const
|
|
||||||
{
|
|
||||||
return *reinterpret_cast<const uint32*>(&m_color) < *reinterpret_cast<const uint32*>(&c.m_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator== (const unique_color& c) const
|
|
||||||
{
|
|
||||||
return *reinterpret_cast<const uint32*>(&m_color) == *reinterpret_cast<const uint32*>(&c.m_color);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(unique_color);
|
|
||||||
|
|
||||||
class dxt1_endpoint_optimizer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dxt1_endpoint_optimizer();
|
|
||||||
|
|
||||||
struct params
|
|
||||||
{
|
|
||||||
params() :
|
|
||||||
m_block_index(0),
|
|
||||||
m_pPixels(NULL),
|
|
||||||
m_num_pixels(0),
|
|
||||||
m_dxt1a_alpha_threshold(128U),
|
|
||||||
m_quality(cCRNDXTQualityUber),
|
|
||||||
m_pixels_have_alpha(false),
|
|
||||||
m_use_alpha_blocks(true),
|
|
||||||
m_perceptual(true),
|
|
||||||
m_grayscale_sampling(false),
|
|
||||||
m_endpoint_caching(true),
|
|
||||||
m_use_transparent_indices_for_black(false),
|
|
||||||
m_force_alpha_blocks(false)
|
|
||||||
{
|
|
||||||
m_color_weights[0] = 1;
|
|
||||||
m_color_weights[1] = 1;
|
|
||||||
m_color_weights[2] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint m_block_index;
|
|
||||||
|
|
||||||
const color_quad_u8* m_pPixels;
|
|
||||||
uint m_num_pixels;
|
|
||||||
uint m_dxt1a_alpha_threshold;
|
|
||||||
|
|
||||||
crn_dxt_quality m_quality;
|
|
||||||
|
|
||||||
bool m_pixels_have_alpha;
|
|
||||||
bool m_use_alpha_blocks;
|
|
||||||
bool m_perceptual;
|
|
||||||
bool m_grayscale_sampling;
|
|
||||||
bool m_endpoint_caching;
|
|
||||||
bool m_use_transparent_indices_for_black;
|
|
||||||
bool m_force_alpha_blocks;
|
|
||||||
int m_color_weights[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct results
|
|
||||||
{
|
|
||||||
inline results() : m_pSelectors(NULL) { }
|
|
||||||
|
|
||||||
uint64 m_error;
|
|
||||||
|
|
||||||
uint16 m_low_color;
|
|
||||||
uint16 m_high_color;
|
|
||||||
|
|
||||||
uint8* m_pSelectors;
|
|
||||||
bool m_alpha_block;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct solution
|
|
||||||
{
|
|
||||||
solution() { }
|
|
||||||
|
|
||||||
solution(const solution& other)
|
|
||||||
{
|
|
||||||
m_results = other.m_results;
|
|
||||||
m_selectors = other.m_selectors;
|
|
||||||
m_results.m_pSelectors = m_selectors.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
solution& operator= (const solution& rhs)
|
|
||||||
{
|
|
||||||
if (this == &rhs)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
m_results = rhs.m_results;
|
|
||||||
m_selectors = rhs.m_selectors;
|
|
||||||
m_results.m_pSelectors = m_selectors.begin();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
results m_results;
|
|
||||||
crnlib::vector<uint8> m_selectors;
|
|
||||||
|
|
||||||
inline bool operator< (const solution& other) const
|
|
||||||
{
|
|
||||||
return m_results.m_error < other.m_results.m_error;
|
|
||||||
}
|
|
||||||
static inline bool coords_equal(const solution& lhs, const solution& rhs)
|
|
||||||
{
|
|
||||||
return (lhs.m_results.m_low_color == rhs.m_results.m_low_color) && (lhs.m_results.m_high_color == rhs.m_results.m_high_color);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
typedef crnlib::vector<solution> solution_vec;
|
|
||||||
|
|
||||||
bool compute(const params& p, results& r, solution_vec* pSolutions = NULL);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const params* m_pParams;
|
|
||||||
results* m_pResults;
|
|
||||||
solution_vec* m_pSolutions;
|
|
||||||
|
|
||||||
bool m_perceptual;
|
|
||||||
bool m_has_color_weighting;
|
|
||||||
|
|
||||||
typedef crnlib::vector<unique_color> unique_color_vec;
|
|
||||||
|
|
||||||
//typedef crnlib::hash_map<uint32, uint32, bit_hasher<uint32> > unique_color_hash_map;
|
|
||||||
typedef crnlib::hash_map<uint32, uint32> unique_color_hash_map;
|
|
||||||
unique_color_hash_map m_unique_color_hash_map;
|
|
||||||
|
|
||||||
unique_color_vec m_unique_colors; // excludes transparent colors!
|
|
||||||
unique_color_vec m_temp_unique_colors;
|
|
||||||
|
|
||||||
uint m_total_unique_color_weight;
|
|
||||||
|
|
||||||
bool m_has_transparent_pixels;
|
|
||||||
|
|
||||||
vec3F_array m_norm_unique_colors;
|
|
||||||
vec3F m_mean_norm_color;
|
|
||||||
|
|
||||||
vec3F_array m_norm_unique_colors_weighted;
|
|
||||||
vec3F m_mean_norm_color_weighted;
|
|
||||||
|
|
||||||
vec3F m_principle_axis;
|
|
||||||
|
|
||||||
bool m_all_pixels_grayscale;
|
|
||||||
|
|
||||||
crnlib::vector<uint16> m_unique_packed_colors;
|
|
||||||
crnlib::vector<uint8> m_trial_selectors;
|
|
||||||
|
|
||||||
crnlib::vector<vec3F> m_low_coords;
|
|
||||||
crnlib::vector<vec3F> m_high_coords;
|
|
||||||
|
|
||||||
enum { cMaxPrevResults = 4 };
|
|
||||||
dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
|
|
||||||
uint m_num_prev_results;
|
|
||||||
|
|
||||||
crnlib::vector<vec3I> m_lo_cells;
|
|
||||||
crnlib::vector<vec3I> m_hi_cells;
|
|
||||||
|
|
||||||
uint m_total_evals;
|
|
||||||
|
|
||||||
struct potential_solution
|
|
||||||
{
|
|
||||||
potential_solution() : m_coords(), m_error(cUINT64_MAX), m_alpha_block(false), m_valid(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
dxt1_solution_coordinates m_coords;
|
|
||||||
crnlib::vector<uint8> m_selectors;
|
|
||||||
uint64 m_error;
|
|
||||||
bool m_alpha_block;
|
|
||||||
bool m_valid;
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_coords.clear();
|
|
||||||
m_selectors.resize(0);
|
|
||||||
m_error = cUINT64_MAX;
|
|
||||||
m_alpha_block = false;
|
|
||||||
m_valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool are_selectors_all_equal() const
|
|
||||||
{
|
|
||||||
if (m_selectors.empty())
|
|
||||||
return false;
|
|
||||||
const uint s = m_selectors[0];
|
|
||||||
for (uint i = 1; i < m_selectors.size(); i++)
|
|
||||||
if (m_selectors[i] != s)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
potential_solution m_trial_solution;
|
|
||||||
potential_solution m_best_solution;
|
|
||||||
|
|
||||||
typedef crnlib::hash_map<uint, empty_type> solution_hash_map;
|
|
||||||
solution_hash_map m_solutions_tried;
|
|
||||||
|
|
||||||
bool refine_solution(int refinement_level = 0);
|
|
||||||
|
|
||||||
bool evaluate_solution(
|
|
||||||
const dxt1_solution_coordinates& coords,
|
|
||||||
bool early_out,
|
|
||||||
potential_solution* pBest_solution,
|
|
||||||
bool alternate_rounding = false);
|
|
||||||
|
|
||||||
bool evaluate_solution_uber(
|
|
||||||
potential_solution& solution,
|
|
||||||
const dxt1_solution_coordinates& coords,
|
|
||||||
bool early_out,
|
|
||||||
potential_solution* pBest_solution,
|
|
||||||
bool alternate_rounding = false);
|
|
||||||
|
|
||||||
bool evaluate_solution_fast(
|
|
||||||
potential_solution& solution,
|
|
||||||
const dxt1_solution_coordinates& coords,
|
|
||||||
bool early_out,
|
|
||||||
potential_solution* pBest_solution,
|
|
||||||
bool alternate_rounding = false);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
void find_unique_colors();
|
|
||||||
bool handle_all_transparent_block();
|
|
||||||
bool handle_solid_block();
|
|
||||||
bool handle_multicolor_block();
|
|
||||||
bool handle_grayscale_block();
|
|
||||||
void compute_pca(vec3F& axis, const vec3F_array& norm_colors, const vec3F& def);
|
|
||||||
void compute_vectors(const vec3F& perceptual_weights);
|
|
||||||
void return_solution(results& results, const potential_solution& solution);
|
|
||||||
void try_combinatorial_encoding();
|
|
||||||
void optimize_endpoint_comps();
|
|
||||||
bool optimize_endpoints(vec3F& low_color, vec3F& high_color);
|
|
||||||
bool try_alpha_as_black_optimization();
|
|
||||||
bool try_average_block_as_solid();
|
|
||||||
bool try_median4(const vec3F& low_color, const vec3F& high_color);
|
|
||||||
|
|
||||||
bool compute_internal(const params& p, results& r, solution_vec* pSolutions);
|
|
||||||
|
|
||||||
unique_color lerp_color(const color_quad_u8& a, const color_quad_u8& b, float f, int rounding = 1);
|
|
||||||
|
|
||||||
inline uint color_distance(bool perceptual, const color_quad_u8& e1, const color_quad_u8& e2, bool alpha);
|
|
||||||
|
|
||||||
static inline vec3F unpack_to_vec3F_raw(uint16 packed_color);
|
|
||||||
static inline vec3F unpack_to_vec3F(uint16 packed_color);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void swap(dxt1_endpoint_optimizer::solution& a, dxt1_endpoint_optimizer::solution& b)
|
|
||||||
{
|
|
||||||
std::swap(a.m_results, b.m_results);
|
|
||||||
a.m_selectors.swap(b.m_selectors);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,209 +0,0 @@
|
||||||
// File: crn_dxt5a.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_dxt5a.h"
|
|
||||||
#include "crn_ryg_dxt.hpp"
|
|
||||||
#include "crn_dxt_fast.h"
|
|
||||||
#include "crn_intersect.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
dxt5_endpoint_optimizer::dxt5_endpoint_optimizer() :
|
|
||||||
m_pParams(NULL),
|
|
||||||
m_pResults(NULL)
|
|
||||||
{
|
|
||||||
m_unique_values.reserve(16);
|
|
||||||
m_unique_value_weights.reserve(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dxt5_endpoint_optimizer::compute(const params& p, results& r)
|
|
||||||
{
|
|
||||||
m_pParams = &p;
|
|
||||||
m_pResults = &r;
|
|
||||||
|
|
||||||
if ((!p.m_num_pixels) || (!p.m_pPixels))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_unique_values.resize(0);
|
|
||||||
m_unique_value_weights.resize(0);
|
|
||||||
|
|
||||||
for (uint i = 0; i < 256; i++)
|
|
||||||
m_unique_value_map[i] = -1;
|
|
||||||
|
|
||||||
for (uint i = 0; i < p.m_num_pixels; i++)
|
|
||||||
{
|
|
||||||
uint alpha = p.m_pPixels[i][p.m_comp_index];
|
|
||||||
|
|
||||||
int index = m_unique_value_map[alpha];
|
|
||||||
|
|
||||||
if (index == -1)
|
|
||||||
{
|
|
||||||
index = m_unique_values.size();
|
|
||||||
|
|
||||||
m_unique_value_map[alpha] = index;
|
|
||||||
|
|
||||||
m_unique_values.push_back(static_cast<uint8>(alpha));
|
|
||||||
m_unique_value_weights.push_back(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_unique_value_weights[index]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_unique_values.size() == 1)
|
|
||||||
{
|
|
||||||
r.m_block_type = 0;
|
|
||||||
r.m_error = 0;
|
|
||||||
r.m_first_endpoint = m_unique_values[0];
|
|
||||||
r.m_second_endpoint = m_unique_values[0];
|
|
||||||
memset(r.m_pSelectors, 0, p.m_num_pixels);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_trial_selectors.resize(m_unique_values.size());
|
|
||||||
m_best_selectors.resize(m_unique_values.size());
|
|
||||||
|
|
||||||
r.m_error = cUINT64_MAX;
|
|
||||||
|
|
||||||
for (uint i = 0; i < m_unique_values.size() - 1; i++)
|
|
||||||
{
|
|
||||||
const uint low_endpoint = m_unique_values[i];
|
|
||||||
|
|
||||||
for (uint j = i + 1; j < m_unique_values.size(); j++)
|
|
||||||
{
|
|
||||||
const uint high_endpoint = m_unique_values[j];
|
|
||||||
|
|
||||||
evaluate_solution(low_endpoint, high_endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m_pParams->m_quality >= cCRNDXTQualityBetter) && (m_pResults->m_error))
|
|
||||||
{
|
|
||||||
m_flags.resize(256 * 256);
|
|
||||||
m_flags.clear_all_bits();
|
|
||||||
|
|
||||||
const int cProbeAmount = (m_pParams->m_quality == cCRNDXTQualityUber) ? 16 : 8;
|
|
||||||
|
|
||||||
for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
|
|
||||||
{
|
|
||||||
const int l = m_pResults->m_first_endpoint + l_delta;
|
|
||||||
if (l < 0)
|
|
||||||
continue;
|
|
||||||
else if (l > 255)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const uint bit_index = l * 256;
|
|
||||||
|
|
||||||
for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
|
|
||||||
{
|
|
||||||
const int h = m_pResults->m_second_endpoint + h_delta;
|
|
||||||
if (h < 0)
|
|
||||||
continue;
|
|
||||||
else if (h > 255)
|
|
||||||
break;
|
|
||||||
|
|
||||||
//if (m_flags.get_bit(bit_index + h))
|
|
||||||
// continue;
|
|
||||||
if ((m_flags.get_bit(bit_index + h)) || (m_flags.get_bit(h * 256 + l)))
|
|
||||||
continue;
|
|
||||||
m_flags.set_bit(bit_index + h);
|
|
||||||
|
|
||||||
evaluate_solution(static_cast<uint>(l), static_cast<uint>(h));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_pResults->m_first_endpoint == m_pResults->m_second_endpoint)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_best_selectors.size(); i++)
|
|
||||||
m_best_selectors[i] = 0;
|
|
||||||
}
|
|
||||||
else if (m_pResults->m_block_type)
|
|
||||||
{
|
|
||||||
//if (l > h)
|
|
||||||
// eight alpha
|
|
||||||
// else
|
|
||||||
// six alpha
|
|
||||||
|
|
||||||
if (m_pResults->m_first_endpoint > m_pResults->m_second_endpoint)
|
|
||||||
{
|
|
||||||
utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
|
|
||||||
for (uint i = 0; i < m_best_selectors.size(); i++)
|
|
||||||
m_best_selectors[i] = g_six_alpha_invert_table[m_best_selectors[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!(m_pResults->m_first_endpoint > m_pResults->m_second_endpoint))
|
|
||||||
{
|
|
||||||
utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
|
|
||||||
for (uint i = 0; i < m_best_selectors.size(); i++)
|
|
||||||
m_best_selectors[i] = g_eight_alpha_invert_table[m_best_selectors[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint i = 0; i < m_pParams->m_num_pixels; i++)
|
|
||||||
{
|
|
||||||
uint alpha = m_pParams->m_pPixels[i][m_pParams->m_comp_index];
|
|
||||||
|
|
||||||
int index = m_unique_value_map[alpha];
|
|
||||||
|
|
||||||
m_pResults->m_pSelectors[i] = m_best_selectors[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dxt5_endpoint_optimizer::evaluate_solution(uint low_endpoint, uint high_endpoint)
|
|
||||||
{
|
|
||||||
for (uint block_type = 0; block_type < (m_pParams->m_use_both_block_types ? 2U : 1U); block_type++)
|
|
||||||
{
|
|
||||||
uint selector_values[8];
|
|
||||||
|
|
||||||
if (!block_type)
|
|
||||||
dxt5_block::get_block_values8(selector_values, low_endpoint, high_endpoint);
|
|
||||||
else
|
|
||||||
dxt5_block::get_block_values6(selector_values, low_endpoint, high_endpoint);
|
|
||||||
|
|
||||||
uint64 trial_error = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < m_unique_values.size(); i++)
|
|
||||||
{
|
|
||||||
const uint val = m_unique_values[i];
|
|
||||||
const uint weight = m_unique_value_weights[i];
|
|
||||||
|
|
||||||
uint best_selector_error = UINT_MAX;
|
|
||||||
uint best_selector = 0;
|
|
||||||
|
|
||||||
for (uint j = 0; j < 8; j++)
|
|
||||||
{
|
|
||||||
int selector_error = val - selector_values[j];
|
|
||||||
selector_error = selector_error * selector_error * (int)weight;
|
|
||||||
|
|
||||||
if (static_cast<uint>(selector_error) < best_selector_error)
|
|
||||||
{
|
|
||||||
best_selector_error = selector_error;
|
|
||||||
best_selector = j;
|
|
||||||
if (!best_selector_error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_trial_selectors[i] = static_cast<uint8>(best_selector);
|
|
||||||
trial_error += best_selector_error;
|
|
||||||
|
|
||||||
if (trial_error > m_pResults->m_error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trial_error < m_pResults->m_error)
|
|
||||||
{
|
|
||||||
m_pResults->m_error = trial_error;
|
|
||||||
m_pResults->m_first_endpoint = static_cast<uint8>(low_endpoint);
|
|
||||||
m_pResults->m_second_endpoint = static_cast<uint8>(high_endpoint);
|
|
||||||
m_pResults->m_block_type = static_cast<uint8>(block_type);
|
|
||||||
m_best_selectors.swap(m_trial_selectors);
|
|
||||||
|
|
||||||
if (!trial_error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,66 +0,0 @@
|
||||||
// File: crn_dxt5a.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class dxt5_endpoint_optimizer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dxt5_endpoint_optimizer();
|
|
||||||
|
|
||||||
struct params
|
|
||||||
{
|
|
||||||
params() :
|
|
||||||
m_block_index(0),
|
|
||||||
m_pPixels(NULL),
|
|
||||||
m_num_pixels(0),
|
|
||||||
m_comp_index(3),
|
|
||||||
m_quality(cCRNDXTQualityUber),
|
|
||||||
m_use_both_block_types(true)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint m_block_index;
|
|
||||||
|
|
||||||
const color_quad_u8* m_pPixels;
|
|
||||||
uint m_num_pixels;
|
|
||||||
uint m_comp_index;
|
|
||||||
|
|
||||||
crn_dxt_quality m_quality;
|
|
||||||
|
|
||||||
bool m_use_both_block_types;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct results
|
|
||||||
{
|
|
||||||
uint8* m_pSelectors;
|
|
||||||
|
|
||||||
uint64 m_error;
|
|
||||||
|
|
||||||
uint8 m_first_endpoint;
|
|
||||||
uint8 m_second_endpoint;
|
|
||||||
|
|
||||||
uint8 m_block_type; // 1 if 6-alpha, otherwise 8-alpha
|
|
||||||
};
|
|
||||||
|
|
||||||
bool compute(const params& p, results& r);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const params* m_pParams;
|
|
||||||
results* m_pResults;
|
|
||||||
|
|
||||||
crnlib::vector<uint8> m_unique_values;
|
|
||||||
crnlib::vector<uint> m_unique_value_weights;
|
|
||||||
|
|
||||||
crnlib::vector<uint8> m_trial_selectors;
|
|
||||||
crnlib::vector<uint8> m_best_selectors;
|
|
||||||
int m_unique_value_map[256];
|
|
||||||
|
|
||||||
sparse_bit_array m_flags;
|
|
||||||
|
|
||||||
void evaluate_solution(uint low_endpoint, uint high_endpoint);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,362 +0,0 @@
|
||||||
// File: crn_dxt_endpoint_refiner.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_dxt_endpoint_refiner.h"
|
|
||||||
#include "crn_dxt1.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
dxt_endpoint_refiner::dxt_endpoint_refiner() :
|
|
||||||
m_pParams(NULL),
|
|
||||||
m_pResults(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dxt_endpoint_refiner::refine(const params& p, results& r)
|
|
||||||
{
|
|
||||||
if (!p.m_num_pixels)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_pParams = &p;
|
|
||||||
m_pResults = &r;
|
|
||||||
|
|
||||||
r.m_error = cUINT64_MAX;
|
|
||||||
r.m_low_color = 0;
|
|
||||||
r.m_high_color = 0;
|
|
||||||
|
|
||||||
double alpha2_sum = 0.0f;
|
|
||||||
double beta2_sum = 0.0f;
|
|
||||||
double alphabeta_sum = 0.0f;
|
|
||||||
|
|
||||||
vec<3, double> alphax_sum( 0.0f );
|
|
||||||
vec<3, double> betax_sum( 0.0f );
|
|
||||||
|
|
||||||
vec<3, double> first_color( 0.0f );
|
|
||||||
|
|
||||||
// This linear solver is from Squish.
|
|
||||||
for( uint i = 0; i < p.m_num_pixels; ++i )
|
|
||||||
{
|
|
||||||
uint8 c = p.m_pSelectors[i];
|
|
||||||
|
|
||||||
double k;
|
|
||||||
if (p.m_dxt1_selectors)
|
|
||||||
k = g_dxt1_to_linear[c] * 1.0f/3.0f;
|
|
||||||
else
|
|
||||||
k = g_dxt5_to_linear[c] * 1.0f/7.0f;
|
|
||||||
|
|
||||||
double alpha = 1.0f - k;
|
|
||||||
double beta = k;
|
|
||||||
|
|
||||||
vec<3, double> x;
|
|
||||||
|
|
||||||
if (p.m_dxt1_selectors)
|
|
||||||
x.set( p.m_pPixels[i][0] * 1.0f/255.0f, p.m_pPixels[i][1] * 1.0f/255.0f, p.m_pPixels[i][2] * 1.0f/255.0f );
|
|
||||||
else
|
|
||||||
x.set( p.m_pPixels[i][p.m_alpha_comp_index]/255.0f );
|
|
||||||
|
|
||||||
if (!i)
|
|
||||||
first_color = x;
|
|
||||||
|
|
||||||
alpha2_sum += alpha*alpha;
|
|
||||||
beta2_sum += beta*beta;
|
|
||||||
alphabeta_sum += alpha*beta;
|
|
||||||
alphax_sum += alpha*x;
|
|
||||||
betax_sum += beta*x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// zero where non-determinate
|
|
||||||
vec<3, double> a, b;
|
|
||||||
if( beta2_sum == 0.0f )
|
|
||||||
{
|
|
||||||
a = alphax_sum / alpha2_sum;
|
|
||||||
b.clear();
|
|
||||||
}
|
|
||||||
else if( alpha2_sum == 0.0f )
|
|
||||||
{
|
|
||||||
a.clear();
|
|
||||||
b = betax_sum / beta2_sum;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double factor = alpha2_sum*beta2_sum - alphabeta_sum*alphabeta_sum;
|
|
||||||
if (factor != 0.0f)
|
|
||||||
{
|
|
||||||
a = ( alphax_sum*beta2_sum - betax_sum*alphabeta_sum ) / factor;
|
|
||||||
b = ( betax_sum*alpha2_sum - alphax_sum*alphabeta_sum ) / factor;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = first_color;
|
|
||||||
b = first_color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3F l(0.0f), h(0.0f);
|
|
||||||
l = a;
|
|
||||||
h = b;
|
|
||||||
|
|
||||||
l.clamp(0.0f, 1.0f);
|
|
||||||
h.clamp(0.0f, 1.0f);
|
|
||||||
|
|
||||||
if (p.m_dxt1_selectors)
|
|
||||||
optimize_dxt1(l, h);
|
|
||||||
else
|
|
||||||
optimize_dxt5(l, h);
|
|
||||||
|
|
||||||
//if (r.m_low_color < r.m_high_color)
|
|
||||||
// utils::swap(r.m_low_color, r.m_high_color);
|
|
||||||
|
|
||||||
return r.m_error < p.m_error_to_beat;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dxt_endpoint_refiner::optimize_dxt5(vec3F low_color, vec3F high_color)
|
|
||||||
{
|
|
||||||
float nl = low_color[0];
|
|
||||||
float nh = high_color[0];
|
|
||||||
|
|
||||||
#if CRNLIB_DXT_ALT_ROUNDING
|
|
||||||
nl = math::clamp(nl, 0.0f, .999f);
|
|
||||||
nh = math::clamp(nh, 0.0f, .999f);
|
|
||||||
uint il = (int)floor(nl * 256.0f);
|
|
||||||
uint ih = (int)floor(nh * 256.0f);
|
|
||||||
#else
|
|
||||||
uint il = (int)floor(.5f + math::clamp(nl, 0.0f, 1.0f) * 255.0f);
|
|
||||||
uint ih = (int)floor(.5f + math::clamp(nh, 0.0f, 1.0f) * 255.0f);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
crnlib::vector<uint> trial_solutions;
|
|
||||||
trial_solutions.reserve(256);
|
|
||||||
trial_solutions.push_back(il | (ih << 8));
|
|
||||||
|
|
||||||
sparse_bit_array flags;
|
|
||||||
flags.resize(256 * 256);
|
|
||||||
|
|
||||||
flags.set_bit((il * 256) + ih);
|
|
||||||
|
|
||||||
const int cProbeAmount = 11;
|
|
||||||
|
|
||||||
for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
|
|
||||||
{
|
|
||||||
const int l = il + l_delta;
|
|
||||||
if (l < 0)
|
|
||||||
continue;
|
|
||||||
else if (l > 255)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const uint bit_index = l * 256;
|
|
||||||
|
|
||||||
for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
|
|
||||||
{
|
|
||||||
const int h = ih + h_delta;
|
|
||||||
if (h < 0)
|
|
||||||
continue;
|
|
||||||
else if (h > 255)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((flags.get_bit(bit_index + h)) || (flags.get_bit(h * 256 + l)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
flags.set_bit(bit_index + h);
|
|
||||||
|
|
||||||
trial_solutions.push_back(l | (h << 8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint trial = 0; trial < trial_solutions.size(); trial++)
|
|
||||||
{
|
|
||||||
uint l = trial_solutions[trial] & 0xFF;
|
|
||||||
uint h = trial_solutions[trial] >> 8;
|
|
||||||
|
|
||||||
if (l == h)
|
|
||||||
{
|
|
||||||
if (h)
|
|
||||||
h--;
|
|
||||||
else
|
|
||||||
l++;
|
|
||||||
}
|
|
||||||
else if (l < h)
|
|
||||||
{
|
|
||||||
utils::swap(l, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(l > h);
|
|
||||||
|
|
||||||
uint values[cDXT5SelectorValues];
|
|
||||||
dxt5_block::get_block_values8(values, l, h);
|
|
||||||
|
|
||||||
uint total_error = 0;
|
|
||||||
|
|
||||||
for (uint j = 0; j < m_pParams->m_num_pixels; j++)
|
|
||||||
{
|
|
||||||
int p = m_pParams->m_pPixels[j][m_pParams->m_alpha_comp_index];
|
|
||||||
int c = values[m_pParams->m_pSelectors[j]];
|
|
||||||
|
|
||||||
int error = p - c;
|
|
||||||
error *= error;
|
|
||||||
|
|
||||||
total_error += error;
|
|
||||||
|
|
||||||
if (total_error > m_pResults->m_error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_error < m_pResults->m_error)
|
|
||||||
{
|
|
||||||
m_pResults->m_error = total_error;
|
|
||||||
m_pResults->m_low_color = static_cast<uint16>(l);
|
|
||||||
m_pResults->m_high_color = static_cast<uint16>(h);
|
|
||||||
|
|
||||||
if (m_pResults->m_error == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dxt_endpoint_refiner::optimize_dxt1(vec3F low_color, vec3F high_color)
|
|
||||||
{
|
|
||||||
uint selector_hist[4];
|
|
||||||
utils::zero_object(selector_hist);
|
|
||||||
for (uint i = 0; i < m_pParams->m_num_pixels; i++)
|
|
||||||
selector_hist[m_pParams->m_pSelectors[i]]++;
|
|
||||||
|
|
||||||
dxt1_solution_coordinates c(low_color, high_color);
|
|
||||||
|
|
||||||
for (uint pass = 0; pass < 8; pass++)
|
|
||||||
{
|
|
||||||
const uint64 initial_error = m_pResults->m_error;
|
|
||||||
|
|
||||||
dxt1_solution_coordinates_vec coords_to_try;
|
|
||||||
|
|
||||||
coords_to_try.resize(0);
|
|
||||||
|
|
||||||
color_quad_u8 lc(dxt1_block::unpack_color(c.m_low_color, false));
|
|
||||||
color_quad_u8 hc(dxt1_block::unpack_color(c.m_high_color, false));
|
|
||||||
|
|
||||||
for (int i = 0; i < 27; i++)
|
|
||||||
{
|
|
||||||
if (13 == i) continue;
|
|
||||||
|
|
||||||
const int ir = (i % 3) - 1;
|
|
||||||
const int ig = ((i / 3) % 3) - 1;
|
|
||||||
const int ib = ((i / 9) % 3) - 1;
|
|
||||||
|
|
||||||
int r = lc.r + ir;
|
|
||||||
int g = lc.g + ig;
|
|
||||||
int b = lc.b + ib;
|
|
||||||
if ((r < 0) || (r > 31)|| (g < 0) || (g > 63) || (b < 0) || (b > 31)) continue;
|
|
||||||
|
|
||||||
coords_to_try.push_back(
|
|
||||||
dxt1_solution_coordinates(dxt1_block::pack_color(r, g, b, false), c.m_high_color)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 27; i++)
|
|
||||||
{
|
|
||||||
if (13 == i) continue;
|
|
||||||
|
|
||||||
const int ir = (i % 3) - 1;
|
|
||||||
const int ig = ((i / 3) % 3) - 1;
|
|
||||||
const int ib = ((i / 9) % 3) - 1;
|
|
||||||
|
|
||||||
int r = hc.r + ir;
|
|
||||||
int g = hc.g + ig;
|
|
||||||
int b = hc.b + ib;
|
|
||||||
if ((r < 0) || (r > 31)|| (g < 0) || (g > 63) || (b < 0) || (b > 31)) continue;
|
|
||||||
|
|
||||||
coords_to_try.push_back(dxt1_solution_coordinates(c.m_low_color, dxt1_block::pack_color(r, g, b, false)));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(coords_to_try.begin(), coords_to_try.end());
|
|
||||||
|
|
||||||
dxt1_solution_coordinates_vec::const_iterator p_last = std::unique(coords_to_try.begin(), coords_to_try.end());
|
|
||||||
uint num_coords_to_try = (uint)(p_last - coords_to_try.begin());
|
|
||||||
|
|
||||||
for (uint i = 0; i < num_coords_to_try; i++)
|
|
||||||
{
|
|
||||||
color_quad_u8 block_colors[4];
|
|
||||||
uint16 l = coords_to_try[i].m_low_color;
|
|
||||||
uint16 h = coords_to_try[i].m_high_color;
|
|
||||||
if (l < h)
|
|
||||||
utils::swap(l, h);
|
|
||||||
else if (l == h)
|
|
||||||
{
|
|
||||||
color_quad_u8 lc(dxt1_block::unpack_color(l, false));
|
|
||||||
color_quad_u8 hc(dxt1_block::unpack_color(h, false));
|
|
||||||
|
|
||||||
bool retry = false;
|
|
||||||
if ((selector_hist[0] + selector_hist[2]) > (selector_hist[1] + selector_hist[3]))
|
|
||||||
{
|
|
||||||
// l affects the output more than h, so muck with h
|
|
||||||
if (hc[2] != 0)
|
|
||||||
hc[2]--;
|
|
||||||
else if (hc[0] != 0)
|
|
||||||
hc[0]--;
|
|
||||||
else if (hc[1] != 0)
|
|
||||||
hc[1]--;
|
|
||||||
else
|
|
||||||
retry = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// h affects the output more than l, so muck with l
|
|
||||||
if (lc[2] != 31)
|
|
||||||
lc[2]++;
|
|
||||||
else if (lc[0] != 31)
|
|
||||||
lc[0]++;
|
|
||||||
else if (lc[1] != 63)
|
|
||||||
lc[1]++;
|
|
||||||
else
|
|
||||||
retry = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retry)
|
|
||||||
{
|
|
||||||
if (l == 0)
|
|
||||||
l++;
|
|
||||||
else
|
|
||||||
h--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
l = dxt1_block::pack_color(lc, false);
|
|
||||||
h = dxt1_block::pack_color(hc, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(l > h);
|
|
||||||
}
|
|
||||||
|
|
||||||
dxt1_block::get_block_colors4(block_colors, l, h);
|
|
||||||
|
|
||||||
uint total_error = 0;
|
|
||||||
|
|
||||||
for (uint j = 0; j < m_pParams->m_num_pixels; j++)
|
|
||||||
{
|
|
||||||
const color_quad_u8& c = block_colors[m_pParams->m_pSelectors[j]];
|
|
||||||
total_error += color::color_distance(m_pParams->m_perceptual, c, m_pParams->m_pPixels[j], false);
|
|
||||||
|
|
||||||
if (total_error > m_pResults->m_error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_error < m_pResults->m_error)
|
|
||||||
{
|
|
||||||
m_pResults->m_error = total_error;
|
|
||||||
m_pResults->m_low_color = l;
|
|
||||||
m_pResults->m_high_color = h;
|
|
||||||
CRNLIB_ASSERT(l > h);
|
|
||||||
if (m_pResults->m_error == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_pResults->m_error == initial_error)
|
|
||||||
break;
|
|
||||||
|
|
||||||
c.m_low_color = m_pResults->m_low_color;
|
|
||||||
c.m_high_color = m_pResults->m_high_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
// File: crn_dxt_endpoint_refiner.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
// TODO: Experimental/Not fully implemented
|
|
||||||
class dxt_endpoint_refiner
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dxt_endpoint_refiner();
|
|
||||||
|
|
||||||
struct params
|
|
||||||
{
|
|
||||||
params() :
|
|
||||||
m_block_index(0),
|
|
||||||
m_pPixels(NULL),
|
|
||||||
m_num_pixels(0),
|
|
||||||
m_pSelectors(NULL),
|
|
||||||
m_alpha_comp_index(0),
|
|
||||||
m_error_to_beat(cUINT64_MAX),
|
|
||||||
m_dxt1_selectors(true),
|
|
||||||
m_perceptual(true),
|
|
||||||
m_highest_quality(true)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint m_block_index;
|
|
||||||
|
|
||||||
const color_quad_u8* m_pPixels;
|
|
||||||
uint m_num_pixels;
|
|
||||||
|
|
||||||
const uint8* m_pSelectors;
|
|
||||||
|
|
||||||
uint m_alpha_comp_index;
|
|
||||||
|
|
||||||
uint64 m_error_to_beat;
|
|
||||||
|
|
||||||
bool m_dxt1_selectors;
|
|
||||||
bool m_perceptual;
|
|
||||||
bool m_highest_quality;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct results
|
|
||||||
{
|
|
||||||
uint16 m_low_color;
|
|
||||||
uint16 m_high_color;
|
|
||||||
uint64 m_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool refine(const params& p, results& r);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const params* m_pParams;
|
|
||||||
results* m_pResults;
|
|
||||||
|
|
||||||
void optimize_dxt1(vec3F low_color, vec3F high_color);
|
|
||||||
void optimize_dxt5(vec3F low_color, vec3F high_color);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,916 +0,0 @@
|
||||||
// File: crn_dxt_fast.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
// Parts of this module are derived from RYG's excellent public domain DXTx compressor.
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_dxt_fast.h"
|
|
||||||
#include "crn_ryg_dxt.hpp"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace dxt_fast
|
|
||||||
{
|
|
||||||
static inline int mul_8bit(int a, int b)
|
|
||||||
{
|
|
||||||
int t = a * b + 128;
|
|
||||||
return (t + (t >> 8)) >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline color_quad_u8& unpack_color(color_quad_u8& c, uint v)
|
|
||||||
{
|
|
||||||
uint rv = (v & 0xf800) >> 11;
|
|
||||||
uint gv = (v & 0x07e0) >> 5;
|
|
||||||
uint bv = (v & 0x001f) >> 0;
|
|
||||||
|
|
||||||
c.r = ryg_dxt::Expand5[rv];
|
|
||||||
c.g = ryg_dxt::Expand6[gv];
|
|
||||||
c.b = ryg_dxt::Expand5[bv];
|
|
||||||
c.a = 0;
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint pack_color(const color_quad_u8& c)
|
|
||||||
{
|
|
||||||
return (mul_8bit(c.r, 31) << 11) + (mul_8bit(c.g, 63) << 5) + mul_8bit(c.b, 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void lerp_color(color_quad_u8& result, const color_quad_u8& p1, const color_quad_u8& p2, uint f)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(f <= 255);
|
|
||||||
|
|
||||||
result.r = static_cast<uint8>(p1.r + mul_8bit(p2.r - p1.r, f));
|
|
||||||
result.g = static_cast<uint8>(p1.g + mul_8bit(p2.g - p1.g, f));
|
|
||||||
result.b = static_cast<uint8>(p1.b + mul_8bit(p2.b - p1.b, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void eval_colors(color_quad_u8* pColors, uint c0, uint c1)
|
|
||||||
{
|
|
||||||
unpack_color(pColors[0], c0);
|
|
||||||
unpack_color(pColors[1], c1);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
lerp_color(pColors[2], pColors[0], pColors[1], 0x55);
|
|
||||||
lerp_color(pColors[3], pColors[0], pColors[1], 0xAA);
|
|
||||||
#else
|
|
||||||
pColors[2].r = (pColors[0].r*2+pColors[1].r)/3;
|
|
||||||
pColors[2].g = (pColors[0].g*2+pColors[1].g)/3;
|
|
||||||
pColors[2].b = (pColors[0].b*2+pColors[1].b)/3;
|
|
||||||
|
|
||||||
pColors[3].r = (pColors[1].r*2+pColors[0].r)/3;
|
|
||||||
pColors[3].g = (pColors[1].g*2+pColors[0].g)/3;
|
|
||||||
pColors[3].b = (pColors[1].b*2+pColors[0].b)/3;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// false if all selectors equal
|
|
||||||
static bool match_block_colors(uint n, const color_quad_u8* pBlock, const color_quad_u8* pColors, uint8* pSelectors)
|
|
||||||
{
|
|
||||||
int dirr = pColors[0].r - pColors[1].r;
|
|
||||||
int dirg = pColors[0].g - pColors[1].g;
|
|
||||||
int dirb = pColors[0].b - pColors[1].b;
|
|
||||||
|
|
||||||
int stops[4];
|
|
||||||
for(int i = 0; i < 4; i++)
|
|
||||||
stops[i] = pColors[i].r*dirr + pColors[i].g*dirg + pColors[i].b*dirb;
|
|
||||||
|
|
||||||
// 0 2 3 1
|
|
||||||
int c0Point = stops[1] + stops[3];
|
|
||||||
int halfPoint = stops[3] + stops[2];
|
|
||||||
int c3Point = stops[2] + stops[0];
|
|
||||||
|
|
||||||
//dirr *= 2;
|
|
||||||
//dirg *= 2;
|
|
||||||
//dirb *= 2;
|
|
||||||
c0Point >>= 1;
|
|
||||||
halfPoint >>= 1;
|
|
||||||
c3Point >>= 1;
|
|
||||||
|
|
||||||
bool status = false;
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
int dot = pBlock[i].r*dirr + pBlock[i].g*dirg + pBlock[i].b*dirb;
|
|
||||||
|
|
||||||
uint8 s;
|
|
||||||
if (dot < halfPoint)
|
|
||||||
s = (dot < c0Point) ? 1 : 3;
|
|
||||||
else
|
|
||||||
s = (dot < c3Point) ? 2 : 0;
|
|
||||||
|
|
||||||
pSelectors[i] = s;
|
|
||||||
|
|
||||||
if (s != pSelectors[0])
|
|
||||||
status = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool optimize_block_colors(uint n, const color_quad_u8* block, uint& max16, uint& min16, uint ave_color[3], float axis[3])
|
|
||||||
{
|
|
||||||
int min[3], max[3];
|
|
||||||
|
|
||||||
for(uint ch = 0; ch < 3; ch++)
|
|
||||||
{
|
|
||||||
const uint8 *bp = ((const uint8 *) block) + ch;
|
|
||||||
int minv, maxv;
|
|
||||||
|
|
||||||
int64 muv = bp[0];
|
|
||||||
minv = maxv = bp[0];
|
|
||||||
|
|
||||||
const uint l = n << 2;
|
|
||||||
for (uint i = 4; i < l; i += 4)
|
|
||||||
{
|
|
||||||
muv += bp[i];
|
|
||||||
minv = math::minimum<int>(minv, bp[i]);
|
|
||||||
maxv = math::maximum<int>(maxv, bp[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ave_color[ch] = static_cast<int>((muv + (n / 2)) / n);
|
|
||||||
min[ch] = minv;
|
|
||||||
max[ch] = maxv;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((min[0] == max[0]) && (min[1] == max[1]) && (min[2] == max[2]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// determine covariance matrix
|
|
||||||
double cov[6];
|
|
||||||
for(int i=0;i<6;i++)
|
|
||||||
cov[i] = 0;
|
|
||||||
|
|
||||||
for(uint i=0;i<n;i++)
|
|
||||||
{
|
|
||||||
double r = (int)block[i].r - (int)ave_color[0];
|
|
||||||
double g = (int)block[i].g - (int)ave_color[1];
|
|
||||||
double b = (int)block[i].b - (int)ave_color[2];
|
|
||||||
|
|
||||||
cov[0] += r*r;
|
|
||||||
cov[1] += r*g;
|
|
||||||
cov[2] += r*b;
|
|
||||||
cov[3] += g*g;
|
|
||||||
cov[4] += g*b;
|
|
||||||
cov[5] += b*b;
|
|
||||||
}
|
|
||||||
|
|
||||||
double covf[6],vfr,vfg,vfb;
|
|
||||||
for(int i=0;i<6;i++)
|
|
||||||
covf[i] = cov[i] * (1.0f/255.0f);
|
|
||||||
|
|
||||||
vfr = max[0] - min[0];
|
|
||||||
vfg = max[1] - min[1];
|
|
||||||
vfb = max[2] - min[2];
|
|
||||||
|
|
||||||
static const uint nIterPower = 4;
|
|
||||||
for(uint iter = 0; iter < nIterPower; iter++)
|
|
||||||
{
|
|
||||||
double r = vfr*covf[0] + vfg*covf[1] + vfb*covf[2];
|
|
||||||
double g = vfr*covf[1] + vfg*covf[3] + vfb*covf[4];
|
|
||||||
double b = vfr*covf[2] + vfg*covf[4] + vfb*covf[5];
|
|
||||||
|
|
||||||
vfr = r;
|
|
||||||
vfg = g;
|
|
||||||
vfb = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
double magn = math::maximum(math::maximum(fabs(vfr),fabs(vfg)),fabs(vfb));
|
|
||||||
int v_r, v_g, v_b;
|
|
||||||
|
|
||||||
if (magn < 4.0f) // too small, default to luminance
|
|
||||||
{
|
|
||||||
v_r = 148;
|
|
||||||
v_g = 300;
|
|
||||||
v_b = 58;
|
|
||||||
|
|
||||||
axis[0] = (float)v_r;
|
|
||||||
axis[1] = (float)v_g;
|
|
||||||
axis[2] = (float)v_b;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
magn = 512.0f / magn;
|
|
||||||
vfr *= magn;
|
|
||||||
vfg *= magn;
|
|
||||||
vfb *= magn;
|
|
||||||
v_r = static_cast<int>(vfr);
|
|
||||||
v_g = static_cast<int>(vfg);
|
|
||||||
v_b = static_cast<int>(vfb);
|
|
||||||
|
|
||||||
axis[0] = (float)vfr;
|
|
||||||
axis[1] = (float)vfg;
|
|
||||||
axis[2] = (float)vfb;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mind = block[0].r * v_r + block[0].g * v_g + block[0].b * v_b;
|
|
||||||
int maxd = mind;
|
|
||||||
color_quad_u8 minp(block[0]);
|
|
||||||
color_quad_u8 maxp(block[0]);
|
|
||||||
|
|
||||||
for(uint i = 1; i < n; i++)
|
|
||||||
{
|
|
||||||
int dot = block[i].r * v_r + block[i].g * v_g + block[i].b * v_b;
|
|
||||||
|
|
||||||
if (dot < mind)
|
|
||||||
{
|
|
||||||
mind = dot;
|
|
||||||
minp = block[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dot > maxd)
|
|
||||||
{
|
|
||||||
maxd = dot;
|
|
||||||
maxp = block[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
max16 = pack_color(maxp);
|
|
||||||
min16 = pack_color(minp);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The refinement function. (Clever code, part 2)
|
|
||||||
// Tries to optimize colors to suit block contents better.
|
|
||||||
// (By solving a least squares system via normal equations+Cramer's rule)
|
|
||||||
static bool refine_block(uint n, const color_quad_u8 *block, uint &max16, uint &min16, const uint8* pSelectors)
|
|
||||||
{
|
|
||||||
static const int w1Tab[4] = { 3,0,2,1 };
|
|
||||||
|
|
||||||
static const int prods_0[4] = { 0x00,0x00,0x02,0x02 };
|
|
||||||
static const int prods_1[4] = { 0x00,0x09,0x01,0x04 };
|
|
||||||
static const int prods_2[4] = { 0x09,0x00,0x04,0x01 };
|
|
||||||
|
|
||||||
double akku_0 = 0;
|
|
||||||
double akku_1 = 0;
|
|
||||||
double akku_2 = 0;
|
|
||||||
double At1_r, At1_g, At1_b;
|
|
||||||
double At2_r, At2_g, At2_b;
|
|
||||||
|
|
||||||
At1_r = At1_g = At1_b = 0;
|
|
||||||
At2_r = At2_g = At2_b = 0;
|
|
||||||
for(uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
double r = block[i].r;
|
|
||||||
double g = block[i].g;
|
|
||||||
double b = block[i].b;
|
|
||||||
int step = pSelectors[i];
|
|
||||||
|
|
||||||
int w1 = w1Tab[step];
|
|
||||||
|
|
||||||
akku_0 += prods_0[step];
|
|
||||||
akku_1 += prods_1[step];
|
|
||||||
akku_2 += prods_2[step];
|
|
||||||
At1_r += w1*r;
|
|
||||||
At1_g += w1*g;
|
|
||||||
At1_b += w1*b;
|
|
||||||
At2_r += r;
|
|
||||||
At2_g += g;
|
|
||||||
At2_b += b;
|
|
||||||
}
|
|
||||||
|
|
||||||
At2_r = 3*At2_r - At1_r;
|
|
||||||
At2_g = 3*At2_g - At1_g;
|
|
||||||
At2_b = 3*At2_b - At1_b;
|
|
||||||
|
|
||||||
double xx = akku_2;
|
|
||||||
double yy = akku_1;
|
|
||||||
double xy = akku_0;
|
|
||||||
|
|
||||||
double t = xx * yy - xy * xy;
|
|
||||||
if (!yy || !xx || (fabs(t) < .0000125f))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
double frb = (3.0f * 31.0f / 255.0f) / t;
|
|
||||||
double fg = frb * (63.0f / 31.0f);
|
|
||||||
|
|
||||||
uint oldMin = min16;
|
|
||||||
uint oldMax = max16;
|
|
||||||
|
|
||||||
// solve.
|
|
||||||
max16 = math::clamp<int>(static_cast<int>((At1_r*yy - At2_r*xy)*frb+0.5f),0,31) << 11;
|
|
||||||
max16 |= math::clamp<int>(static_cast<int>((At1_g*yy - At2_g*xy)*fg +0.5f),0,63) << 5;
|
|
||||||
max16 |= math::clamp<int>(static_cast<int>((At1_b*yy - At2_b*xy)*frb+0.5f),0,31) << 0;
|
|
||||||
|
|
||||||
min16 = math::clamp<int>(static_cast<int>((At2_r*xx - At1_r*xy)*frb+0.5f),0,31) << 11;
|
|
||||||
min16 |= math::clamp<int>(static_cast<int>((At2_g*xx - At1_g*xy)*fg +0.5f),0,63) << 5;
|
|
||||||
min16 |= math::clamp<int>(static_cast<int>((At2_b*xx - At1_b*xy)*frb+0.5f),0,31) << 0;
|
|
||||||
|
|
||||||
return (oldMin != min16) || (oldMax != max16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// false if all selectors equal
|
|
||||||
static bool determine_selectors(uint n, const color_quad_u8* block, uint min16, uint max16, uint8* pSelectors)
|
|
||||||
{
|
|
||||||
color_quad_u8 color[4];
|
|
||||||
|
|
||||||
if (max16 != min16)
|
|
||||||
{
|
|
||||||
eval_colors(color, min16, max16);
|
|
||||||
|
|
||||||
return match_block_colors(n, block, color, pSelectors);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(pSelectors, 0, n);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64 determine_error(uint n, const color_quad_u8* block, uint min16, uint max16, uint64 early_out_error)
|
|
||||||
{
|
|
||||||
color_quad_u8 color[4];
|
|
||||||
|
|
||||||
eval_colors(color, min16, max16);
|
|
||||||
|
|
||||||
int dirr = color[0].r - color[1].r;
|
|
||||||
int dirg = color[0].g - color[1].g;
|
|
||||||
int dirb = color[0].b - color[1].b;
|
|
||||||
|
|
||||||
int stops[4];
|
|
||||||
for(int i = 0; i < 4; i++)
|
|
||||||
stops[i] = color[i].r*dirr + color[i].g*dirg + color[i].b*dirb;
|
|
||||||
|
|
||||||
// 0 2 3 1
|
|
||||||
int c0Point = stops[1] + stops[3];
|
|
||||||
int halfPoint = stops[3] + stops[2];
|
|
||||||
int c3Point = stops[2] + stops[0];
|
|
||||||
|
|
||||||
c0Point >>= 1;
|
|
||||||
halfPoint >>= 1;
|
|
||||||
c3Point >>= 1;
|
|
||||||
|
|
||||||
uint64 total_error = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
const color_quad_u8& a = block[i];
|
|
||||||
|
|
||||||
uint s = 0;
|
|
||||||
if (min16 != max16)
|
|
||||||
{
|
|
||||||
int dot = a.r*dirr + a.g*dirg + a.b*dirb;
|
|
||||||
|
|
||||||
if (dot < halfPoint)
|
|
||||||
s = (dot < c0Point) ? 1 : 3;
|
|
||||||
else
|
|
||||||
s = (dot < c3Point) ? 2 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const color_quad_u8& b = color[s];
|
|
||||||
|
|
||||||
int e = a[0] - b[0];
|
|
||||||
total_error += e * e;
|
|
||||||
|
|
||||||
e = a[1] - b[1];
|
|
||||||
total_error += e * e;
|
|
||||||
|
|
||||||
e = a[2] - b[2];
|
|
||||||
total_error += e * e;
|
|
||||||
|
|
||||||
if (total_error >= early_out_error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return total_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool refine_endpoints(uint n, const color_quad_u8* pBlock, uint& low16, uint& high16, uint8* pSelectors)
|
|
||||||
{
|
|
||||||
bool optimized = false;
|
|
||||||
|
|
||||||
const int limits[3] = { 31, 63, 31 };
|
|
||||||
|
|
||||||
for (uint trial = 0; trial < 2; trial++)
|
|
||||||
{
|
|
||||||
color_quad_u8 color[4];
|
|
||||||
eval_colors(color, low16, high16);
|
|
||||||
|
|
||||||
uint64 total_error[3] = { 0, 0, 0 };
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
const color_quad_u8& a = pBlock[i];
|
|
||||||
|
|
||||||
const uint s = pSelectors[i];
|
|
||||||
const color_quad_u8& b = color[s];
|
|
||||||
|
|
||||||
int e = a[0] - b[0];
|
|
||||||
total_error[0] += e * e;
|
|
||||||
|
|
||||||
e = a[1] - b[1];
|
|
||||||
total_error[1] += e * e;
|
|
||||||
|
|
||||||
e = a[2] - b[2];
|
|
||||||
total_error[2] += e * e;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8 endpoints[2];
|
|
||||||
endpoints[0] = dxt1_block::unpack_color((uint16)low16, false);
|
|
||||||
endpoints[1] = dxt1_block::unpack_color((uint16)high16, false);
|
|
||||||
|
|
||||||
color_quad_u8 expanded_endpoints[2];
|
|
||||||
expanded_endpoints[0] = dxt1_block::unpack_color((uint16)low16, true);
|
|
||||||
expanded_endpoints[1] = dxt1_block::unpack_color((uint16)high16, true);
|
|
||||||
|
|
||||||
bool trial_optimized = false;
|
|
||||||
|
|
||||||
for (uint axis = 0; axis < 3; axis++)
|
|
||||||
{
|
|
||||||
if (!total_error[axis])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const sU8* const pExpand = (axis == 1) ? ryg_dxt::Expand6 : ryg_dxt::Expand5;
|
|
||||||
|
|
||||||
for (uint e = 0; e < 2; e++)
|
|
||||||
{
|
|
||||||
uint v[4];
|
|
||||||
v[e^1] = expanded_endpoints[e^1][axis];
|
|
||||||
|
|
||||||
for (int t = -1; t <= 1; t += 2)
|
|
||||||
{
|
|
||||||
int a = endpoints[e][axis] + t;
|
|
||||||
if ((a < 0) || (a > limits[axis]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
v[e] = pExpand[a];
|
|
||||||
|
|
||||||
//int delta = v[1] - v[0];
|
|
||||||
//v[2] = v[0] + mul_8bit(delta, 0x55);
|
|
||||||
//v[3] = v[0] + mul_8bit(delta, 0xAA);
|
|
||||||
|
|
||||||
v[2] = (v[0] * 2 + v[1]) / 3;
|
|
||||||
v[3] = (v[0] + v[1] * 2) / 3;
|
|
||||||
|
|
||||||
uint64 axis_error = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
const color_quad_u8& p = pBlock[i];
|
|
||||||
|
|
||||||
int e = v[pSelectors[i]] - p[axis];
|
|
||||||
|
|
||||||
axis_error += e * e;
|
|
||||||
|
|
||||||
if (axis_error >= total_error[axis])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axis_error < total_error[axis])
|
|
||||||
{
|
|
||||||
//total_error[axis] = axis_error;
|
|
||||||
|
|
||||||
endpoints[e][axis] = (uint8)a;
|
|
||||||
expanded_endpoints[e][axis] = (uint8)v[e];
|
|
||||||
|
|
||||||
if (e)
|
|
||||||
high16 = dxt1_block::pack_color(endpoints[1], false);
|
|
||||||
else
|
|
||||||
low16 = dxt1_block::pack_color(endpoints[0], false);
|
|
||||||
|
|
||||||
determine_selectors(n, pBlock, low16, high16, pSelectors);
|
|
||||||
|
|
||||||
eval_colors(color, low16, high16);
|
|
||||||
|
|
||||||
utils::zero_object(total_error);
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
const color_quad_u8& a = pBlock[i];
|
|
||||||
|
|
||||||
const uint s = pSelectors[i];
|
|
||||||
const color_quad_u8& b = color[s];
|
|
||||||
|
|
||||||
int e = a[0] - b[0];
|
|
||||||
total_error[0] += e * e;
|
|
||||||
|
|
||||||
e = a[1] - b[1];
|
|
||||||
total_error[1] += e * e;
|
|
||||||
|
|
||||||
e = a[2] - b[2];
|
|
||||||
total_error[2] += e * e;
|
|
||||||
}
|
|
||||||
|
|
||||||
trial_optimized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // t
|
|
||||||
|
|
||||||
} // e
|
|
||||||
} // axis
|
|
||||||
|
|
||||||
if (!trial_optimized)
|
|
||||||
break;
|
|
||||||
|
|
||||||
optimized = true;
|
|
||||||
|
|
||||||
} // for ( ; ; )
|
|
||||||
|
|
||||||
return optimized;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refine_endpoints2(uint n, const color_quad_u8* pBlock, uint& low16, uint& high16, uint8* pSelectors, float axis[3])
|
|
||||||
{
|
|
||||||
uint64 orig_error = determine_error(n, pBlock, low16, high16, cUINT64_MAX);
|
|
||||||
if (!orig_error)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float l = 1.0f / sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
|
|
||||||
vec3F principle_axis(axis[0] * l, axis[1] * l, axis[2] * l);
|
|
||||||
|
|
||||||
const float dist_per_trial = 0.027063293f;
|
|
||||||
|
|
||||||
const uint cMaxProbeRange = 8;
|
|
||||||
uint probe_low[cMaxProbeRange * 2 + 1];
|
|
||||||
uint probe_high[cMaxProbeRange * 2 + 1];
|
|
||||||
|
|
||||||
int probe_range = 8;
|
|
||||||
uint num_iters = 4;
|
|
||||||
|
|
||||||
const uint num_trials = probe_range * 2 + 1;
|
|
||||||
|
|
||||||
vec3F scaled_principle_axis(principle_axis * dist_per_trial);
|
|
||||||
scaled_principle_axis[0] *= 31.0f;
|
|
||||||
scaled_principle_axis[1] *= 63.0f;
|
|
||||||
scaled_principle_axis[2] *= 31.0f;
|
|
||||||
vec3F initial_ofs(scaled_principle_axis * (float)-probe_range);
|
|
||||||
initial_ofs[0] += .5f;
|
|
||||||
initial_ofs[1] += .5f;
|
|
||||||
initial_ofs[2] += .5f;
|
|
||||||
|
|
||||||
uint64 cur_error = orig_error;
|
|
||||||
|
|
||||||
for (uint iter = 0; iter < num_iters; iter++)
|
|
||||||
{
|
|
||||||
color_quad_u8 endpoints[2];
|
|
||||||
|
|
||||||
endpoints[0] = dxt1_block::unpack_color((uint16)low16, false);
|
|
||||||
endpoints[1] = dxt1_block::unpack_color((uint16)high16, false);
|
|
||||||
|
|
||||||
vec3F low_color(endpoints[0][0], endpoints[0][1], endpoints[0][2]);
|
|
||||||
vec3F high_color(endpoints[1][0], endpoints[1][1], endpoints[1][2]);
|
|
||||||
|
|
||||||
vec3F probe_low_color(low_color + initial_ofs);
|
|
||||||
for (uint i = 0; i < num_trials; i++)
|
|
||||||
{
|
|
||||||
int r = math::clamp((int)floor(probe_low_color[0]), 0, 31);
|
|
||||||
int g = math::clamp((int)floor(probe_low_color[1]), 0, 63);
|
|
||||||
int b = math::clamp((int)floor(probe_low_color[2]), 0, 31);
|
|
||||||
probe_low[i] = b | (g << 5U) | (r << 11U);
|
|
||||||
|
|
||||||
probe_low_color += scaled_principle_axis;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3F probe_high_color(high_color + initial_ofs);
|
|
||||||
for (uint i = 0; i < num_trials; i++)
|
|
||||||
{
|
|
||||||
int r = math::clamp((int)floor(probe_high_color[0]), 0, 31);
|
|
||||||
int g = math::clamp((int)floor(probe_high_color[1]), 0, 63);
|
|
||||||
int b = math::clamp((int)floor(probe_high_color[2]), 0, 31);
|
|
||||||
probe_high[i] = b | (g << 5U) | (r << 11U);
|
|
||||||
|
|
||||||
probe_high_color += scaled_principle_axis;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint best_l = low16;
|
|
||||||
uint best_h = high16;
|
|
||||||
|
|
||||||
enum { cMaxHash = 4 };
|
|
||||||
uint64 hash[cMaxHash];
|
|
||||||
for (uint i = 0; i < cMaxHash; i++)
|
|
||||||
hash[i] = 0;
|
|
||||||
|
|
||||||
uint c = best_l | (best_h << 16);
|
|
||||||
c = fast_hash(&c, sizeof(c));
|
|
||||||
hash[(c >> 6) & 3] = 1ULL << (c & 63);
|
|
||||||
|
|
||||||
for (uint i = 0; i < num_trials; i++)
|
|
||||||
{
|
|
||||||
for (uint j = 0; j < num_trials; j++)
|
|
||||||
{
|
|
||||||
uint l = probe_low[i];
|
|
||||||
uint h = probe_high[j];
|
|
||||||
if (l < h)
|
|
||||||
utils::swap(l, h);
|
|
||||||
|
|
||||||
uint c = l | (h << 16);
|
|
||||||
c = fast_hash(&c, sizeof(c));
|
|
||||||
uint64 mask = 1ULL << (c & 63);
|
|
||||||
uint ofs = (c >> 6) & 3;
|
|
||||||
if (hash[ofs] & mask)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
hash[ofs] |= mask;
|
|
||||||
|
|
||||||
uint64 new_error = determine_error(n, pBlock, l, h, cur_error);
|
|
||||||
if (new_error < cur_error)
|
|
||||||
{
|
|
||||||
best_l = l;
|
|
||||||
best_h = h;
|
|
||||||
cur_error = new_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool improved = false;
|
|
||||||
|
|
||||||
if ((best_l != low16) || (best_h != high16))
|
|
||||||
{
|
|
||||||
low16 = best_l;
|
|
||||||
high16 = best_h;
|
|
||||||
|
|
||||||
determine_selectors(n, pBlock, low16, high16, pSelectors);
|
|
||||||
improved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refine_endpoints(n, pBlock, low16, high16, pSelectors))
|
|
||||||
{
|
|
||||||
improved = true;
|
|
||||||
|
|
||||||
uint64 cur_error = determine_error(n, pBlock, low16, high16, cUINT64_MAX);
|
|
||||||
if (!cur_error)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!improved)
|
|
||||||
break;
|
|
||||||
|
|
||||||
} // iter
|
|
||||||
|
|
||||||
//uint64 end_error = determine_error(n, pBlock, low16, high16, UINT64_MAX);
|
|
||||||
//if (end_error > orig_error) DebugBreak();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void compress_solid_block(uint n, uint ave_color[3], uint& low16, uint& high16, uint8* pSelectors)
|
|
||||||
{
|
|
||||||
uint r = ave_color[0];
|
|
||||||
uint g = ave_color[1];
|
|
||||||
uint b = ave_color[2];
|
|
||||||
|
|
||||||
memset(pSelectors, 2, n);
|
|
||||||
|
|
||||||
low16 = (ryg_dxt::OMatch5[r][0]<<11) | (ryg_dxt::OMatch6[g][0]<<5) | ryg_dxt::OMatch5[b][0];
|
|
||||||
high16 = (ryg_dxt::OMatch5[r][1]<<11) | (ryg_dxt::OMatch6[g][1]<<5) | ryg_dxt::OMatch5[b][1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void compress_color_block(uint n, const color_quad_u8* block, uint& low16, uint& high16, uint8* pSelectors, bool refine)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((n & 15) == 0);
|
|
||||||
|
|
||||||
uint ave_color[3];
|
|
||||||
float axis[3];
|
|
||||||
|
|
||||||
if (!optimize_block_colors(n, block, low16, high16, ave_color, axis))
|
|
||||||
{
|
|
||||||
compress_solid_block(n, ave_color, low16, high16, pSelectors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!determine_selectors(n, block, low16, high16, pSelectors))
|
|
||||||
compress_solid_block(n, ave_color, low16, high16, pSelectors);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (refine_block(n, block, low16, high16, pSelectors))
|
|
||||||
determine_selectors(n, block, low16, high16, pSelectors);
|
|
||||||
|
|
||||||
if (refine)
|
|
||||||
refine_endpoints2(n, block, low16, high16, pSelectors, axis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (low16 < high16)
|
|
||||||
{
|
|
||||||
utils::swap(low16, high16);
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
pSelectors[i] ^= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compress_color_block(dxt1_block* pDXT1_block, const color_quad_u8* pBlock, bool refine)
|
|
||||||
{
|
|
||||||
uint8 color_selectors[16];
|
|
||||||
uint low16, high16;
|
|
||||||
dxt_fast::compress_color_block(16, pBlock, low16, high16, color_selectors, refine);
|
|
||||||
|
|
||||||
pDXT1_block->set_low_color(static_cast<uint16>(low16));
|
|
||||||
pDXT1_block->set_high_color(static_cast<uint16>(high16));
|
|
||||||
|
|
||||||
uint mask = 0;
|
|
||||||
for (int i = 15; i >= 0; i--)
|
|
||||||
{
|
|
||||||
mask <<= 2;
|
|
||||||
mask |= color_selectors[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
pDXT1_block->m_selectors[0] = (uint8)(mask & 0xFF);
|
|
||||||
pDXT1_block->m_selectors[1] = (uint8)((mask >> 8) & 0xFF);
|
|
||||||
pDXT1_block->m_selectors[2] = (uint8)((mask >> 16) & 0xFF);
|
|
||||||
pDXT1_block->m_selectors[3] = (uint8)((mask >> 24) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compress_alpha_block(uint n, const color_quad_u8* block, uint& low8, uint& high8, uint8* pSelectors, uint comp_index)
|
|
||||||
{
|
|
||||||
int min, max;
|
|
||||||
min = max = block[0][comp_index];
|
|
||||||
|
|
||||||
for (uint i = 1; i < n; i++)
|
|
||||||
{
|
|
||||||
min = math::minimum<int>(min, block[i][comp_index]);
|
|
||||||
max = math::maximum<int>(max, block[i][comp_index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
low8 = max;
|
|
||||||
high8 = min;
|
|
||||||
|
|
||||||
int dist = max-min;
|
|
||||||
int bias = min*7 - (dist >> 1);
|
|
||||||
int dist4 = dist*4;
|
|
||||||
int dist2 = dist*2;
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
int a = block[i][comp_index]*7 - bias;
|
|
||||||
int ind,t;
|
|
||||||
|
|
||||||
t = (dist4 - a) >> 31; ind = t & 4; a -= dist4 & t;
|
|
||||||
t = (dist2 - a) >> 31; ind += t & 2; a -= dist2 & t;
|
|
||||||
t = (dist - a) >> 31; ind += t & 1;
|
|
||||||
|
|
||||||
ind = -ind & 7;
|
|
||||||
ind ^= (2 > ind);
|
|
||||||
|
|
||||||
pSelectors[i] = static_cast<uint8>(ind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compress_alpha_block(dxt5_block* pDXT5_block, const color_quad_u8* pBlock, uint comp_index)
|
|
||||||
{
|
|
||||||
uint8 selectors[16];
|
|
||||||
uint low8, high8;
|
|
||||||
|
|
||||||
compress_alpha_block(16, pBlock, low8, high8, selectors, comp_index);
|
|
||||||
|
|
||||||
pDXT5_block->set_low_alpha(low8);
|
|
||||||
pDXT5_block->set_high_alpha(high8);
|
|
||||||
|
|
||||||
uint mask = 0;
|
|
||||||
uint bits = 0;
|
|
||||||
uint8* pDst = pDXT5_block->m_selectors;
|
|
||||||
|
|
||||||
for (uint i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
mask |= (selectors[i] << bits);
|
|
||||||
|
|
||||||
if ((bits += 3) >= 8)
|
|
||||||
{
|
|
||||||
*pDst++ = static_cast<uint8>(mask);
|
|
||||||
mask >>= 8;
|
|
||||||
bits -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void find_representative_colors(uint n, const color_quad_u8* pBlock, color_quad_u8& lo, color_quad_u8& hi)
|
|
||||||
{
|
|
||||||
uint64 ave64[3];
|
|
||||||
ave64[0] = 0;
|
|
||||||
ave64[1] = 0;
|
|
||||||
ave64[2] = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
ave64[0] += pBlock[i].r;
|
|
||||||
ave64[1] += pBlock[i].g;
|
|
||||||
ave64[2] += pBlock[i].b;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint ave[3];
|
|
||||||
ave[0] = static_cast<uint>((ave64[0] + (n / 2)) / n);
|
|
||||||
ave[1] = static_cast<uint>((ave64[1] + (n / 2)) / n);
|
|
||||||
ave[2] = static_cast<uint>((ave64[2] + (n / 2)) / n);
|
|
||||||
|
|
||||||
int furthest_dist = -1;
|
|
||||||
uint furthest_index = 0;
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
int r = pBlock[i].r - ave[0];
|
|
||||||
int g = pBlock[i].g - ave[1];
|
|
||||||
int b = pBlock[i].b - ave[2];
|
|
||||||
int dist = r*r + g*g + b*b;
|
|
||||||
if (dist > furthest_dist)
|
|
||||||
{
|
|
||||||
furthest_dist = dist;
|
|
||||||
furthest_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8 lo_color(pBlock[furthest_index]);
|
|
||||||
|
|
||||||
int opp_dist = -1;
|
|
||||||
uint opp_index = 0;
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
int r = pBlock[i].r - lo_color.r;
|
|
||||||
int g = pBlock[i].g - lo_color.g;
|
|
||||||
int b = pBlock[i].b - lo_color.b;
|
|
||||||
int dist = r*r + g*g + b*b;
|
|
||||||
if (dist > opp_dist)
|
|
||||||
{
|
|
||||||
opp_dist = dist;
|
|
||||||
opp_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8 hi_color(pBlock[opp_index]);
|
|
||||||
|
|
||||||
for (uint i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
lo_color[i] = static_cast<uint8>((lo_color[i] + ave[i]) >> 1);
|
|
||||||
hi_color[i] = static_cast<uint8>((hi_color[i] + ave[i]) >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint cMaxIters = 4;
|
|
||||||
for (uint iter_index = 0; iter_index < cMaxIters; iter_index++)
|
|
||||||
{
|
|
||||||
if ((lo_color[0] == hi_color[0]) && (lo_color[1] == hi_color[1]) && (lo_color[2] == hi_color[2]))
|
|
||||||
break;
|
|
||||||
|
|
||||||
uint64 new_color[2][3];
|
|
||||||
uint weight[2];
|
|
||||||
|
|
||||||
utils::zero_object(new_color);
|
|
||||||
utils::zero_object(weight);
|
|
||||||
|
|
||||||
int vec_r = hi_color[0] - lo_color[0];
|
|
||||||
int vec_g = hi_color[1] - lo_color[1];
|
|
||||||
int vec_b = hi_color[2] - lo_color[2];
|
|
||||||
|
|
||||||
int lo_dot = vec_r * lo_color[0] + vec_g * lo_color[1] + vec_b * lo_color[2];
|
|
||||||
int hi_dot = vec_r * hi_color[0] + vec_g * hi_color[1] + vec_b * hi_color[2];
|
|
||||||
int mid_dot = lo_dot + hi_dot;
|
|
||||||
|
|
||||||
vec_r *= 2;
|
|
||||||
vec_g *= 2;
|
|
||||||
vec_b *= 2;
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
const color_quad_u8& c = pBlock[i];
|
|
||||||
|
|
||||||
const int dot = c[0] * vec_r + c[1] * vec_g + c[2] * vec_b;
|
|
||||||
const uint match_index = (dot > mid_dot);
|
|
||||||
|
|
||||||
new_color[match_index][0] += c.r;
|
|
||||||
new_color[match_index][1] += c.g;
|
|
||||||
new_color[match_index][2] += c.b;
|
|
||||||
weight[match_index]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!weight[0]) || (!weight[1]))
|
|
||||||
break;
|
|
||||||
|
|
||||||
uint8 new_color8[2][3];
|
|
||||||
|
|
||||||
for (uint j = 0; j < 2; j++)
|
|
||||||
for (uint i = 0; i < 3; i++)
|
|
||||||
new_color8[j][i] = static_cast<uint8>((new_color[j][i] + (weight[j] / 2)) / weight[j]);
|
|
||||||
|
|
||||||
if ((new_color8[0][0] == lo_color[0]) && (new_color8[0][1] == lo_color[1]) && (new_color8[0][2] == lo_color[2]) &&
|
|
||||||
(new_color8[1][0] == hi_color[0]) && (new_color8[1][1] == hi_color[1]) && (new_color8[1][2] == hi_color[2]))
|
|
||||||
break;
|
|
||||||
|
|
||||||
for (uint i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
lo_color[i] = new_color8[0][i];
|
|
||||||
hi_color[i] = new_color8[1][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint energy[2] = { 0, 0 };
|
|
||||||
for (uint i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
energy[0] += lo_color[i] * lo_color[i];
|
|
||||||
energy[1] += hi_color[i] * hi_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (energy[0] > energy[1])
|
|
||||||
utils::swap(lo_color, hi_color);
|
|
||||||
|
|
||||||
lo = lo_color;
|
|
||||||
hi = hi_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dxt_fast
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
// File: crn_dxt_fast.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_color.h"
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace dxt_fast
|
|
||||||
{
|
|
||||||
void compress_color_block(uint n, const color_quad_u8* block, uint& low16, uint& high16, uint8* pSelectors, bool refine = false);
|
|
||||||
void compress_color_block(dxt1_block* pDXT1_block, const color_quad_u8* pBlock, bool refine = false);
|
|
||||||
|
|
||||||
void compress_alpha_block(uint n, const color_quad_u8* block, uint& low8, uint& high8, uint8* pSelectors, uint comp_index);
|
|
||||||
void compress_alpha_block(dxt5_block* pDXT5_block, const color_quad_u8* pBlock, uint comp_index);
|
|
||||||
|
|
||||||
void find_representative_colors(uint n, const color_quad_u8* pBlock, color_quad_u8& lo, color_quad_u8& hi);
|
|
||||||
|
|
||||||
} // namespace dxt_fast
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,439 +0,0 @@
|
||||||
// File: crn_dxt_hc.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_dxt1.h"
|
|
||||||
#include "crn_dxt5a.h"
|
|
||||||
#include "crn_dxt_endpoint_refiner.h"
|
|
||||||
#include "crn_image.h"
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
#include "crn_image.h"
|
|
||||||
#include "crn_dxt_hc_common.h"
|
|
||||||
#include "crn_tree_clusterizer.h"
|
|
||||||
#include "crn_threading.h"
|
|
||||||
|
|
||||||
#define CRN_NO_FUNCTION_DEFINITIONS
|
|
||||||
#include "../inc/crnlib.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
const uint cTotalCompressionPhases = 25;
|
|
||||||
|
|
||||||
class dxt_hc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dxt_hc();
|
|
||||||
~dxt_hc();
|
|
||||||
|
|
||||||
struct pixel_chunk
|
|
||||||
{
|
|
||||||
pixel_chunk() { clear(); }
|
|
||||||
|
|
||||||
dxt_pixel_block m_blocks[cChunkBlockHeight][cChunkBlockWidth];
|
|
||||||
|
|
||||||
const color_quad_u8& operator() (uint cx, uint cy) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((cx < cChunkPixelWidth) && (cy < cChunkPixelHeight));
|
|
||||||
|
|
||||||
return m_blocks[cy >> cBlockPixelHeightShift][cx >> cBlockPixelWidthShift].m_pixels
|
|
||||||
[cy & (cBlockPixelHeight - 1)][cx & (cBlockPixelWidth - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8& operator() (uint cx, uint cy)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((cx < cChunkPixelWidth) && (cy < cChunkPixelHeight));
|
|
||||||
|
|
||||||
return m_blocks[cy >> cBlockPixelHeightShift][cx >> cBlockPixelWidthShift].m_pixels
|
|
||||||
[cy & (cBlockPixelHeight - 1)][cx & (cBlockPixelWidth - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
utils::zero_object(*this);
|
|
||||||
m_weight = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float m_weight;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<pixel_chunk> pixel_chunk_vec;
|
|
||||||
|
|
||||||
struct params
|
|
||||||
{
|
|
||||||
params() :
|
|
||||||
m_color_endpoint_codebook_size(3072),
|
|
||||||
m_color_selector_codebook_size(3072),
|
|
||||||
m_alpha_endpoint_codebook_size(3072),
|
|
||||||
m_alpha_selector_codebook_size(3072),
|
|
||||||
m_adaptive_tile_color_psnr_derating(2.0f), // was 3.4f
|
|
||||||
m_adaptive_tile_alpha_psnr_derating(2.0f),
|
|
||||||
m_adaptive_tile_color_alpha_weighting_ratio(3.0f),
|
|
||||||
m_num_levels(0),
|
|
||||||
m_format(cDXT1),
|
|
||||||
m_hierarchical(true),
|
|
||||||
m_perceptual(true),
|
|
||||||
m_debugging(false),
|
|
||||||
m_pProgress_func(NULL),
|
|
||||||
m_pProgress_func_data(NULL)
|
|
||||||
{
|
|
||||||
m_alpha_component_indices[0] = 3;
|
|
||||||
m_alpha_component_indices[1] = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < cCRNMaxLevels; i++)
|
|
||||||
{
|
|
||||||
m_levels[i].m_first_chunk = 0;
|
|
||||||
m_levels[i].m_num_chunks = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid range for codebook sizes: [32,8192] (non-power of two values are okay)
|
|
||||||
uint m_color_endpoint_codebook_size;
|
|
||||||
uint m_color_selector_codebook_size;
|
|
||||||
|
|
||||||
uint m_alpha_endpoint_codebook_size;
|
|
||||||
uint m_alpha_selector_codebook_size;
|
|
||||||
|
|
||||||
// Higher values cause fewer 8x4, 4x8, and 4x4 blocks to be utilized less often (lower quality/smaller files).
|
|
||||||
// Lower values cause the encoder to use large tiles less often (better quality/larger files).
|
|
||||||
// Valid range: [0.0,100.0].
|
|
||||||
// A value of 0 will cause the encoder to only use tiles larger than 4x4 if doing so would incur to quality loss.
|
|
||||||
float m_adaptive_tile_color_psnr_derating;
|
|
||||||
|
|
||||||
float m_adaptive_tile_alpha_psnr_derating;
|
|
||||||
|
|
||||||
float m_adaptive_tile_color_alpha_weighting_ratio;
|
|
||||||
|
|
||||||
uint m_alpha_component_indices[2];
|
|
||||||
|
|
||||||
struct miplevel_desc
|
|
||||||
{
|
|
||||||
uint m_first_chunk;
|
|
||||||
uint m_num_chunks;
|
|
||||||
};
|
|
||||||
// The mip level data is optional!
|
|
||||||
miplevel_desc m_levels[cCRNMaxLevels];
|
|
||||||
uint m_num_levels;
|
|
||||||
|
|
||||||
dxt_format m_format;
|
|
||||||
|
|
||||||
// If m_hierarchical is false, only 4x4 blocks will be used by the encoder (leading to higher quality/larger files).
|
|
||||||
bool m_hierarchical;
|
|
||||||
|
|
||||||
// If m_perceptual is true, perceptual color metrics will be used by the encoder.
|
|
||||||
bool m_perceptual;
|
|
||||||
|
|
||||||
bool m_debugging;
|
|
||||||
|
|
||||||
crn_progress_callback_func m_pProgress_func;
|
|
||||||
void* m_pProgress_func_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
// Main compression function
|
|
||||||
bool compress(const params& p, uint num_chunks, const pixel_chunk* pChunks, task_pool& task_pool);
|
|
||||||
|
|
||||||
// Output accessors
|
|
||||||
inline uint get_num_chunks() const { return m_num_chunks; }
|
|
||||||
|
|
||||||
struct chunk_encoding
|
|
||||||
{
|
|
||||||
chunk_encoding() { utils::zero_object(*this); };
|
|
||||||
|
|
||||||
// Index into g_chunk_encodings.
|
|
||||||
uint8 m_encoding_index;
|
|
||||||
|
|
||||||
// Number of tiles, endpoint indices.
|
|
||||||
uint8 m_num_tiles;
|
|
||||||
|
|
||||||
// Color, alpha0, alpha1
|
|
||||||
enum { cColorIndex = 0, cAlpha0Index = 1, cAlpha1Index = 2 };
|
|
||||||
uint16 m_endpoint_indices[3][cChunkMaxTiles];
|
|
||||||
uint16 m_selector_indices[3][cChunkBlockHeight][cChunkBlockWidth]; // [block_y][block_x]
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<chunk_encoding> chunk_encoding_vec;
|
|
||||||
|
|
||||||
inline const chunk_encoding& get_chunk_encoding(uint chunk_index) const { return m_chunk_encoding[chunk_index]; }
|
|
||||||
inline const chunk_encoding_vec& get_chunk_encoding_vec() const { return m_chunk_encoding; }
|
|
||||||
|
|
||||||
struct selectors
|
|
||||||
{
|
|
||||||
selectors() { utils::zero_object(*this); }
|
|
||||||
|
|
||||||
uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth];
|
|
||||||
|
|
||||||
uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); const uint8* p = (const uint8*)m_selectors; return *(p + i); }
|
|
||||||
void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); uint8* p = (uint8*)m_selectors; *(p + i) = static_cast<uint8>(v); }
|
|
||||||
};
|
|
||||||
typedef crnlib::vector<selectors> selectors_vec;
|
|
||||||
|
|
||||||
// Color endpoints
|
|
||||||
inline uint get_color_endpoint_codebook_size() const { return m_color_endpoints.size(); }
|
|
||||||
inline uint get_color_endpoint(uint codebook_index) const { return m_color_endpoints[codebook_index]; }
|
|
||||||
const crnlib::vector<uint>& get_color_endpoint_vec() const { return m_color_endpoints; }
|
|
||||||
|
|
||||||
// Color selectors
|
|
||||||
uint get_color_selector_codebook_size() const { return m_color_selectors.size(); }
|
|
||||||
const selectors& get_color_selectors(uint codebook_index) const { return m_color_selectors[codebook_index]; }
|
|
||||||
const crnlib::vector<selectors>& get_color_selectors_vec() const { return m_color_selectors; }
|
|
||||||
|
|
||||||
// Alpha endpoints
|
|
||||||
inline uint get_alpha_endpoint_codebook_size() const { return m_alpha_endpoints.size(); }
|
|
||||||
inline uint get_alpha_endpoint(uint codebook_index) const { return m_alpha_endpoints[codebook_index]; }
|
|
||||||
const crnlib::vector<uint>& get_alpha_endpoint_vec() const { return m_alpha_endpoints; }
|
|
||||||
|
|
||||||
// Alpha selectors
|
|
||||||
uint get_alpha_selector_codebook_size() const { return m_alpha_selectors.size(); }
|
|
||||||
const selectors& get_alpha_selectors(uint codebook_index) const { return m_alpha_selectors[codebook_index]; }
|
|
||||||
const crnlib::vector<selectors>& get_alpha_selectors_vec() const { return m_alpha_selectors; }
|
|
||||||
|
|
||||||
// Debug images
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels() const { return m_dbg_chunk_pixels; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_tile_vis() const { return m_dbg_chunk_pixels_tile_vis; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_color_quantized() const { return m_dbg_chunk_pixels_color_quantized; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_alpha_quantized() const { return m_dbg_chunk_pixels_alpha_quantized; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_final() const { return m_dbg_chunk_pixels_final; }
|
|
||||||
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_orig_color_selectors() const { return m_dbg_chunk_pixels_orig_color_selectors; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_color_selectors() const { return m_dbg_chunk_pixels_quantized_color_selectors; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_final_color_selectors() const { return m_dbg_chunk_pixels_final_color_selectors; }
|
|
||||||
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_orig_alpha_selectors() const { return m_dbg_chunk_pixels_orig_alpha_selectors; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_alpha_selectors() const { return m_dbg_chunk_pixels_quantized_alpha_selectors; }
|
|
||||||
const pixel_chunk_vec& get_compressed_chunk_pixels_final_alpha_selectors() const { return m_dbg_chunk_pixels_final_alpha_selectors; }
|
|
||||||
|
|
||||||
static void create_debug_image_from_chunks(uint num_chunks_x, uint num_chunks_y, const pixel_chunk_vec& chunks, const chunk_encoding_vec *pChunk_encodings, image_u8& img, bool serpentine_scan, int comp_index = -1);
|
|
||||||
|
|
||||||
private:
|
|
||||||
params m_params;
|
|
||||||
|
|
||||||
uint m_num_chunks;
|
|
||||||
const pixel_chunk* m_pChunks;
|
|
||||||
|
|
||||||
chunk_encoding_vec m_chunk_encoding;
|
|
||||||
|
|
||||||
uint m_num_alpha_blocks; // 0, 1, or 2
|
|
||||||
bool m_has_color_blocks;
|
|
||||||
bool m_has_alpha0_blocks;
|
|
||||||
bool m_has_alpha1_blocks;
|
|
||||||
|
|
||||||
struct compressed_tile
|
|
||||||
{
|
|
||||||
uint m_endpoint_cluster_index;
|
|
||||||
uint m_first_endpoint;
|
|
||||||
uint m_second_endpoint;
|
|
||||||
|
|
||||||
uint8 m_selectors[cChunkPixelWidth * cChunkPixelHeight];
|
|
||||||
|
|
||||||
void set_selector(uint x, uint y, uint s)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < m_pixel_width) && (y < m_pixel_height));
|
|
||||||
m_selectors[x + y * m_pixel_width] = static_cast<uint8>(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_selector(uint x, uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < m_pixel_width) && (y < m_pixel_height));
|
|
||||||
return m_selectors[x + y * m_pixel_width];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 m_pixel_width;
|
|
||||||
uint8 m_pixel_height;
|
|
||||||
|
|
||||||
uint8 m_layout_index;
|
|
||||||
|
|
||||||
bool m_alpha_encoding;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct compressed_chunk
|
|
||||||
{
|
|
||||||
compressed_chunk() { utils::zero_object(*this); }
|
|
||||||
|
|
||||||
uint8 m_encoding_index;
|
|
||||||
|
|
||||||
uint8 m_num_tiles;
|
|
||||||
|
|
||||||
compressed_tile m_tiles[cChunkMaxTiles];
|
|
||||||
compressed_tile m_quantized_tiles[cChunkMaxTiles];
|
|
||||||
|
|
||||||
uint16 m_endpoint_cluster_index[cChunkMaxTiles];
|
|
||||||
uint16 m_selector_cluster_index[cChunkBlockHeight][cChunkBlockWidth];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<compressed_chunk> compressed_chunk_vec;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cColorChunks = 0,
|
|
||||||
cAlpha0Chunks = 1,
|
|
||||||
cAlpha1Chunks = 2,
|
|
||||||
|
|
||||||
cNumCompressedChunkVecs = 3
|
|
||||||
};
|
|
||||||
compressed_chunk_vec m_compressed_chunks[cNumCompressedChunkVecs];
|
|
||||||
|
|
||||||
volatile atomic32_t m_encoding_hist[cNumChunkEncodings];
|
|
||||||
|
|
||||||
atomic32_t m_total_tiles;
|
|
||||||
|
|
||||||
void compress_dxt1_block(
|
|
||||||
dxt1_endpoint_optimizer::results& results,
|
|
||||||
uint chunk_index, const image_u8& chunk, uint x_ofs, uint y_ofs, uint width, uint height,
|
|
||||||
uint8* pSelectors);
|
|
||||||
|
|
||||||
void compress_dxt5_block(
|
|
||||||
dxt5_endpoint_optimizer::results& results,
|
|
||||||
uint chunk_index, const image_u8& chunk, uint x_ofs, uint y_ofs, uint width, uint height, uint component_index,
|
|
||||||
uint8* pAlpha_selectors);
|
|
||||||
|
|
||||||
void determine_compressed_chunks_task(uint64 data, void* pData_ptr);
|
|
||||||
bool determine_compressed_chunks();
|
|
||||||
|
|
||||||
struct tile_cluster
|
|
||||||
{
|
|
||||||
tile_cluster() : m_first_endpoint(0), m_second_endpoint(0), m_error(0), m_alpha_encoding(false) { }
|
|
||||||
|
|
||||||
// first = chunk, second = tile
|
|
||||||
// if an alpha tile, second's upper 16 bits contains the alpha index (0 or 1)
|
|
||||||
crnlib::vector< std::pair<uint, uint> > m_tiles;
|
|
||||||
|
|
||||||
uint m_first_endpoint;
|
|
||||||
uint m_second_endpoint;
|
|
||||||
uint64 m_error;
|
|
||||||
|
|
||||||
bool m_alpha_encoding;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<tile_cluster> tile_cluster_vec;
|
|
||||||
|
|
||||||
tile_cluster_vec m_color_clusters;
|
|
||||||
tile_cluster_vec m_alpha_clusters;
|
|
||||||
|
|
||||||
selectors_vec m_color_selectors;
|
|
||||||
selectors_vec m_alpha_selectors;
|
|
||||||
|
|
||||||
// For each selector, this array indicates every chunk/tile/tile block that use this color selector.
|
|
||||||
struct block_id
|
|
||||||
{
|
|
||||||
block_id() { utils::zero_object(*this); }
|
|
||||||
|
|
||||||
block_id(uint chunk_index, uint alpha_index, uint tile_index, uint block_x, uint block_y) :
|
|
||||||
m_chunk_index(chunk_index), m_alpha_index((uint8)alpha_index), m_tile_index((uint8)tile_index), m_block_x((uint8)block_x), m_block_y((uint8)block_y) { }
|
|
||||||
|
|
||||||
uint m_chunk_index;
|
|
||||||
uint8 m_alpha_index;
|
|
||||||
uint8 m_tile_index;
|
|
||||||
uint8 m_block_x;
|
|
||||||
uint8 m_block_y;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector< crnlib::vector< block_id > > chunk_blocks_using_selectors_vec;
|
|
||||||
chunk_blocks_using_selectors_vec m_chunk_blocks_using_color_selectors;
|
|
||||||
chunk_blocks_using_selectors_vec m_chunk_blocks_using_alpha_selectors; // second's upper 16 bits contain alpha index!
|
|
||||||
|
|
||||||
crnlib::vector<uint> m_color_endpoints; // not valid until end, only for user access
|
|
||||||
crnlib::vector<uint> m_alpha_endpoints; // not valid until end, only for user access
|
|
||||||
|
|
||||||
// Debugging
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_tile_vis;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_color_quantized;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_alpha_quantized;
|
|
||||||
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_orig_color_selectors;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_quantized_color_selectors;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_final_color_selectors;
|
|
||||||
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_orig_alpha_selectors;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_quantized_alpha_selectors;
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_final_alpha_selectors;
|
|
||||||
|
|
||||||
pixel_chunk_vec m_dbg_chunk_pixels_final;
|
|
||||||
|
|
||||||
crn_thread_id_t m_main_thread_id;
|
|
||||||
bool m_canceled;
|
|
||||||
task_pool* m_pTask_pool;
|
|
||||||
|
|
||||||
int m_prev_phase_index;
|
|
||||||
int m_prev_percentage_complete;
|
|
||||||
|
|
||||||
typedef vec<6, float> vec6F;
|
|
||||||
typedef vec<16, float> vec16F;
|
|
||||||
typedef tree_clusterizer<vec2F> vec2F_tree_vq;
|
|
||||||
typedef tree_clusterizer<vec6F> vec6F_tree_vq;
|
|
||||||
typedef tree_clusterizer<vec16F> vec16F_tree_vq;
|
|
||||||
|
|
||||||
struct assign_color_endpoint_clusters_state
|
|
||||||
{
|
|
||||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(assign_color_endpoint_clusters_state);
|
|
||||||
|
|
||||||
assign_color_endpoint_clusters_state(vec6F_tree_vq& vq, crnlib::vector< crnlib::vector<vec6F> >& training_vecs) :
|
|
||||||
m_vq(vq), m_training_vecs(training_vecs) { }
|
|
||||||
|
|
||||||
vec6F_tree_vq& m_vq;
|
|
||||||
crnlib::vector< crnlib::vector<vec6F> >& m_training_vecs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct create_selector_codebook_state
|
|
||||||
{
|
|
||||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(create_selector_codebook_state);
|
|
||||||
|
|
||||||
create_selector_codebook_state(dxt_hc& hc, bool alpha_blocks, uint comp_index_start, uint comp_index_end, vec16F_tree_vq& selector_vq, chunk_blocks_using_selectors_vec& chunk_blocks_using_selectors, selectors_vec& selectors_cb) :
|
|
||||||
m_hc(hc),
|
|
||||||
m_alpha_blocks(alpha_blocks),
|
|
||||||
m_comp_index_start(comp_index_start),
|
|
||||||
m_comp_index_end(comp_index_end),
|
|
||||||
m_selector_vq(selector_vq),
|
|
||||||
m_chunk_blocks_using_selectors(chunk_blocks_using_selectors),
|
|
||||||
m_selectors_cb(selectors_cb)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
dxt_hc& m_hc;
|
|
||||||
bool m_alpha_blocks;
|
|
||||||
uint m_comp_index_start;
|
|
||||||
uint m_comp_index_end;
|
|
||||||
vec16F_tree_vq& m_selector_vq;
|
|
||||||
chunk_blocks_using_selectors_vec& m_chunk_blocks_using_selectors;
|
|
||||||
selectors_vec& m_selectors_cb;
|
|
||||||
|
|
||||||
mutable spinlock m_chunk_blocks_using_selectors_lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
void assign_color_endpoint_clusters_task(uint64 data, void* pData_ptr);
|
|
||||||
bool determine_color_endpoint_clusters();
|
|
||||||
|
|
||||||
struct determine_alpha_endpoint_clusters_state
|
|
||||||
{
|
|
||||||
vec2F_tree_vq m_vq;
|
|
||||||
crnlib::vector< crnlib::vector<vec2F> > m_training_vecs[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
void determine_alpha_endpoint_clusters_task(uint64 data, void* pData_ptr);
|
|
||||||
bool determine_alpha_endpoint_clusters();
|
|
||||||
|
|
||||||
void determine_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool determine_color_endpoint_codebook();
|
|
||||||
|
|
||||||
void determine_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool determine_alpha_endpoint_codebook();
|
|
||||||
|
|
||||||
void create_quantized_debug_images();
|
|
||||||
|
|
||||||
void create_selector_codebook_task(uint64 data, void* pData_ptr);
|
|
||||||
bool create_selector_codebook(bool alpha_blocks);
|
|
||||||
|
|
||||||
bool refine_quantized_color_endpoints();
|
|
||||||
bool refine_quantized_color_selectors();
|
|
||||||
bool refine_quantized_alpha_endpoints();
|
|
||||||
bool refine_quantized_alpha_selectors();
|
|
||||||
void create_final_debug_image();
|
|
||||||
bool create_chunk_encodings();
|
|
||||||
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
|
|
||||||
bool compress_internal(const params& p, uint num_chunks, const pixel_chunk* pChunks);
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::pixel_chunk);
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::chunk_encoding);
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::selectors);
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,47 +0,0 @@
|
||||||
// File: crn_dxt_hc_common.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_dxt_hc_common.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings] =
|
|
||||||
{
|
|
||||||
{ 1, { { 0, 0, 8, 8, 0 } } },
|
|
||||||
|
|
||||||
{ 2, { { 0, 0, 8, 4, 1 }, { 0, 4, 8, 4, 2 } } },
|
|
||||||
{ 2, { { 0, 0, 4, 8, 3 }, { 4, 0, 4, 8, 4 } } },
|
|
||||||
|
|
||||||
{ 3, { { 0, 0, 8, 4, 1 }, { 0, 4, 4, 4, 7 }, { 4, 4, 4, 4, 8 } } },
|
|
||||||
{ 3, { { 0, 4, 8, 4, 2 }, { 0, 0, 4, 4, 5 }, { 4, 0, 4, 4, 6 } } },
|
|
||||||
|
|
||||||
{ 3, { { 0, 0, 4, 8, 3 }, { 4, 0, 4, 4, 6 }, { 4, 4, 4, 4, 8 } } },
|
|
||||||
{ 3, { { 4, 0, 4, 8, 4 }, { 0, 0, 4, 4, 5 }, { 0, 4, 4, 4, 7 } } },
|
|
||||||
|
|
||||||
{ 4, { { 0, 0, 4, 4, 5 }, { 4, 0, 4, 4, 6 }, { 0, 4, 4, 4, 7 }, { 4, 4, 4, 4, 8 } } }
|
|
||||||
};
|
|
||||||
|
|
||||||
chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts] =
|
|
||||||
{
|
|
||||||
// 2x2
|
|
||||||
{ 0, 0, 8, 8, 0 },
|
|
||||||
|
|
||||||
// 2x1
|
|
||||||
{ 0, 0, 8, 4, 1 },
|
|
||||||
{ 0, 4, 8, 4, 2 },
|
|
||||||
|
|
||||||
// 1x2
|
|
||||||
{ 0, 0, 4, 8, 3 },
|
|
||||||
{ 4, 0, 4, 8, 4 },
|
|
||||||
|
|
||||||
// 1x1
|
|
||||||
{ 0, 0, 4, 4, 5 },
|
|
||||||
{ 4, 0, 4, 4, 6 },
|
|
||||||
{ 0, 4, 4, 4, 7 },
|
|
||||||
{ 4, 4, 4, 4, 8 }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// File: crn_dxt_hc_common.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
struct chunk_tile_desc
|
|
||||||
{
|
|
||||||
// These values are in pixels, and always a multiple of cBlockPixelWidth/cBlockPixelHeight.
|
|
||||||
uint m_x_ofs;
|
|
||||||
uint m_y_ofs;
|
|
||||||
uint m_width;
|
|
||||||
uint m_height;
|
|
||||||
uint m_layout_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct chunk_encoding_desc
|
|
||||||
{
|
|
||||||
uint m_num_tiles;
|
|
||||||
chunk_tile_desc m_tiles[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint cChunkPixelWidth = 8;
|
|
||||||
const uint cChunkPixelHeight = 8;
|
|
||||||
const uint cChunkBlockWidth = 2;
|
|
||||||
const uint cChunkBlockHeight = 2;
|
|
||||||
|
|
||||||
const uint cChunkMaxTiles = 4;
|
|
||||||
|
|
||||||
const uint cBlockPixelWidthShift = 2;
|
|
||||||
const uint cBlockPixelHeightShift = 2;
|
|
||||||
|
|
||||||
const uint cBlockPixelWidth = 4;
|
|
||||||
const uint cBlockPixelHeight = 4;
|
|
||||||
|
|
||||||
const uint cNumChunkEncodings = 8;
|
|
||||||
extern chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings];
|
|
||||||
|
|
||||||
const uint cNumChunkTileLayouts = 9;
|
|
||||||
const uint cFirst4x4ChunkTileLayout = 5;
|
|
||||||
extern chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts];
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,248 +0,0 @@
|
||||||
// File: crn_dxt_image.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_dxt1.h"
|
|
||||||
#include "crn_dxt5a.h"
|
|
||||||
#include "crn_etc.h"
|
|
||||||
#if CRNLIB_SUPPORT_ETC_A1
|
|
||||||
#include "crn_etc_a1.h"
|
|
||||||
#endif
|
|
||||||
#include "crn_image.h"
|
|
||||||
|
|
||||||
#define CRNLIB_SUPPORT_ATI_COMPRESS 0
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class task_pool;
|
|
||||||
|
|
||||||
class dxt_image
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dxt_image();
|
|
||||||
dxt_image(const dxt_image& other);
|
|
||||||
dxt_image& operator= (const dxt_image& rhs);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
inline bool is_valid() const { return m_blocks_x > 0; }
|
|
||||||
|
|
||||||
uint get_width() const { return m_width; }
|
|
||||||
uint get_height() const { return m_height; }
|
|
||||||
|
|
||||||
uint get_blocks_x() const { return m_blocks_x; }
|
|
||||||
uint get_blocks_y() const { return m_blocks_y; }
|
|
||||||
uint get_total_blocks() const { return m_blocks_x * m_blocks_y; }
|
|
||||||
|
|
||||||
uint get_elements_per_block() const { return m_num_elements_per_block; }
|
|
||||||
uint get_bytes_per_block() const { return m_bytes_per_block; }
|
|
||||||
|
|
||||||
dxt_format get_format() const { return m_format; }
|
|
||||||
|
|
||||||
bool has_color() const { return (m_format == cDXT1) || (m_format == cDXT1A) || (m_format == cDXT3) || (m_format == cDXT5) || (m_format == cETC1); }
|
|
||||||
|
|
||||||
// Will be pretty slow if the image is DXT1, as this method scans for alpha blocks/selectors.
|
|
||||||
bool has_alpha() const;
|
|
||||||
|
|
||||||
enum element_type
|
|
||||||
{
|
|
||||||
cUnused = 0,
|
|
||||||
|
|
||||||
cColorDXT1, // DXT1 color block
|
|
||||||
|
|
||||||
cAlphaDXT3, // DXT3 alpha block (only)
|
|
||||||
cAlphaDXT5, // DXT5 alpha block (only)
|
|
||||||
|
|
||||||
cColorETC1, // ETC1 color block
|
|
||||||
};
|
|
||||||
|
|
||||||
element_type get_element_type(uint element_index) const { CRNLIB_ASSERT(element_index < m_num_elements_per_block); return m_element_type[element_index]; }
|
|
||||||
|
|
||||||
//Returns -1 for RGB, or [0,3]
|
|
||||||
int8 get_element_component_index(uint element_index) const { CRNLIB_ASSERT(element_index < m_num_elements_per_block); return m_element_component_index[element_index]; }
|
|
||||||
|
|
||||||
struct element
|
|
||||||
{
|
|
||||||
uint8 m_bytes[8];
|
|
||||||
|
|
||||||
uint get_le_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2] | (m_bytes[index * 2 + 1] << 8); }
|
|
||||||
uint get_be_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2 + 1] | (m_bytes[index * 2] << 8); }
|
|
||||||
|
|
||||||
void set_le_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF); }
|
|
||||||
void set_be_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2+1] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2] = static_cast<uint8>((val >> 8) & 0xFF); }
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
memset(this, 0, sizeof(*this));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<element> element_vec;
|
|
||||||
|
|
||||||
bool init(dxt_format fmt, uint width, uint height, bool clear_elements);
|
|
||||||
bool init(dxt_format fmt, uint width, uint height, uint num_elements, element* pElements, bool create_copy);
|
|
||||||
|
|
||||||
struct pack_params
|
|
||||||
{
|
|
||||||
pack_params()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_quality = cCRNDXTQualityUber;
|
|
||||||
m_perceptual = true;
|
|
||||||
m_dithering = false;
|
|
||||||
m_grayscale_sampling = false;
|
|
||||||
m_use_both_block_types = true;
|
|
||||||
m_endpoint_caching = true;
|
|
||||||
m_compressor = cCRNDXTCompressorCRN;
|
|
||||||
m_pProgress_callback = NULL;
|
|
||||||
m_pProgress_callback_user_data_ptr = NULL;
|
|
||||||
m_dxt1a_alpha_threshold = 128;
|
|
||||||
m_num_helper_threads = 0;
|
|
||||||
m_progress_start = 0;
|
|
||||||
m_progress_range = 100;
|
|
||||||
m_use_transparent_indices_for_black = false;
|
|
||||||
m_pTask_pool = NULL;
|
|
||||||
m_color_weights[0] = 1;
|
|
||||||
m_color_weights[1] = 1;
|
|
||||||
m_color_weights[2] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(const crn_comp_params ¶ms)
|
|
||||||
{
|
|
||||||
m_perceptual = (params.m_flags & cCRNCompFlagPerceptual) != 0;
|
|
||||||
m_num_helper_threads = params.m_num_helper_threads;
|
|
||||||
m_use_both_block_types = (params.m_flags & cCRNCompFlagUseBothBlockTypes) != 0;
|
|
||||||
m_use_transparent_indices_for_black = (params.m_flags & cCRNCompFlagUseTransparentIndicesForBlack) != 0;
|
|
||||||
m_dxt1a_alpha_threshold = params.m_dxt1a_alpha_threshold;
|
|
||||||
m_quality = params.m_dxt_quality;
|
|
||||||
m_endpoint_caching = (params.m_flags & cCRNCompFlagDisableEndpointCaching) == 0;
|
|
||||||
m_grayscale_sampling = (params.m_flags & cCRNCompFlagGrayscaleSampling) != 0;
|
|
||||||
m_compressor = params.m_dxt_compressor_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint m_dxt1a_alpha_threshold;
|
|
||||||
|
|
||||||
uint m_num_helper_threads;
|
|
||||||
|
|
||||||
crn_dxt_quality m_quality;
|
|
||||||
|
|
||||||
crn_dxt_compressor_type m_compressor;
|
|
||||||
|
|
||||||
bool m_perceptual;
|
|
||||||
bool m_dithering;
|
|
||||||
bool m_grayscale_sampling;
|
|
||||||
bool m_use_both_block_types;
|
|
||||||
bool m_endpoint_caching;
|
|
||||||
bool m_use_transparent_indices_for_black;
|
|
||||||
|
|
||||||
typedef bool (*progress_callback_func)(uint percentage_complete, void* pUser_data_ptr);
|
|
||||||
progress_callback_func m_pProgress_callback;
|
|
||||||
void* m_pProgress_callback_user_data_ptr;
|
|
||||||
|
|
||||||
uint m_progress_start;
|
|
||||||
uint m_progress_range;
|
|
||||||
|
|
||||||
task_pool *m_pTask_pool;
|
|
||||||
|
|
||||||
int m_color_weights[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
bool init(dxt_format fmt, const image_u8& img, const pack_params& p = dxt_image::pack_params());
|
|
||||||
|
|
||||||
bool unpack(image_u8& img) const;
|
|
||||||
|
|
||||||
void endian_swap();
|
|
||||||
|
|
||||||
uint get_total_elements() const { return m_elements.size(); }
|
|
||||||
|
|
||||||
const element_vec& get_element_vec() const { return m_elements; }
|
|
||||||
element_vec& get_element_vec() { return m_elements; }
|
|
||||||
|
|
||||||
const element& get_element(uint block_x, uint block_y, uint element_index) const;
|
|
||||||
element& get_element(uint block_x, uint block_y, uint element_index);
|
|
||||||
|
|
||||||
const element* get_element_ptr() const { return m_pElements; }
|
|
||||||
element* get_element_ptr() { return m_pElements; }
|
|
||||||
|
|
||||||
uint get_size_in_bytes() const { return m_elements.size() * sizeof(element); }
|
|
||||||
uint get_row_pitch_in_bytes() const { return m_blocks_x * m_bytes_per_block; }
|
|
||||||
|
|
||||||
color_quad_u8 get_pixel(uint x, uint y) const;
|
|
||||||
uint get_pixel_alpha(uint x, uint y, uint element_index) const;
|
|
||||||
|
|
||||||
void set_pixel(uint x, uint y, const color_quad_u8& c, bool perceptual = true);
|
|
||||||
|
|
||||||
// get_block_pixels() only sets those components stored in the image!
|
|
||||||
bool get_block_pixels(uint block_x, uint block_y, color_quad_u8* pPixels) const;
|
|
||||||
|
|
||||||
struct set_block_pixels_context
|
|
||||||
{
|
|
||||||
dxt1_endpoint_optimizer m_dxt1_optimizer;
|
|
||||||
dxt5_endpoint_optimizer m_dxt5_optimizer;
|
|
||||||
pack_etc1_block_context m_etc1_optimizer;
|
|
||||||
#if CRNLIB_SUPPORT_ETC_A1
|
|
||||||
etc_a1::pack_etc1_block_context m_etc1_a1_optimizer;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p, set_block_pixels_context& context);
|
|
||||||
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p);
|
|
||||||
|
|
||||||
void get_block_endpoints(uint block_x, uint block_y, uint element_index, uint& packed_low_endpoint, uint& packed_high_endpoint) const;
|
|
||||||
|
|
||||||
// Returns a value representing the component(s) that where actually set, where -1 = RGB.
|
|
||||||
// This method does not always set every component!
|
|
||||||
int get_block_endpoints(uint block_x, uint block_y, uint element_index, color_quad_u8& low_endpoint, color_quad_u8& high_endpoint, bool scaled = true) const;
|
|
||||||
|
|
||||||
// pColors should point to a 16 entry array, to handle DXT3.
|
|
||||||
// Returns the number of block colors: 3, 4, 6, 8, or 16.
|
|
||||||
uint get_block_colors(uint block_x, uint block_y, uint element_index, color_quad_u8* pColors, uint subblock_index = 0);
|
|
||||||
|
|
||||||
uint get_subblock_index(uint x, uint y, uint element_index) const;
|
|
||||||
uint get_total_subblocks(uint element_index) const;
|
|
||||||
|
|
||||||
uint get_selector(uint x, uint y, uint element_index) const;
|
|
||||||
|
|
||||||
void change_dxt1_to_dxt1a();
|
|
||||||
|
|
||||||
bool can_flip(uint axis_index);
|
|
||||||
|
|
||||||
// Returns true if the texture can actually be flipped.
|
|
||||||
bool flip_x();
|
|
||||||
bool flip_y();
|
|
||||||
|
|
||||||
private:
|
|
||||||
element_vec m_elements;
|
|
||||||
element* m_pElements;
|
|
||||||
|
|
||||||
uint m_width;
|
|
||||||
uint m_height;
|
|
||||||
|
|
||||||
uint m_blocks_x;
|
|
||||||
uint m_blocks_y;
|
|
||||||
uint m_total_blocks;
|
|
||||||
uint m_total_elements;
|
|
||||||
|
|
||||||
uint m_num_elements_per_block; // 1 or 2
|
|
||||||
uint m_bytes_per_block; // 8 or 16
|
|
||||||
|
|
||||||
int8 m_element_component_index[2];
|
|
||||||
element_type m_element_type[2];
|
|
||||||
|
|
||||||
dxt_format m_format; // DXT1, 1A, 3, 5, N/3DC, or 5A
|
|
||||||
|
|
||||||
bool init_internal(dxt_format fmt, uint width, uint height);
|
|
||||||
void init_task(uint64 data, void* pData_ptr);
|
|
||||||
|
|
||||||
#if CRNLIB_SUPPORT_ATI_COMPRESS
|
|
||||||
bool init_ati_compress(dxt_format fmt, const image_u8& img, const pack_params& p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void flip_col(uint x);
|
|
||||||
void flip_row(uint y);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,206 +0,0 @@
|
||||||
// File: crn_dynamic_stream.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_data_stream.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class dynamic_stream : public data_stream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dynamic_stream(uint initial_size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
|
|
||||||
data_stream(pName, attribs),
|
|
||||||
m_ofs(0)
|
|
||||||
{
|
|
||||||
open(initial_size, pName, attribs);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_stream(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
|
|
||||||
data_stream(pName, attribs),
|
|
||||||
m_ofs(0)
|
|
||||||
{
|
|
||||||
open(pBuf, size, pName, attribs);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_stream() :
|
|
||||||
data_stream(),
|
|
||||||
m_ofs(0)
|
|
||||||
{
|
|
||||||
open();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~dynamic_stream()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(uint initial_size = 0, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
|
|
||||||
m_opened = true;
|
|
||||||
m_buf.clear();
|
|
||||||
m_buf.resize(initial_size);
|
|
||||||
m_ofs = 0;
|
|
||||||
m_name.set(pName ? pName : "dynamic_stream");
|
|
||||||
m_attribs = static_cast<attribs_t>(attribs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reopen(const char* pName, uint attribs)
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
{
|
|
||||||
return open(0, pName, attribs);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_name.set(pName ? pName : "dynamic_stream");
|
|
||||||
m_attribs = static_cast<attribs_t>(attribs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
{
|
|
||||||
m_opened = true;
|
|
||||||
m_buf.resize(size);
|
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf);
|
|
||||||
memcpy(&m_buf[0], pBuf, size);
|
|
||||||
}
|
|
||||||
m_ofs = 0;
|
|
||||||
m_name.set(pName ? pName : "dynamic_stream");
|
|
||||||
m_attribs = static_cast<attribs_t>(attribs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool close()
|
|
||||||
{
|
|
||||||
if (m_opened)
|
|
||||||
{
|
|
||||||
m_opened = false;
|
|
||||||
m_buf.clear();
|
|
||||||
m_ofs = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const crnlib::vector<uint8>& get_buf() const { return m_buf; }
|
|
||||||
crnlib::vector<uint8>& get_buf() { return m_buf; }
|
|
||||||
|
|
||||||
void reserve(uint size)
|
|
||||||
{
|
|
||||||
if (m_opened)
|
|
||||||
{
|
|
||||||
m_buf.reserve(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; }
|
|
||||||
|
|
||||||
virtual uint read(void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
|
|
||||||
|
|
||||||
if ((!m_opened) || (!is_readable()) || (!len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_buf.size());
|
|
||||||
|
|
||||||
uint bytes_left = m_buf.size() - m_ofs;
|
|
||||||
|
|
||||||
len = math::minimum<uint>(len, bytes_left);
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
memcpy(pBuf, &m_buf[m_ofs], len);
|
|
||||||
|
|
||||||
m_ofs += len;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint write(const void* pBuf, uint len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
|
|
||||||
|
|
||||||
if ((!m_opened) || (!is_writable()) || (!len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_buf.size());
|
|
||||||
|
|
||||||
uint new_ofs = m_ofs + len;
|
|
||||||
if (new_ofs > m_buf.size())
|
|
||||||
m_buf.resize(new_ofs);
|
|
||||||
|
|
||||||
memcpy(&m_buf[m_ofs], pBuf, len);
|
|
||||||
m_ofs = new_ofs;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool flush()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_size()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_buf.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_remaining()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(m_ofs <= m_buf.size());
|
|
||||||
|
|
||||||
return m_buf.size() - m_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint64 get_ofs()
|
|
||||||
{
|
|
||||||
if (!m_opened)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool seek(int64 ofs, bool relative)
|
|
||||||
{
|
|
||||||
if ((!m_opened) || (!is_seekable()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
|
|
||||||
|
|
||||||
if (new_ofs < 0)
|
|
||||||
return false;
|
|
||||||
else if (new_ofs > m_buf.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_ofs = static_cast<uint>(new_ofs);
|
|
||||||
|
|
||||||
post_seek();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
crnlib::vector<uint8> m_buf;
|
|
||||||
uint m_ofs;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,668 +0,0 @@
|
||||||
// File: crn_dynamic_string.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_strutils.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
dynamic_string g_empty_dynamic_string;
|
|
||||||
|
|
||||||
dynamic_string::dynamic_string(eVarArg dummy, const char* p, ...) :
|
|
||||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
|
||||||
{
|
|
||||||
dummy;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
format_args(p, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string::dynamic_string(const char* p) :
|
|
||||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
set(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string::dynamic_string(const char* p, uint len) :
|
|
||||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
set_from_buf(p, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string::dynamic_string(const dynamic_string& other) :
|
|
||||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
|
||||||
{
|
|
||||||
set(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dynamic_string::clear()
|
|
||||||
{
|
|
||||||
check();
|
|
||||||
|
|
||||||
if (m_pStr)
|
|
||||||
{
|
|
||||||
crnlib_delete_array(m_pStr);
|
|
||||||
m_pStr = NULL;
|
|
||||||
|
|
||||||
m_len = 0;
|
|
||||||
m_buf_size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dynamic_string::empty()
|
|
||||||
{
|
|
||||||
truncate(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dynamic_string::optimize()
|
|
||||||
{
|
|
||||||
if (!m_len)
|
|
||||||
clear();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint min_buf_size = math::next_pow2((uint)m_len + 1);
|
|
||||||
if (m_buf_size > min_buf_size)
|
|
||||||
{
|
|
||||||
char* p = crnlib_new_array<char>(min_buf_size);
|
|
||||||
memcpy(p, m_pStr, m_len + 1);
|
|
||||||
|
|
||||||
crnlib_delete_array(m_pStr);
|
|
||||||
m_pStr = p;
|
|
||||||
|
|
||||||
m_buf_size = static_cast<uint16>(min_buf_size);
|
|
||||||
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::compare(const char* p, bool case_sensitive) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
const int result = (case_sensitive ? strcmp : crn_stricmp)(get_ptr_priv(), p);
|
|
||||||
|
|
||||||
if (result < 0)
|
|
||||||
return -1;
|
|
||||||
else if (result > 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::compare(const dynamic_string& rhs, bool case_sensitive) const
|
|
||||||
{
|
|
||||||
return compare(rhs.get_ptr_priv(), case_sensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::set(const char* p, uint max_len)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
const uint len = math::minimum<uint>(max_len, static_cast<uint>(strlen(p)));
|
|
||||||
CRNLIB_ASSERT(len < cUINT16_MAX);
|
|
||||||
|
|
||||||
if ((!len) || (len >= cUINT16_MAX))
|
|
||||||
clear();
|
|
||||||
else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size)))
|
|
||||||
{
|
|
||||||
if (m_pStr != p)
|
|
||||||
memmove(m_pStr, p, len);
|
|
||||||
m_pStr[len] = '\0';
|
|
||||||
m_len = static_cast<uint16>(len);
|
|
||||||
}
|
|
||||||
else if (ensure_buf(len, false))
|
|
||||||
{
|
|
||||||
m_len = static_cast<uint16>(len);
|
|
||||||
memcpy(m_pStr, p, m_len + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
check();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::set(const dynamic_string& other, uint max_len)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
{
|
|
||||||
if (max_len < m_len)
|
|
||||||
{
|
|
||||||
m_pStr[max_len] = '\0';
|
|
||||||
m_len = static_cast<uint16>(max_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const uint len = math::minimum<uint>(max_len, other.m_len);
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
clear();
|
|
||||||
else if (ensure_buf(len, false))
|
|
||||||
{
|
|
||||||
m_len = static_cast<uint16>(len);
|
|
||||||
memcpy(m_pStr, other.get_ptr_priv(), m_len);
|
|
||||||
m_pStr[len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dynamic_string::set_len(uint new_len, char fill_char)
|
|
||||||
{
|
|
||||||
if ((new_len >= cUINT16_MAX) || (!fill_char))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint cur_len = m_len;
|
|
||||||
|
|
||||||
if (ensure_buf(new_len, true))
|
|
||||||
{
|
|
||||||
if (new_len > cur_len)
|
|
||||||
memset(m_pStr + cur_len, fill_char, new_len - cur_len);
|
|
||||||
|
|
||||||
m_pStr[new_len] = 0;
|
|
||||||
|
|
||||||
m_len = static_cast<uint16>(new_len);
|
|
||||||
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(buf_size_in_chars <= cUINT16_MAX);
|
|
||||||
CRNLIB_ASSERT(math::is_power_of_2(buf_size_in_chars) || (buf_size_in_chars == cUINT16_MAX));
|
|
||||||
CRNLIB_ASSERT((len_in_chars + 1) <= buf_size_in_chars);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_pStr = pBuf;
|
|
||||||
m_buf_size = static_cast<uint16>(buf_size_in_chars);
|
|
||||||
m_len = static_cast<uint16>(len_in_chars);
|
|
||||||
|
|
||||||
check();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::set_from_buf(const void* pBuf, uint buf_size)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(pBuf);
|
|
||||||
|
|
||||||
if (buf_size >= cUINT16_MAX)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CRNLIB_BUILD_DEBUG
|
|
||||||
if ((buf_size) && (memchr(pBuf, 0, buf_size) != NULL))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ensure_buf(buf_size, false))
|
|
||||||
{
|
|
||||||
if (buf_size)
|
|
||||||
memcpy(m_pStr, pBuf, buf_size);
|
|
||||||
|
|
||||||
m_pStr[buf_size] = 0;
|
|
||||||
|
|
||||||
m_len = static_cast<uint16>(buf_size);
|
|
||||||
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::set_char(uint index, char c)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(index <= m_len);
|
|
||||||
|
|
||||||
if (!c)
|
|
||||||
truncate(index);
|
|
||||||
else if (index < m_len)
|
|
||||||
{
|
|
||||||
m_pStr[index] = c;
|
|
||||||
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
else if (index == m_len)
|
|
||||||
append_char(c);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::append_char(char c)
|
|
||||||
{
|
|
||||||
if (ensure_buf(m_len + 1))
|
|
||||||
{
|
|
||||||
m_pStr[m_len] = c;
|
|
||||||
m_pStr[m_len + 1] = '\0';
|
|
||||||
m_len++;
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::truncate(uint new_len)
|
|
||||||
{
|
|
||||||
if (new_len < m_len)
|
|
||||||
{
|
|
||||||
m_pStr[new_len] = '\0';
|
|
||||||
m_len = static_cast<uint16>(new_len);
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::tolower()
|
|
||||||
{
|
|
||||||
if (m_len)
|
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
_strlwr_s(get_ptr_priv(), m_buf_size);
|
|
||||||
#else
|
|
||||||
strlwr(get_ptr_priv());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::toupper()
|
|
||||||
{
|
|
||||||
if (m_len)
|
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
_strupr_s(get_ptr_priv(), m_buf_size);
|
|
||||||
#else
|
|
||||||
strupr(get_ptr_priv());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::append(const char* p)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
uint len = static_cast<uint>(strlen(p));
|
|
||||||
uint new_total_len = m_len + len;
|
|
||||||
if ((new_total_len) && ensure_buf(new_total_len))
|
|
||||||
{
|
|
||||||
memcpy(m_pStr + m_len, p, len + 1);
|
|
||||||
m_len = static_cast<uint16>(m_len + len);
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::append(const dynamic_string& other)
|
|
||||||
{
|
|
||||||
uint len = other.m_len;
|
|
||||||
uint new_total_len = m_len + len;
|
|
||||||
if ((new_total_len) && ensure_buf(new_total_len))
|
|
||||||
{
|
|
||||||
memcpy(m_pStr + m_len, other.get_ptr_priv(), len + 1);
|
|
||||||
m_len = static_cast<uint16>(m_len + len);
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string operator+ (const char* p, const dynamic_string& a)
|
|
||||||
{
|
|
||||||
return dynamic_string(p).append(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string operator+ (const dynamic_string& a, const char* p)
|
|
||||||
{
|
|
||||||
return dynamic_string(a).append(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string operator+ (const dynamic_string& a, const dynamic_string& b)
|
|
||||||
{
|
|
||||||
return dynamic_string(a).append(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::format_args(const char* p, va_list args)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
const uint cBufSize = 4096;
|
|
||||||
char buf[cBufSize];
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
int l = vsnprintf_s(buf, cBufSize, _TRUNCATE, p, args);
|
|
||||||
#else
|
|
||||||
int l = vsnprintf(buf, cBufSize, p, args);
|
|
||||||
#endif
|
|
||||||
if (l <= 0)
|
|
||||||
clear();
|
|
||||||
else if (ensure_buf(l, false))
|
|
||||||
{
|
|
||||||
memcpy(m_pStr, buf, l + 1);
|
|
||||||
|
|
||||||
m_len = static_cast<uint16>(l);
|
|
||||||
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::format(const char* p, ...)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start(args, p);
|
|
||||||
format_args(p, args);
|
|
||||||
va_end(args);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::crop(uint start, uint len)
|
|
||||||
{
|
|
||||||
if (start >= m_len)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = math::minimum<uint>(len, m_len - start);
|
|
||||||
|
|
||||||
if (start)
|
|
||||||
memmove(get_ptr_priv(), get_ptr_priv() + start, len);
|
|
||||||
|
|
||||||
m_pStr[len] = '\0';
|
|
||||||
|
|
||||||
m_len = static_cast<uint16>(len);
|
|
||||||
|
|
||||||
check();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::substring(uint start, uint end)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(start <= end);
|
|
||||||
if (start > end)
|
|
||||||
return *this;
|
|
||||||
return crop(start, end - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::left(uint len)
|
|
||||||
{
|
|
||||||
return substring(0, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::mid(uint start, uint len)
|
|
||||||
{
|
|
||||||
return crop(start, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::right(uint start)
|
|
||||||
{
|
|
||||||
return substring(start, get_len());
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::tail(uint num)
|
|
||||||
{
|
|
||||||
return substring(math::maximum<int>(static_cast<int>(get_len()) - static_cast<int>(num), 0), get_len());
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::unquote()
|
|
||||||
{
|
|
||||||
if (m_len >= 2)
|
|
||||||
{
|
|
||||||
if ( ((*this)[0] == '\"') && ((*this)[m_len - 1] == '\"') )
|
|
||||||
{
|
|
||||||
return mid(1, m_len - 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::find_left(const char* p, bool case_sensitive) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
const int p_len = (int)strlen(p);
|
|
||||||
|
|
||||||
for (int i = 0; i <= (m_len - p_len); i++)
|
|
||||||
if ((case_sensitive ? strncmp : _strnicmp)(p, &m_pStr[i], p_len) == 0)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dynamic_string::contains(const char* p, bool case_sensitive) const
|
|
||||||
{
|
|
||||||
return find_left(p, case_sensitive) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint dynamic_string::count_char(char c) const
|
|
||||||
{
|
|
||||||
uint count = 0;
|
|
||||||
for (uint i = 0; i < m_len; i++)
|
|
||||||
if (m_pStr[i] == c)
|
|
||||||
count++;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::find_left(char c) const
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_len; i++)
|
|
||||||
if (m_pStr[i] == c)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::find_right(char c) const
|
|
||||||
{
|
|
||||||
for (int i = (int)m_len - 1; i >= 0; i--)
|
|
||||||
if (m_pStr[i] == c)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::find_right(const char* p, bool case_sensitive) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
const int p_len = (int)strlen(p);
|
|
||||||
|
|
||||||
for (int i = m_len - p_len; i >= 0; i--)
|
|
||||||
if ((case_sensitive ? strncmp : _strnicmp)(p, &m_pStr[i], p_len) == 0)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::trim()
|
|
||||||
{
|
|
||||||
int s, e;
|
|
||||||
for (s = 0; s < (int)m_len; s++)
|
|
||||||
if (!isspace(m_pStr[s]))
|
|
||||||
break;
|
|
||||||
|
|
||||||
for (e = m_len - 1; e > s; e--)
|
|
||||||
if (!isspace(m_pStr[e]))
|
|
||||||
break;
|
|
||||||
|
|
||||||
return crop(s, e - s + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::trim_crlf()
|
|
||||||
{
|
|
||||||
int s = 0, e;
|
|
||||||
|
|
||||||
for (e = m_len - 1; e > s; e--)
|
|
||||||
if ((m_pStr[e] != 13) && (m_pStr[e] != 10))
|
|
||||||
break;
|
|
||||||
|
|
||||||
return crop(s, e - s + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_string& dynamic_string::remap(int from_char, int to_char)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_len; i++)
|
|
||||||
if (m_pStr[i] == from_char)
|
|
||||||
m_pStr[i] = (char)to_char;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CRNLIB_BUILD_DEBUG
|
|
||||||
void dynamic_string::check() const
|
|
||||||
{
|
|
||||||
if (!m_pStr)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(!m_buf_size && !m_len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_buf_size);
|
|
||||||
CRNLIB_ASSERT((m_buf_size == cUINT16_MAX) || math::is_power_of_2((uint32)m_buf_size));
|
|
||||||
CRNLIB_ASSERT(m_len < m_buf_size);
|
|
||||||
CRNLIB_ASSERT(!m_pStr[m_len]);
|
|
||||||
#if CRNLIB_SLOW_STRING_LEN_CHECKS
|
|
||||||
CRNLIB_ASSERT(strlen(m_pStr) == m_len);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool dynamic_string::ensure_buf(uint len, bool preserve_contents)
|
|
||||||
{
|
|
||||||
uint buf_size_needed = len + 1;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(buf_size_needed <= cUINT16_MAX);
|
|
||||||
|
|
||||||
if (buf_size_needed <= cUINT16_MAX)
|
|
||||||
{
|
|
||||||
if (buf_size_needed > m_buf_size)
|
|
||||||
expand_buf(buf_size_needed, preserve_contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_buf_size >= buf_size_needed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dynamic_string::expand_buf(uint new_buf_size, bool preserve_contents)
|
|
||||||
{
|
|
||||||
new_buf_size = math::minimum<uint>(cUINT16_MAX, math::next_pow2(math::maximum<uint>(m_buf_size, new_buf_size)));
|
|
||||||
|
|
||||||
if (new_buf_size != m_buf_size)
|
|
||||||
{
|
|
||||||
char* p = crnlib_new_array<char>(new_buf_size);
|
|
||||||
|
|
||||||
if (preserve_contents)
|
|
||||||
memcpy(p, get_ptr_priv(), m_len + 1);
|
|
||||||
|
|
||||||
crnlib_delete_array(m_pStr);
|
|
||||||
m_pStr = p;
|
|
||||||
|
|
||||||
m_buf_size = static_cast<uint16>(new_buf_size);
|
|
||||||
|
|
||||||
if (preserve_contents)
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_buf_size >= new_buf_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dynamic_string::swap(dynamic_string& other)
|
|
||||||
{
|
|
||||||
utils::swap(other.m_buf_size, m_buf_size);
|
|
||||||
utils::swap(other.m_len, m_len);
|
|
||||||
utils::swap(other.m_pStr, m_pStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::serialize(void* pBuf, uint buf_size, bool little_endian) const
|
|
||||||
{
|
|
||||||
uint buf_left = buf_size;
|
|
||||||
|
|
||||||
//if (m_len > cUINT16_MAX)
|
|
||||||
// return -1;
|
|
||||||
CRNLIB_ASSUME(sizeof(m_len) == sizeof(uint16));
|
|
||||||
|
|
||||||
if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (buf_left < m_len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memcpy(pBuf, get_ptr(), m_len);
|
|
||||||
|
|
||||||
buf_left -= m_len;
|
|
||||||
|
|
||||||
return buf_size - buf_left;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dynamic_string::deserialize(const void* pBuf, uint buf_size, bool little_endian)
|
|
||||||
{
|
|
||||||
uint buf_left = buf_size;
|
|
||||||
|
|
||||||
if (buf_left < sizeof(uint16)) return -1;
|
|
||||||
|
|
||||||
uint16 l;
|
|
||||||
if (!utils::read_obj(l, pBuf, buf_left, little_endian))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (buf_left < l)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
set_from_buf(pBuf, l);
|
|
||||||
|
|
||||||
buf_left -= l;
|
|
||||||
|
|
||||||
return buf_size - buf_left;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dynamic_string::translate_lf_to_crlf()
|
|
||||||
{
|
|
||||||
if (find_left(0x0A) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
dynamic_string tmp;
|
|
||||||
tmp.ensure_buf(m_len + 2);
|
|
||||||
|
|
||||||
// normal sequence is 0x0D 0x0A (CR LF, \r\n)
|
|
||||||
|
|
||||||
int prev_char = -1;
|
|
||||||
for (uint i = 0; i < get_len(); i++)
|
|
||||||
{
|
|
||||||
const int cur_char = (*this)[i];
|
|
||||||
|
|
||||||
if ((cur_char == 0x0A) && (prev_char != 0x0D))
|
|
||||||
tmp.append_char(0x0D);
|
|
||||||
|
|
||||||
tmp.append_char(cur_char);
|
|
||||||
|
|
||||||
prev_char = cur_char;
|
|
||||||
}
|
|
||||||
|
|
||||||
swap(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,173 +0,0 @@
|
||||||
// File: crn_dynamic_string.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
enum { cMaxDynamicStringLen = cUINT16_MAX - 1 };
|
|
||||||
class dynamic_string
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline dynamic_string() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
|
|
||||||
dynamic_string(eVarArg dummy, const char* p, ...);
|
|
||||||
dynamic_string(const char* p);
|
|
||||||
dynamic_string(const char* p, uint len);
|
|
||||||
dynamic_string(const dynamic_string& other);
|
|
||||||
|
|
||||||
inline ~dynamic_string() { if (m_pStr) crnlib_delete_array(m_pStr); }
|
|
||||||
|
|
||||||
// Truncates the string to 0 chars and frees the buffer.
|
|
||||||
void clear();
|
|
||||||
void optimize();
|
|
||||||
|
|
||||||
// Truncates the string to 0 chars, but does not free the buffer.
|
|
||||||
void empty();
|
|
||||||
inline const char *assume_ownership() { const char *p = m_pStr; m_pStr = NULL; m_len = 0; m_buf_size = 0; return p; }
|
|
||||||
|
|
||||||
inline uint get_len() const { return m_len; }
|
|
||||||
inline bool is_empty() const { return !m_len; }
|
|
||||||
|
|
||||||
inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; }
|
|
||||||
inline const char* c_str() const { return get_ptr(); }
|
|
||||||
|
|
||||||
inline const char* get_ptr_raw() const { return m_pStr; }
|
|
||||||
inline char* get_ptr_raw() { return m_pStr; }
|
|
||||||
|
|
||||||
inline char front() const { return m_len ? m_pStr[0] : '\0'; }
|
|
||||||
inline char back() const { return m_len ? m_pStr[m_len - 1] : '\0'; }
|
|
||||||
|
|
||||||
inline char operator[] (uint i) const { CRNLIB_ASSERT(i <= m_len); return get_ptr()[i]; }
|
|
||||||
|
|
||||||
inline operator size_t() const { return fast_hash(get_ptr(), m_len) ^ fast_hash(&m_len, sizeof(m_len)); }
|
|
||||||
|
|
||||||
int compare(const char* p, bool case_sensitive = false) const;
|
|
||||||
int compare(const dynamic_string& rhs, bool case_sensitive = false) const;
|
|
||||||
|
|
||||||
inline bool operator== (const dynamic_string& rhs) const { return compare(rhs) == 0; }
|
|
||||||
inline bool operator== (const char* p) const { return compare(p) == 0; }
|
|
||||||
|
|
||||||
inline bool operator!= (const dynamic_string& rhs) const { return compare(rhs) != 0; }
|
|
||||||
inline bool operator!= (const char* p) const { return compare(p) != 0; }
|
|
||||||
|
|
||||||
inline bool operator< (const dynamic_string& rhs) const { return compare(rhs) < 0; }
|
|
||||||
inline bool operator< (const char* p) const { return compare(p) < 0; }
|
|
||||||
|
|
||||||
inline bool operator> (const dynamic_string& rhs) const { return compare(rhs) > 0; }
|
|
||||||
inline bool operator> (const char* p) const { return compare(p) > 0; }
|
|
||||||
|
|
||||||
inline bool operator<= (const dynamic_string& rhs) const { return compare(rhs) <= 0; }
|
|
||||||
inline bool operator<= (const char* p) const { return compare(p) <= 0; }
|
|
||||||
|
|
||||||
inline bool operator>= (const dynamic_string& rhs) const { return compare(rhs) >= 0; }
|
|
||||||
inline bool operator>= (const char* p) const { return compare(p) >= 0; }
|
|
||||||
|
|
||||||
friend inline bool operator== (const char* p, const dynamic_string& rhs) { return rhs.compare(p) == 0; }
|
|
||||||
|
|
||||||
dynamic_string& set(const char* p, uint max_len = UINT_MAX);
|
|
||||||
dynamic_string& set(const dynamic_string& other, uint max_len = UINT_MAX);
|
|
||||||
|
|
||||||
bool set_len(uint new_len, char fill_char = ' ');
|
|
||||||
|
|
||||||
// Set from non-zero terminated buffer.
|
|
||||||
dynamic_string& set_from_buf(const void* pBuf, uint buf_size);
|
|
||||||
|
|
||||||
dynamic_string& operator= (const dynamic_string& rhs) { return set(rhs); }
|
|
||||||
dynamic_string& operator= (const char* p) { return set(p); }
|
|
||||||
|
|
||||||
dynamic_string& set_char(uint index, char c);
|
|
||||||
dynamic_string& append_char(char c);
|
|
||||||
dynamic_string& append_char(int c) { CRNLIB_ASSERT((c >= 0) && (c <= 255)); return append_char(static_cast<char>(c)); }
|
|
||||||
dynamic_string& truncate(uint new_len);
|
|
||||||
dynamic_string& tolower();
|
|
||||||
dynamic_string& toupper();
|
|
||||||
|
|
||||||
dynamic_string& append(const char* p);
|
|
||||||
dynamic_string& append(const dynamic_string& other);
|
|
||||||
dynamic_string& operator += (const char* p) { return append(p); }
|
|
||||||
dynamic_string& operator += (const dynamic_string& other) { return append(other); }
|
|
||||||
|
|
||||||
friend dynamic_string operator+ (const char* p, const dynamic_string& a);
|
|
||||||
friend dynamic_string operator+ (const dynamic_string& a, const char* p);
|
|
||||||
friend dynamic_string operator+ (const dynamic_string& a, const dynamic_string& b);
|
|
||||||
|
|
||||||
dynamic_string& format_args(const char* p, va_list args);
|
|
||||||
dynamic_string& format(const char* p, ...);
|
|
||||||
|
|
||||||
dynamic_string& crop(uint start, uint len);
|
|
||||||
dynamic_string& substring(uint start, uint end);
|
|
||||||
dynamic_string& left(uint len);
|
|
||||||
dynamic_string& mid(uint start, uint len);
|
|
||||||
dynamic_string& right(uint start);
|
|
||||||
dynamic_string& tail(uint num);
|
|
||||||
|
|
||||||
dynamic_string& unquote();
|
|
||||||
|
|
||||||
uint count_char(char c) const;
|
|
||||||
|
|
||||||
int find_left(const char* p, bool case_sensitive = false) const;
|
|
||||||
int find_left(char c) const;
|
|
||||||
|
|
||||||
int find_right(char c) const;
|
|
||||||
int find_right(const char* p, bool case_sensitive = false) const;
|
|
||||||
|
|
||||||
bool contains(const char* p, bool case_sensitive = false) const;
|
|
||||||
|
|
||||||
dynamic_string& trim();
|
|
||||||
dynamic_string& trim_crlf();
|
|
||||||
|
|
||||||
dynamic_string& remap(int from_char, int to_char);
|
|
||||||
|
|
||||||
void swap(dynamic_string& other);
|
|
||||||
|
|
||||||
// Returns -1 on failure, or the number of bytes written.
|
|
||||||
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
|
|
||||||
|
|
||||||
// Returns -1 on failure, or the number of bytes read.
|
|
||||||
int deserialize(const void* pBuf, uint buf_size, bool little_endian);
|
|
||||||
|
|
||||||
void translate_lf_to_crlf();
|
|
||||||
|
|
||||||
static inline char *create_raw_buffer(uint& buf_size_in_chars);
|
|
||||||
static inline void free_raw_buffer(char *p) { crnlib_delete_array(p); }
|
|
||||||
dynamic_string& set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars);
|
|
||||||
private:
|
|
||||||
uint16 m_buf_size;
|
|
||||||
uint16 m_len;
|
|
||||||
char* m_pStr;
|
|
||||||
|
|
||||||
#ifdef CRNLIB_BUILD_DEBUG
|
|
||||||
void check() const;
|
|
||||||
#else
|
|
||||||
inline void check() const { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool expand_buf(uint new_buf_size, bool preserve_contents);
|
|
||||||
|
|
||||||
const char* get_ptr_priv() const { return m_pStr ? m_pStr : ""; }
|
|
||||||
char* get_ptr_priv() { return (char*)(m_pStr ? m_pStr : ""); }
|
|
||||||
|
|
||||||
bool ensure_buf(uint len, bool preserve_contents = true);
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<dynamic_string> dynamic_string_array;
|
|
||||||
|
|
||||||
extern dynamic_string g_empty_dynamic_string;
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_MOVABLE(dynamic_string);
|
|
||||||
|
|
||||||
inline void swap (dynamic_string& a, dynamic_string& b)
|
|
||||||
{
|
|
||||||
a.swap(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char *dynamic_string::create_raw_buffer(uint& buf_size_in_chars)
|
|
||||||
{
|
|
||||||
if (buf_size_in_chars > cUINT16_MAX)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
buf_size_in_chars = math::minimum<uint>(cUINT16_MAX, math::next_pow2(buf_size_in_chars));
|
|
||||||
return crnlib_new_array<char>(buf_size_in_chars);
|
|
||||||
}
|
|
||||||
} // namespace crnlib
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,609 +0,0 @@
|
||||||
// File: crn_etc.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "../inc/crnlib.h"
|
|
||||||
#include "crn_dxt.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
enum etc_constants
|
|
||||||
{
|
|
||||||
cETC1BytesPerBlock = 8U,
|
|
||||||
|
|
||||||
cETC1SelectorBits = 2U,
|
|
||||||
cETC1SelectorValues = 1U << cETC1SelectorBits,
|
|
||||||
cETC1SelectorMask = cETC1SelectorValues - 1U,
|
|
||||||
|
|
||||||
cETC1BlockShift = 2U,
|
|
||||||
cETC1BlockSize = 1U << cETC1BlockShift,
|
|
||||||
|
|
||||||
cETC1LSBSelectorIndicesBitOffset = 0,
|
|
||||||
cETC1MSBSelectorIndicesBitOffset = 16,
|
|
||||||
|
|
||||||
cETC1FlipBitOffset = 32,
|
|
||||||
cETC1DiffBitOffset = 33,
|
|
||||||
|
|
||||||
cETC1IntenModifierNumBits = 3,
|
|
||||||
cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
|
|
||||||
cETC1RightIntenModifierTableBitOffset = 34,
|
|
||||||
cETC1LeftIntenModifierTableBitOffset = 37,
|
|
||||||
|
|
||||||
// Base+Delta encoding (5 bit bases, 3 bit delta)
|
|
||||||
cETC1BaseColorCompNumBits = 5,
|
|
||||||
cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
|
|
||||||
|
|
||||||
cETC1DeltaColorCompNumBits = 3,
|
|
||||||
cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
|
|
||||||
cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
|
|
||||||
|
|
||||||
cETC1BaseColor5RBitOffset = 59,
|
|
||||||
cETC1BaseColor5GBitOffset = 51,
|
|
||||||
cETC1BaseColor5BBitOffset = 43,
|
|
||||||
|
|
||||||
cETC1DeltaColor3RBitOffset = 56,
|
|
||||||
cETC1DeltaColor3GBitOffset = 48,
|
|
||||||
cETC1DeltaColor3BBitOffset = 40,
|
|
||||||
|
|
||||||
// Absolute (non-delta) encoding (two 4-bit per component bases)
|
|
||||||
cETC1AbsColorCompNumBits = 4,
|
|
||||||
cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
|
|
||||||
|
|
||||||
cETC1AbsColor4R1BitOffset = 60,
|
|
||||||
cETC1AbsColor4G1BitOffset = 52,
|
|
||||||
cETC1AbsColor4B1BitOffset = 44,
|
|
||||||
|
|
||||||
cETC1AbsColor4R2BitOffset = 56,
|
|
||||||
cETC1AbsColor4G2BitOffset = 48,
|
|
||||||
cETC1AbsColor4B2BitOffset = 40,
|
|
||||||
|
|
||||||
cETC1ColorDeltaMin = -4,
|
|
||||||
cETC1ColorDeltaMax = 3,
|
|
||||||
|
|
||||||
// Delta3:
|
|
||||||
// 0 1 2 3 4 5 6 7
|
|
||||||
// 000 001 010 011 100 101 110 111
|
|
||||||
// 0 1 2 3 -4 -3 -2 -1
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues];
|
|
||||||
extern const uint8 g_etc1_to_selector_index[cETC1SelectorValues];
|
|
||||||
extern const uint8 g_selector_index_to_etc1[cETC1SelectorValues];
|
|
||||||
|
|
||||||
struct etc1_coord2
|
|
||||||
{
|
|
||||||
uint8 m_x, m_y;
|
|
||||||
};
|
|
||||||
extern const etc1_coord2 g_etc1_pixel_coords[2][2][8]; // [flipped][subblock][subblock_pixel]
|
|
||||||
|
|
||||||
struct etc1_block
|
|
||||||
{
|
|
||||||
// big endian uint64:
|
|
||||||
// bit ofs: 56 48 40 32 24 16 8 0
|
|
||||||
// byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint64 m_uint64;
|
|
||||||
uint8 m_bytes[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8 m_low_color[2];
|
|
||||||
uint8 m_high_color[2];
|
|
||||||
|
|
||||||
enum { cNumSelectorBytes = 4 };
|
|
||||||
uint8 m_selectors[cNumSelectorBytes];
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
utils::zero_this(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_general_bits(uint ofs, uint num) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((ofs + num) <= 64U);
|
|
||||||
CRNLIB_ASSERT(num && (num < 32U));
|
|
||||||
return (utils::read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_general_bits(uint ofs, uint num, uint bits)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((ofs + num) <= 64U);
|
|
||||||
CRNLIB_ASSERT(num && (num < 32U));
|
|
||||||
|
|
||||||
uint64 x = utils::read_be64(&m_uint64);
|
|
||||||
uint64 msk = ((1ULL << static_cast<uint64>(num)) - 1ULL) << static_cast<uint64>(ofs);
|
|
||||||
x &= ~msk;
|
|
||||||
x |= (static_cast<uint64>(bits) << static_cast<uint64>(ofs));
|
|
||||||
utils::write_be64(&m_uint64, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_byte_bits(uint ofs, uint num) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((ofs + num) <= 64U);
|
|
||||||
CRNLIB_ASSERT(num && (num <= 8U));
|
|
||||||
CRNLIB_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
|
|
||||||
const uint byte_ofs = 7 - (ofs >> 3);
|
|
||||||
const uint byte_bit_ofs = ofs & 7;
|
|
||||||
return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_byte_bits(uint ofs, uint num, uint bits)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((ofs + num) <= 64U);
|
|
||||||
CRNLIB_ASSERT(num && (num < 32U));
|
|
||||||
CRNLIB_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
|
|
||||||
CRNLIB_ASSERT(bits < (1U << num));
|
|
||||||
const uint byte_ofs = 7 - (ofs >> 3);
|
|
||||||
const uint byte_bit_ofs = ofs & 7;
|
|
||||||
const uint mask = (1 << num) - 1;
|
|
||||||
m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
|
|
||||||
m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// false = left/right subblocks
|
|
||||||
// true = upper/lower subblocks
|
|
||||||
inline bool get_flip_bit() const
|
|
||||||
{
|
|
||||||
return (m_bytes[3] & 1) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_flip_bit(bool flip)
|
|
||||||
{
|
|
||||||
m_bytes[3] &= ~1;
|
|
||||||
m_bytes[3] |= static_cast<uint8>(flip);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool get_diff_bit() const
|
|
||||||
{
|
|
||||||
return (m_bytes[3] & 2) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_diff_bit(bool diff)
|
|
||||||
{
|
|
||||||
m_bytes[3] &= ~2;
|
|
||||||
m_bytes[3] |= (static_cast<uint>(diff) << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns intensity modifier table (0-7) used by subblock subblock_id.
|
|
||||||
// subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
|
|
||||||
inline uint get_inten_table(uint subblock_id) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(subblock_id < 2);
|
|
||||||
const uint ofs = subblock_id ? 2 : 5;
|
|
||||||
return (m_bytes[3] >> ofs) & 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
|
|
||||||
inline void set_inten_table(uint subblock_id, uint t)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(subblock_id < 2);
|
|
||||||
CRNLIB_ASSERT(t < 8);
|
|
||||||
const uint ofs = subblock_id ? 2 : 5;
|
|
||||||
m_bytes[3] &= ~(7 << ofs);
|
|
||||||
m_bytes[3] |= (t << ofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
|
|
||||||
inline uint get_selector(uint x, uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x | y) < 4);
|
|
||||||
|
|
||||||
const uint bit_index = x * 4 + y;
|
|
||||||
const uint byte_bit_ofs = bit_index & 7;
|
|
||||||
const uint8 *p = &m_bytes[7 - (bit_index >> 3)];
|
|
||||||
const uint lsb = (p[0] >> byte_bit_ofs) & 1;
|
|
||||||
const uint msb = (p[-2] >> byte_bit_ofs) & 1;
|
|
||||||
const uint val = lsb | (msb << 1);
|
|
||||||
|
|
||||||
return g_etc1_to_selector_index[val];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
|
|
||||||
inline void set_selector(uint x, uint y, uint val)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x | y | val) < 4);
|
|
||||||
const uint bit_index = x * 4 + y;
|
|
||||||
|
|
||||||
uint8 *p = &m_bytes[7 - (bit_index >> 3)];
|
|
||||||
|
|
||||||
const uint byte_bit_ofs = bit_index & 7;
|
|
||||||
const uint mask = 1 << byte_bit_ofs;
|
|
||||||
|
|
||||||
const uint etc1_val = g_selector_index_to_etc1[val];
|
|
||||||
|
|
||||||
const uint lsb = etc1_val & 1;
|
|
||||||
const uint msb = etc1_val >> 1;
|
|
||||||
|
|
||||||
p[0] &= ~mask;
|
|
||||||
p[0] |= (lsb << byte_bit_ofs);
|
|
||||||
|
|
||||||
p[-2] &= ~mask;
|
|
||||||
p[-2] |= (msb << byte_bit_ofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_base4_color(uint idx, uint16 c)
|
|
||||||
{
|
|
||||||
if (idx)
|
|
||||||
{
|
|
||||||
set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
|
|
||||||
set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
|
|
||||||
set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
|
|
||||||
set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
|
|
||||||
set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 get_base4_color(uint idx) const
|
|
||||||
{
|
|
||||||
uint r, g, b;
|
|
||||||
if (idx)
|
|
||||||
{
|
|
||||||
r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
|
|
||||||
g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
|
|
||||||
b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
|
|
||||||
g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
|
|
||||||
b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
|
|
||||||
}
|
|
||||||
return static_cast<uint16>(b | (g << 4U) | (r << 8U));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_base5_color(uint16 c)
|
|
||||||
{
|
|
||||||
set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
|
|
||||||
set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
|
|
||||||
set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 get_base5_color() const
|
|
||||||
{
|
|
||||||
const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
|
|
||||||
const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
|
|
||||||
const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
|
|
||||||
return static_cast<uint16>(b | (g << 5U) | (r << 10U));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_delta3_color(uint16 c)
|
|
||||||
{
|
|
||||||
set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
|
|
||||||
set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
|
|
||||||
set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 get_delta3_color() const
|
|
||||||
{
|
|
||||||
const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
|
|
||||||
const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
|
|
||||||
const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
|
|
||||||
return static_cast<uint16>(b | (g << 3U) | (r << 6U));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base color 5
|
|
||||||
static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U);
|
|
||||||
static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
|
|
||||||
|
|
||||||
static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
|
|
||||||
static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
|
|
||||||
|
|
||||||
static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
|
|
||||||
static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
|
|
||||||
|
|
||||||
// Delta color 3
|
|
||||||
// Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
|
|
||||||
static uint16 pack_delta3(const color_quad_i16& color);
|
|
||||||
static uint16 pack_delta3(int r, int g, int b);
|
|
||||||
|
|
||||||
// Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
|
|
||||||
static color_quad_i16 unpack_delta3(uint16 packed_delta3);
|
|
||||||
static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3);
|
|
||||||
|
|
||||||
// Abs color 4
|
|
||||||
static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U);
|
|
||||||
static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
|
|
||||||
|
|
||||||
static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
|
|
||||||
static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled);
|
|
||||||
|
|
||||||
// subblock colors
|
|
||||||
static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx);
|
|
||||||
static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
|
|
||||||
static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx);
|
|
||||||
|
|
||||||
static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4)
|
|
||||||
{
|
|
||||||
if (color4)
|
|
||||||
{
|
|
||||||
dst.r = src.r | (src.r << 4);
|
|
||||||
dst.g = src.g | (src.g << 4);
|
|
||||||
dst.b = src.b | (src.b << 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dst.r = (src.r >> 2) | (src.r << 3);
|
|
||||||
dst.g = (src.g >> 2) | (src.g << 3);
|
|
||||||
dst.b = (src.b >> 2) | (src.b << 3);
|
|
||||||
}
|
|
||||||
dst.a = src.a;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CRNLIB_DEFINE_BITWISE_COPYABLE(etc1_block);
|
|
||||||
|
|
||||||
// Returns false if the block is invalid (it will still be unpacked with clamping).
|
|
||||||
bool unpack_etc1(const etc1_block& block, color_quad_u8 *pDst, bool preserve_alpha = false);
|
|
||||||
|
|
||||||
enum crn_etc_quality
|
|
||||||
{
|
|
||||||
cCRNETCQualityFast,
|
|
||||||
cCRNETCQualityMedium,
|
|
||||||
cCRNETCQualitySlow,
|
|
||||||
|
|
||||||
cCRNETCQualityTotal,
|
|
||||||
|
|
||||||
cCRNETCQualityForceDWORD = 0xFFFFFFFF
|
|
||||||
};
|
|
||||||
|
|
||||||
struct crn_etc1_pack_params
|
|
||||||
{
|
|
||||||
crn_etc_quality m_quality;
|
|
||||||
bool m_perceptual;
|
|
||||||
bool m_dithering;
|
|
||||||
|
|
||||||
inline crn_etc1_pack_params()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_quality = cCRNETCQualitySlow;
|
|
||||||
m_perceptual = true;
|
|
||||||
m_dithering = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct etc1_solution_coordinates
|
|
||||||
{
|
|
||||||
inline etc1_solution_coordinates() :
|
|
||||||
m_unscaled_color(0, 0, 0, 0),
|
|
||||||
m_inten_table(0),
|
|
||||||
m_color4(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4) :
|
|
||||||
m_unscaled_color(r, g, b, 255),
|
|
||||||
m_inten_table(inten_table),
|
|
||||||
m_color4(color4)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline etc1_solution_coordinates(const color_quad_u8& c, uint inten_table, bool color4) :
|
|
||||||
m_unscaled_color(c),
|
|
||||||
m_inten_table(inten_table),
|
|
||||||
m_color4(color4)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline etc1_solution_coordinates(const etc1_solution_coordinates& other)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline etc1_solution_coordinates& operator= (const etc1_solution_coordinates& rhs)
|
|
||||||
{
|
|
||||||
m_unscaled_color = rhs.m_unscaled_color;
|
|
||||||
m_inten_table = rhs.m_inten_table;
|
|
||||||
m_color4 = rhs.m_color4;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
m_unscaled_color.clear();
|
|
||||||
m_inten_table = 0;
|
|
||||||
m_color4 = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_quad_u8 get_scaled_color() const
|
|
||||||
{
|
|
||||||
int br, bg, bb;
|
|
||||||
if (m_color4)
|
|
||||||
{
|
|
||||||
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
|
|
||||||
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
|
|
||||||
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
|
|
||||||
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
|
|
||||||
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
|
|
||||||
}
|
|
||||||
return color_quad_u8(br, bg, bb);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void get_block_colors(color_quad_u8* pBlock_colors)
|
|
||||||
{
|
|
||||||
int br, bg, bb;
|
|
||||||
if (m_color4)
|
|
||||||
{
|
|
||||||
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
|
|
||||||
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
|
|
||||||
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
|
|
||||||
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
|
|
||||||
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
|
|
||||||
}
|
|
||||||
const int* pInten_table = g_etc1_inten_tables[m_inten_table];
|
|
||||||
pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]);
|
|
||||||
pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]);
|
|
||||||
pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]);
|
|
||||||
pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
color_quad_u8 m_unscaled_color;
|
|
||||||
uint m_inten_table;
|
|
||||||
bool m_color4;
|
|
||||||
};
|
|
||||||
|
|
||||||
class etc1_optimizer
|
|
||||||
{
|
|
||||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(etc1_optimizer);
|
|
||||||
|
|
||||||
public:
|
|
||||||
etc1_optimizer()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_pParams = NULL;
|
|
||||||
m_pResult = NULL;
|
|
||||||
m_pSorted_luma = NULL;
|
|
||||||
m_pSorted_luma_indices = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct params : crn_etc1_pack_params
|
|
||||||
{
|
|
||||||
params()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
params(const crn_etc1_pack_params& base_params) :
|
|
||||||
crn_etc1_pack_params(base_params)
|
|
||||||
{
|
|
||||||
clear_optimizer_params();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
crn_etc1_pack_params::clear();
|
|
||||||
clear_optimizer_params();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_optimizer_params()
|
|
||||||
{
|
|
||||||
m_num_src_pixels = 0;
|
|
||||||
m_pSrc_pixels = 0;
|
|
||||||
|
|
||||||
m_use_color4 = false;
|
|
||||||
static const int s_default_scan_delta[] = { 0 };
|
|
||||||
m_pScan_deltas = s_default_scan_delta;
|
|
||||||
m_scan_delta_size = 1;
|
|
||||||
|
|
||||||
m_base_color5.clear();
|
|
||||||
m_constrain_against_base_color5 = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint m_num_src_pixels;
|
|
||||||
const color_quad_u8* m_pSrc_pixels;
|
|
||||||
|
|
||||||
bool m_use_color4;
|
|
||||||
const int* m_pScan_deltas;
|
|
||||||
uint m_scan_delta_size;
|
|
||||||
|
|
||||||
color_quad_u8 m_base_color5;
|
|
||||||
bool m_constrain_against_base_color5;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct results
|
|
||||||
{
|
|
||||||
uint64 m_error;
|
|
||||||
color_quad_u8 m_block_color_unscaled;
|
|
||||||
uint m_block_inten_table;
|
|
||||||
uint m_n;
|
|
||||||
uint8* m_pSelectors;
|
|
||||||
bool m_block_color4;
|
|
||||||
|
|
||||||
inline results& operator= (const results& rhs)
|
|
||||||
{
|
|
||||||
m_block_color_unscaled = rhs.m_block_color_unscaled;
|
|
||||||
m_block_color4 = rhs.m_block_color4;
|
|
||||||
m_block_inten_table = rhs.m_block_inten_table;
|
|
||||||
m_error = rhs.m_error;
|
|
||||||
CRNLIB_ASSERT(m_n == rhs.m_n);
|
|
||||||
memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void init(const params& params, results& result);
|
|
||||||
bool compute();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct potential_solution
|
|
||||||
{
|
|
||||||
potential_solution() : m_coords(), m_error(cUINT64_MAX), m_valid(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
etc1_solution_coordinates m_coords;
|
|
||||||
crnlib::vector<uint8> m_selectors;
|
|
||||||
uint64 m_error;
|
|
||||||
bool m_valid;
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_coords.clear();
|
|
||||||
m_selectors.resize(0);
|
|
||||||
m_error = cUINT64_MAX;
|
|
||||||
m_valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool are_selectors_all_equal() const
|
|
||||||
{
|
|
||||||
if (m_selectors.empty())
|
|
||||||
return false;
|
|
||||||
const uint s = m_selectors[0];
|
|
||||||
for (uint i = 1; i < m_selectors.size(); i++)
|
|
||||||
if (m_selectors[i] != s)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const params* m_pParams;
|
|
||||||
results* m_pResult;
|
|
||||||
|
|
||||||
int m_limit;
|
|
||||||
|
|
||||||
vec3F m_avg_color;
|
|
||||||
int m_br, m_bg, m_bb;
|
|
||||||
crnlib::vector<uint16> m_luma;
|
|
||||||
crnlib::vector<uint32> m_sorted_luma[2];
|
|
||||||
const uint32* m_pSorted_luma_indices;
|
|
||||||
uint32* m_pSorted_luma;
|
|
||||||
|
|
||||||
crnlib::vector<uint8> m_selectors;
|
|
||||||
crnlib::vector<uint8> m_best_selectors;
|
|
||||||
|
|
||||||
potential_solution m_best_solution;
|
|
||||||
potential_solution m_trial_solution;
|
|
||||||
crnlib::vector<uint8> m_temp_selectors;
|
|
||||||
|
|
||||||
bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
|
|
||||||
bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct pack_etc1_block_context
|
|
||||||
{
|
|
||||||
etc1_optimizer m_optimizer;
|
|
||||||
};
|
|
||||||
|
|
||||||
void pack_etc1_block_init();
|
|
||||||
|
|
||||||
uint64 pack_etc1_block(etc1_block& block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params, pack_etc1_block_context& context);
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,578 +0,0 @@
|
||||||
// File: crn_file_utils.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_file_utils.h"
|
|
||||||
#include "crn_strutils.h"
|
|
||||||
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <direct.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
#if CRNLIB_USE_WIN32_API
|
|
||||||
bool file_utils::is_read_only(const char* pFilename)
|
|
||||||
{
|
|
||||||
uint32 dst_file_attribs = GetFileAttributesA(pFilename);
|
|
||||||
if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return false;
|
|
||||||
if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::disable_read_only(const char* pFilename)
|
|
||||||
{
|
|
||||||
uint32 dst_file_attribs = GetFileAttributesA(pFilename);
|
|
||||||
if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return false;
|
|
||||||
if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
|
|
||||||
{
|
|
||||||
dst_file_attribs &= ~FILE_ATTRIBUTE_READONLY;
|
|
||||||
if (SetFileAttributesA(pFilename, dst_file_attribs))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename)
|
|
||||||
{
|
|
||||||
WIN32_FILE_ATTRIBUTE_DATA src_file_attribs;
|
|
||||||
const BOOL src_file_exists = GetFileAttributesExA(pSrcFilename, GetFileExInfoStandard, &src_file_attribs);
|
|
||||||
|
|
||||||
WIN32_FILE_ATTRIBUTE_DATA dst_file_attribs;
|
|
||||||
const BOOL dest_file_exists = GetFileAttributesExA(pDstFilename, GetFileExInfoStandard, &dst_file_attribs);
|
|
||||||
|
|
||||||
if ((dest_file_exists) && (src_file_exists))
|
|
||||||
{
|
|
||||||
LONG timeComp = CompareFileTime(&src_file_attribs.ftLastWriteTime, &dst_file_attribs.ftLastWriteTime);
|
|
||||||
if (timeComp < 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::does_file_exist(const char* pFilename)
|
|
||||||
{
|
|
||||||
const DWORD fullAttributes = GetFileAttributesA(pFilename);
|
|
||||||
|
|
||||||
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::does_dir_exist(const char* pDir)
|
|
||||||
{
|
|
||||||
//-- Get the file attributes.
|
|
||||||
DWORD fullAttributes = GetFileAttributesA(pDir);
|
|
||||||
|
|
||||||
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
|
|
||||||
{
|
|
||||||
file_size = 0;
|
|
||||||
|
|
||||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
|
||||||
|
|
||||||
if (0 == GetFileAttributesExA(pFilename, GetFileExInfoStandard, &attr))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
file_size = static_cast<uint64>(attr.nFileSizeLow) | (static_cast<uint64>(attr.nFileSizeHigh) << 32U);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#elif defined( __GNUC__ )
|
|
||||||
bool file_utils::is_read_only(const char* pFilename)
|
|
||||||
{
|
|
||||||
pFilename;
|
|
||||||
// TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::disable_read_only(const char* pFilename)
|
|
||||||
{
|
|
||||||
pFilename;
|
|
||||||
// TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename)
|
|
||||||
{
|
|
||||||
pSrcFilename, pDstFilename;
|
|
||||||
// TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::does_file_exist(const char* pFilename)
|
|
||||||
{
|
|
||||||
struct stat stat_buf;
|
|
||||||
int result = stat(pFilename, &stat_buf);
|
|
||||||
if (result)
|
|
||||||
return false;
|
|
||||||
if (S_ISREG(stat_buf.st_mode))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::does_dir_exist(const char* pDir)
|
|
||||||
{
|
|
||||||
struct stat stat_buf;
|
|
||||||
int result = stat(pDir, &stat_buf);
|
|
||||||
if (result)
|
|
||||||
return false;
|
|
||||||
if (S_ISDIR(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
|
|
||||||
{
|
|
||||||
file_size = 0;
|
|
||||||
struct stat stat_buf;
|
|
||||||
int result = stat(pFilename, &stat_buf);
|
|
||||||
if (result)
|
|
||||||
return false;
|
|
||||||
if (!S_ISREG(stat_buf.st_mode))
|
|
||||||
return false;
|
|
||||||
file_size = stat_buf.st_size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
bool file_utils::is_read_only(const char* pFilename)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::disable_read_only(const char* pFilename)
|
|
||||||
{
|
|
||||||
pFilename;
|
|
||||||
// TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::does_file_exist(const char* pFilename)
|
|
||||||
{
|
|
||||||
FILE* pFile;
|
|
||||||
crn_fopen(&pFile, pFilename, "rb");
|
|
||||||
if (!pFile)
|
|
||||||
return false;
|
|
||||||
fclose(pFile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::does_dir_exist(const char* pDir)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
|
|
||||||
{
|
|
||||||
FILE* pFile;
|
|
||||||
crn_fopen(&pFile, pFilename, "rb");
|
|
||||||
if (!pFile)
|
|
||||||
return false;
|
|
||||||
crn_fseek(pFile, 0, SEEK_END);
|
|
||||||
file_size = crn_ftell(pFile);
|
|
||||||
fclose(pFile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool file_utils::get_file_size(const char* pFilename, uint32& file_size)
|
|
||||||
{
|
|
||||||
uint64 file_size64;
|
|
||||||
if (!get_file_size(pFilename, file_size64))
|
|
||||||
{
|
|
||||||
file_size = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_size64 > cUINT32_MAX)
|
|
||||||
file_size64 = cUINT32_MAX;
|
|
||||||
|
|
||||||
file_size = static_cast<uint32>(file_size64);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::is_path_separator(char c)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
return (c == '/') || (c == '\\');
|
|
||||||
#else
|
|
||||||
return (c == '/');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::is_path_or_drive_separator(char c)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
return (c == '/') || (c == '\\') || (c == ':');
|
|
||||||
#else
|
|
||||||
return (c == '/');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::is_drive_separator(char c)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
return (c == ':');
|
|
||||||
#else
|
|
||||||
c;
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(p);
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
char drive_buf[_MAX_DRIVE];
|
|
||||||
char dir_buf[_MAX_DIR];
|
|
||||||
char fname_buf[_MAX_FNAME];
|
|
||||||
char ext_buf[_MAX_EXT];
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// Compiling with MSVC
|
|
||||||
errno_t error = _splitpath_s(p,
|
|
||||||
pDrive ? drive_buf : NULL, pDrive ? _MAX_DRIVE : 0,
|
|
||||||
pDir ? dir_buf : NULL, pDir ? _MAX_DIR : 0,
|
|
||||||
pFilename ? fname_buf : NULL, pFilename ? _MAX_FNAME : 0,
|
|
||||||
pExt ? ext_buf : NULL, pExt ? _MAX_EXT : 0);
|
|
||||||
if (error != 0)
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
// Compiling with MinGW
|
|
||||||
_splitpath(p,
|
|
||||||
pDrive ? drive_buf : NULL,
|
|
||||||
pDir ? dir_buf : NULL,
|
|
||||||
pFilename ? fname_buf : NULL,
|
|
||||||
pExt ? ext_buf : NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pDrive) *pDrive = drive_buf;
|
|
||||||
if (pDir) *pDir = dir_buf;
|
|
||||||
if (pFilename) *pFilename = fname_buf;
|
|
||||||
if (pExt) *pExt = ext_buf;
|
|
||||||
#else
|
|
||||||
char dirtmp[1024];
|
|
||||||
char nametmp[1024];
|
|
||||||
strcpy_safe(dirtmp, sizeof(dirtmp), p);
|
|
||||||
strcpy_safe(nametmp, sizeof(nametmp), p);
|
|
||||||
|
|
||||||
if (pDrive) pDrive->clear();
|
|
||||||
|
|
||||||
const char *pDirName = dirname(dirtmp);
|
|
||||||
if (!pDirName)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (pDir)
|
|
||||||
{
|
|
||||||
pDir->set(pDirName);
|
|
||||||
if ((!pDir->is_empty()) && (pDir->back() != '/'))
|
|
||||||
pDir->append_char('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *pBaseName = basename(nametmp);
|
|
||||||
if (!pBaseName)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (pFilename)
|
|
||||||
{
|
|
||||||
pFilename->set(pBaseName);
|
|
||||||
remove_extension(*pFilename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pExt)
|
|
||||||
{
|
|
||||||
pExt->set(pBaseName);
|
|
||||||
get_extension(*pExt);
|
|
||||||
*pExt = "." + *pExt;
|
|
||||||
}
|
|
||||||
#endif // #ifdef WIN32
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::split_path(const char* p, dynamic_string& path, dynamic_string& filename)
|
|
||||||
{
|
|
||||||
dynamic_string temp_drive, temp_path, temp_ext;
|
|
||||||
if (!split_path(p, &temp_drive, &temp_path, &filename, &temp_ext))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
filename += temp_ext;
|
|
||||||
|
|
||||||
combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::get_pathname(const char* p, dynamic_string& path)
|
|
||||||
{
|
|
||||||
dynamic_string temp_drive, temp_path;
|
|
||||||
if (!split_path(p, &temp_drive, &temp_path, NULL, NULL))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::get_filename(const char* p, dynamic_string& filename)
|
|
||||||
{
|
|
||||||
dynamic_string temp_ext;
|
|
||||||
if (!split_path(p, NULL, NULL, &filename, &temp_ext))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
filename += temp_ext;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB)
|
|
||||||
{
|
|
||||||
dynamic_string temp(pA);
|
|
||||||
if ((!temp.is_empty()) && (!is_path_separator(pB[0])))
|
|
||||||
{
|
|
||||||
char c = temp[temp.get_len() - 1];
|
|
||||||
if (!is_path_separator(c))
|
|
||||||
temp.append_char(CRNLIB_PATH_SEPERATOR_CHAR);
|
|
||||||
}
|
|
||||||
temp += pB;
|
|
||||||
dst.swap(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC)
|
|
||||||
{
|
|
||||||
combine_path(dst, pA, pB);
|
|
||||||
combine_path(dst, dst.get_ptr(), pC);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::full_path(dynamic_string& path)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
char buf[1024];
|
|
||||||
char* p = _fullpath(buf, path.get_ptr(), sizeof(buf));
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
char* p;
|
|
||||||
dynamic_string pn, fn;
|
|
||||||
split_path(path.get_ptr(), pn, fn);
|
|
||||||
if ((fn == ".") || (fn == ".."))
|
|
||||||
{
|
|
||||||
p = realpath(path.get_ptr(), buf);
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
path.set(buf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pn.is_empty())
|
|
||||||
pn = "./";
|
|
||||||
p = realpath(pn.get_ptr(), buf);
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
combine_path(path, buf, fn.get_ptr());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::get_extension(dynamic_string& filename)
|
|
||||||
{
|
|
||||||
int sep = -1;
|
|
||||||
#ifdef WIN32
|
|
||||||
sep = filename.find_right('\\');
|
|
||||||
#endif
|
|
||||||
if (sep < 0)
|
|
||||||
sep = filename.find_right('/');
|
|
||||||
|
|
||||||
int dot = filename.find_right('.');
|
|
||||||
if (dot < sep)
|
|
||||||
{
|
|
||||||
filename.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename.right(dot + 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::remove_extension(dynamic_string& filename)
|
|
||||||
{
|
|
||||||
int sep = -1;
|
|
||||||
#ifdef WIN32
|
|
||||||
sep = filename.find_right('\\');
|
|
||||||
#endif
|
|
||||||
if (sep < 0)
|
|
||||||
sep = filename.find_right('/');
|
|
||||||
|
|
||||||
int dot = filename.find_right('.');
|
|
||||||
if (dot < sep)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
filename.left(dot);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::create_path(const dynamic_string& fullpath)
|
|
||||||
{
|
|
||||||
bool got_unc = false; got_unc;
|
|
||||||
dynamic_string cur_path;
|
|
||||||
|
|
||||||
const int l = fullpath.get_len();
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
while (n < l)
|
|
||||||
{
|
|
||||||
const char c = fullpath.get_ptr()[n];
|
|
||||||
|
|
||||||
const bool sep = is_path_separator(c);
|
|
||||||
const bool back_sep = is_path_separator(cur_path.back());
|
|
||||||
const bool is_last_char = (n == (l - 1));
|
|
||||||
|
|
||||||
if ( ((sep) && (!back_sep)) || (is_last_char) )
|
|
||||||
{
|
|
||||||
if ((is_last_char) && (!sep))
|
|
||||||
cur_path.append_char(c);
|
|
||||||
|
|
||||||
bool valid = !cur_path.is_empty();
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
// reject obvious stuff (drives, beginning of UNC paths):
|
|
||||||
// c:\b\cool
|
|
||||||
// \\machine\blah
|
|
||||||
// \cool\blah
|
|
||||||
if ((cur_path.get_len() == 2) && (cur_path[1] == ':'))
|
|
||||||
valid = false;
|
|
||||||
else if ((cur_path.get_len() >= 2) && (cur_path[0] == '\\') && (cur_path[1] == '\\'))
|
|
||||||
{
|
|
||||||
if (!got_unc)
|
|
||||||
valid = false;
|
|
||||||
got_unc = true;
|
|
||||||
}
|
|
||||||
else if (cur_path == "\\")
|
|
||||||
valid = false;
|
|
||||||
#endif
|
|
||||||
if (cur_path == "/")
|
|
||||||
valid = false;
|
|
||||||
|
|
||||||
if ((valid) && (cur_path.get_len()))
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
_mkdir(cur_path.get_ptr());
|
|
||||||
#else
|
|
||||||
mkdir(cur_path.get_ptr(), S_IRWXU | S_IRWXG | S_IRWXO );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_path.append_char(c);
|
|
||||||
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_utils::trim_trailing_seperator(dynamic_string& path)
|
|
||||||
{
|
|
||||||
if ((path.get_len()) && (is_path_separator(path.back())))
|
|
||||||
path.truncate(path.get_len() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See http://www.codeproject.com/KB/string/wildcmp.aspx
|
|
||||||
int file_utils::wildcmp(const char* pWild, const char* pString)
|
|
||||||
{
|
|
||||||
const char* cp = NULL, *mp = NULL;
|
|
||||||
|
|
||||||
while ((*pString) && (*pWild != '*'))
|
|
||||||
{
|
|
||||||
if ((*pWild != *pString) && (*pWild != '?'))
|
|
||||||
return 0;
|
|
||||||
pWild++;
|
|
||||||
pString++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Either *pString=='\0' or *pWild='*' here.
|
|
||||||
|
|
||||||
while (*pString)
|
|
||||||
{
|
|
||||||
if (*pWild == '*')
|
|
||||||
{
|
|
||||||
if (!*++pWild)
|
|
||||||
return 1;
|
|
||||||
mp = pWild;
|
|
||||||
cp = pString+1;
|
|
||||||
}
|
|
||||||
else if ((*pWild == *pString) || (*pWild == '?'))
|
|
||||||
{
|
|
||||||
pWild++;
|
|
||||||
pString++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pWild = mp;
|
|
||||||
pString = cp++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*pWild == '*')
|
|
||||||
pWild++;
|
|
||||||
|
|
||||||
return !*pWild;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_utils::write_buf_to_file(const char* pPath, const void* pData, size_t data_size)
|
|
||||||
{
|
|
||||||
FILE *pFile = NULL;
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// Compiling with MSVC
|
|
||||||
if (fopen_s(&pFile, pPath, "wb"))
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
pFile = fopen(pPath, "wb");
|
|
||||||
#endif
|
|
||||||
if (!pFile)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool success = fwrite(pData, 1, data_size, pFile) == data_size;
|
|
||||||
|
|
||||||
fclose(pFile);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,43 +0,0 @@
|
||||||
// File: crn_file_utils.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
struct file_utils
|
|
||||||
{
|
|
||||||
// Returns true if pSrcFilename is older than pDstFilename
|
|
||||||
static bool is_read_only(const char* pFilename);
|
|
||||||
static bool disable_read_only(const char* pFilename);
|
|
||||||
static bool is_older_than(const char *pSrcFilename, const char* pDstFilename);
|
|
||||||
static bool does_file_exist(const char* pFilename);
|
|
||||||
static bool does_dir_exist(const char* pDir);
|
|
||||||
static bool get_file_size(const char* pFilename, uint64& file_size);
|
|
||||||
static bool get_file_size(const char* pFilename, uint32& file_size);
|
|
||||||
|
|
||||||
static bool is_path_separator(char c);
|
|
||||||
static bool is_path_or_drive_separator(char c);
|
|
||||||
static bool is_drive_separator(char c);
|
|
||||||
|
|
||||||
static bool split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt);
|
|
||||||
static bool split_path(const char* p, dynamic_string& path, dynamic_string& filename);
|
|
||||||
|
|
||||||
static bool get_pathname(const char* p, dynamic_string& path);
|
|
||||||
static bool get_filename(const char* p, dynamic_string& filename);
|
|
||||||
|
|
||||||
static void combine_path(dynamic_string& dst, const char* pA, const char* pB);
|
|
||||||
static void combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC);
|
|
||||||
|
|
||||||
static bool full_path(dynamic_string& path);
|
|
||||||
static bool get_extension(dynamic_string& filename);
|
|
||||||
static bool remove_extension(dynamic_string& filename);
|
|
||||||
static bool create_path(const dynamic_string& path);
|
|
||||||
static void trim_trailing_seperator(dynamic_string& path);
|
|
||||||
|
|
||||||
static int wildcmp(const char* pWild, const char* pString);
|
|
||||||
|
|
||||||
static bool write_buf_to_file(const char* pPath, const void* pData, size_t data_size);
|
|
||||||
|
|
||||||
}; // struct file_utils
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,287 +0,0 @@
|
||||||
// File: crn_win32_find_files.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_find_files.h"
|
|
||||||
#include "crn_file_utils.h"
|
|
||||||
#include "crn_strutils.h"
|
|
||||||
|
|
||||||
#ifdef CRNLIB_USE_WIN32_API
|
|
||||||
#include "crn_winhdr.h"
|
|
||||||
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#include <fnmatch.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
#ifdef CRNLIB_USE_WIN32_API
|
|
||||||
bool find_files::find(const char* pBasepath, const char* pFilespec, uint flags)
|
|
||||||
{
|
|
||||||
m_last_error = S_OK;
|
|
||||||
m_files.resize(0);
|
|
||||||
|
|
||||||
return find_internal(pBasepath, "", pFilespec, flags, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool find_files::find(const char* pSpec, uint flags)
|
|
||||||
{
|
|
||||||
dynamic_string find_name(pSpec);
|
|
||||||
|
|
||||||
if (!file_utils::full_path(find_name))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dynamic_string find_pathname, find_filename;
|
|
||||||
if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool find_files::find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level)
|
|
||||||
{
|
|
||||||
WIN32_FIND_DATAA find_data;
|
|
||||||
|
|
||||||
dynamic_string filename;
|
|
||||||
|
|
||||||
dynamic_string_array child_paths;
|
|
||||||
if (flags & cFlagRecursive)
|
|
||||||
{
|
|
||||||
if (strlen(pRelpath))
|
|
||||||
file_utils::combine_path(filename, pBasepath, pRelpath, "*");
|
|
||||||
else
|
|
||||||
file_utils::combine_path(filename, pBasepath, "*");
|
|
||||||
|
|
||||||
HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
HRESULT hres = GetLastError();
|
|
||||||
if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
|
|
||||||
{
|
|
||||||
m_last_error = hres;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
||||||
|
|
||||||
bool skip = !is_dir;
|
|
||||||
if (is_dir)
|
|
||||||
skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
|
|
||||||
|
|
||||||
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
|
|
||||||
skip = true;
|
|
||||||
|
|
||||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
|
||||||
{
|
|
||||||
if ((flags & cFlagAllowHidden) == 0)
|
|
||||||
skip = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!skip)
|
|
||||||
{
|
|
||||||
dynamic_string child_path(find_data.cFileName);
|
|
||||||
if ((!child_path.count_char('?')) && (!child_path.count_char('*')))
|
|
||||||
child_paths.push_back(child_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (FindNextFileA(handle, &find_data) != 0);
|
|
||||||
|
|
||||||
HRESULT hres = GetLastError();
|
|
||||||
|
|
||||||
FindClose(handle);
|
|
||||||
handle = INVALID_HANDLE_VALUE;
|
|
||||||
|
|
||||||
if (hres != ERROR_NO_MORE_FILES)
|
|
||||||
{
|
|
||||||
m_last_error = hres;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(pRelpath))
|
|
||||||
file_utils::combine_path(filename, pBasepath, pRelpath, pFilespec);
|
|
||||||
else
|
|
||||||
file_utils::combine_path(filename, pBasepath, pFilespec);
|
|
||||||
|
|
||||||
HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
HRESULT hres = GetLastError();
|
|
||||||
if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
|
|
||||||
{
|
|
||||||
m_last_error = hres;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
||||||
|
|
||||||
bool skip = false;
|
|
||||||
if (is_dir)
|
|
||||||
skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
|
|
||||||
|
|
||||||
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
|
|
||||||
skip = true;
|
|
||||||
|
|
||||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
|
||||||
{
|
|
||||||
if ((flags & cFlagAllowHidden) == 0)
|
|
||||||
skip = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!skip)
|
|
||||||
{
|
|
||||||
if (((is_dir) && (flags & cFlagAllowDirs)) || ((!is_dir) && (flags & cFlagAllowFiles)))
|
|
||||||
{
|
|
||||||
m_files.resize(m_files.size() + 1);
|
|
||||||
file_desc& file = m_files.back();
|
|
||||||
file.m_is_dir = is_dir;
|
|
||||||
file.m_base = pBasepath;
|
|
||||||
file.m_name = find_data.cFileName;
|
|
||||||
file.m_rel = pRelpath;
|
|
||||||
if (strlen(pRelpath))
|
|
||||||
file_utils::combine_path(file.m_fullname, pBasepath, pRelpath, find_data.cFileName);
|
|
||||||
else
|
|
||||||
file_utils::combine_path(file.m_fullname, pBasepath, find_data.cFileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (FindNextFileA(handle, &find_data) != 0);
|
|
||||||
|
|
||||||
HRESULT hres = GetLastError();
|
|
||||||
|
|
||||||
FindClose(handle);
|
|
||||||
|
|
||||||
if (hres != ERROR_NO_MORE_FILES)
|
|
||||||
{
|
|
||||||
m_last_error = hres;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint i = 0; i < child_paths.size(); i++)
|
|
||||||
{
|
|
||||||
dynamic_string child_path;
|
|
||||||
if (strlen(pRelpath))
|
|
||||||
file_utils::combine_path(child_path, pRelpath, child_paths[i].get_ptr());
|
|
||||||
else
|
|
||||||
child_path = child_paths[i];
|
|
||||||
|
|
||||||
if (!find_internal(pBasepath, child_path.get_ptr(), pFilespec, flags, level + 1))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
bool find_files::find(const char* pBasepath, const char* pFilespec, uint flags)
|
|
||||||
{
|
|
||||||
m_files.resize(0);
|
|
||||||
return find_internal(pBasepath, "", pFilespec, flags, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool find_files::find(const char* pSpec, uint flags)
|
|
||||||
{
|
|
||||||
dynamic_string find_name(pSpec);
|
|
||||||
|
|
||||||
if (!file_utils::full_path(find_name))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dynamic_string find_pathname, find_filename;
|
|
||||||
if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool find_files::find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level)
|
|
||||||
{
|
|
||||||
dynamic_string pathname;
|
|
||||||
if (strlen(pRelpath))
|
|
||||||
file_utils::combine_path(pathname, pBasepath, pRelpath);
|
|
||||||
else
|
|
||||||
pathname = pBasepath;
|
|
||||||
|
|
||||||
if (!pathname.is_empty())
|
|
||||||
{
|
|
||||||
char c = pathname.back();
|
|
||||||
if (c != '/')
|
|
||||||
pathname += "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
DIR *dp = opendir(pathname.get_ptr());
|
|
||||||
|
|
||||||
if (!dp)
|
|
||||||
return level ? true : false;
|
|
||||||
|
|
||||||
dynamic_string_array paths;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
struct dirent *ep = readdir(dp);
|
|
||||||
if (!ep)
|
|
||||||
break;
|
|
||||||
if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const bool is_directory = (ep->d_type & DT_DIR) != 0;
|
|
||||||
const bool is_file = (ep->d_type & DT_REG) != 0;
|
|
||||||
|
|
||||||
dynamic_string filename(ep->d_name);
|
|
||||||
|
|
||||||
if (is_directory)
|
|
||||||
{
|
|
||||||
if (flags & cFlagRecursive)
|
|
||||||
{
|
|
||||||
paths.push_back(filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((is_file) && (flags & cFlagAllowFiles)) || ((is_directory) && (flags & cFlagAllowDirs)))
|
|
||||||
{
|
|
||||||
if (0 == fnmatch(pFilespec, filename.get_ptr(), 0))
|
|
||||||
{
|
|
||||||
m_files.resize(m_files.size() + 1);
|
|
||||||
file_desc& file = m_files.back();
|
|
||||||
file.m_is_dir = is_directory;
|
|
||||||
file.m_base = pBasepath;
|
|
||||||
file.m_rel = pRelpath;
|
|
||||||
file.m_name = filename;
|
|
||||||
file.m_fullname = pathname + filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dp);
|
|
||||||
dp = NULL;
|
|
||||||
|
|
||||||
if (flags & cFlagRecursive)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < paths.size(); i++)
|
|
||||||
{
|
|
||||||
dynamic_string childpath;
|
|
||||||
if (strlen(pRelpath))
|
|
||||||
file_utils::combine_path(childpath, pRelpath, paths[i].get_ptr());
|
|
||||||
else
|
|
||||||
childpath = paths[i];
|
|
||||||
|
|
||||||
if (!find_internal(pBasepath, childpath.get_ptr(), pFilespec, flags, level + 1))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#error Unimplemented
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,60 +0,0 @@
|
||||||
// File: crn_win32_find_files.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class find_files
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct file_desc
|
|
||||||
{
|
|
||||||
inline file_desc() : m_is_dir(false) { }
|
|
||||||
|
|
||||||
dynamic_string m_fullname;
|
|
||||||
dynamic_string m_base;
|
|
||||||
dynamic_string m_rel;
|
|
||||||
dynamic_string m_name;
|
|
||||||
bool m_is_dir;
|
|
||||||
|
|
||||||
inline bool operator== (const file_desc& other) const { return m_fullname == other.m_fullname; }
|
|
||||||
inline bool operator< (const file_desc& other) const { return m_fullname < other.m_fullname; }
|
|
||||||
|
|
||||||
inline operator size_t() const { return static_cast<size_t>(m_fullname); }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<file_desc> file_desc_vec;
|
|
||||||
|
|
||||||
inline find_files()
|
|
||||||
{
|
|
||||||
m_last_error = 0; // S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum flags
|
|
||||||
{
|
|
||||||
cFlagRecursive = 1,
|
|
||||||
cFlagAllowDirs = 2,
|
|
||||||
cFlagAllowFiles = 4,
|
|
||||||
cFlagAllowHidden = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
bool find(const char* pBasepath, const char* pFilespec, uint flags = cFlagAllowFiles);
|
|
||||||
|
|
||||||
bool find(const char* pSpec, uint flags = cFlagAllowFiles);
|
|
||||||
|
|
||||||
// An HRESULT under Win32. FIXME: Abstract this better?
|
|
||||||
inline int64 get_last_error() const { return m_last_error; }
|
|
||||||
|
|
||||||
const file_desc_vec& get_files() const { return m_files; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
file_desc_vec m_files;
|
|
||||||
|
|
||||||
// A HRESULT under Win32
|
|
||||||
int64 m_last_error;
|
|
||||||
|
|
||||||
bool find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level);
|
|
||||||
|
|
||||||
}; // class find_files
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,158 +0,0 @@
|
||||||
// File: crn_freeimage_image_utils.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
// Note: This header file requires FreeImage/FreeImagePlus.
|
|
||||||
|
|
||||||
#include "crn_image_utils.h"
|
|
||||||
|
|
||||||
#include "freeImagePlus.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace freeimage_image_utils
|
|
||||||
{
|
|
||||||
inline bool load_from_file(image_u8& dest, const wchar_t* pFilename, int fi_flag)
|
|
||||||
{
|
|
||||||
fipImage src_image;
|
|
||||||
|
|
||||||
if (!src_image.loadU(pFilename, fi_flag))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const uint orig_bits_per_pixel = src_image.getBitsPerPixel();
|
|
||||||
|
|
||||||
const FREE_IMAGE_COLOR_TYPE orig_color_type = src_image.getColorType();
|
|
||||||
|
|
||||||
if (!src_image.convertTo32Bits())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (src_image.getBitsPerPixel() != 32)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint width = src_image.getWidth();
|
|
||||||
uint height = src_image.getHeight();
|
|
||||||
|
|
||||||
dest.resize(src_image.getWidth(), src_image.getHeight(), src_image.getWidth());
|
|
||||||
|
|
||||||
color_quad_u8* pDst = dest.get_ptr();
|
|
||||||
|
|
||||||
bool grayscale = true;
|
|
||||||
bool has_alpha = false;
|
|
||||||
for (uint y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
const BYTE* pSrc = src_image.getScanLine((WORD)(height - 1 - y));
|
|
||||||
color_quad_u8* pD = pDst;
|
|
||||||
|
|
||||||
for (uint x = width; x; x--)
|
|
||||||
{
|
|
||||||
color_quad_u8 c;
|
|
||||||
c.r = pSrc[FI_RGBA_RED];
|
|
||||||
c.g = pSrc[FI_RGBA_GREEN];
|
|
||||||
c.b = pSrc[FI_RGBA_BLUE];
|
|
||||||
c.a = pSrc[FI_RGBA_ALPHA];
|
|
||||||
|
|
||||||
if (!c.is_grayscale())
|
|
||||||
grayscale = false;
|
|
||||||
has_alpha |= (c.a < 255);
|
|
||||||
|
|
||||||
pSrc += 4;
|
|
||||||
*pD++ = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
pDst += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest.reset_comp_flags();
|
|
||||||
|
|
||||||
if (grayscale)
|
|
||||||
dest.set_grayscale(true);
|
|
||||||
|
|
||||||
dest.set_component_valid(3, has_alpha || (orig_color_type == FIC_RGBALPHA) || (orig_bits_per_pixel == 32));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int cSaveLuma = -1;
|
|
||||||
|
|
||||||
inline bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int fi_flag)
|
|
||||||
{
|
|
||||||
fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), 8);
|
|
||||||
|
|
||||||
RGBQUAD* p = dst_image.getPalette();
|
|
||||||
for (uint i = 0; i < dst_image.getPaletteSize(); i++)
|
|
||||||
{
|
|
||||||
p[i].rgbRed = (BYTE)i;
|
|
||||||
p[i].rgbGreen = (BYTE)i;
|
|
||||||
p[i].rgbBlue = (BYTE)i;
|
|
||||||
p[i].rgbReserved = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint y = 0; y < src.get_height(); y++)
|
|
||||||
{
|
|
||||||
const color_quad_u8* pSrc = src.get_scanline(y);
|
|
||||||
|
|
||||||
for (uint x = 0; x < src.get_width(); x++)
|
|
||||||
{
|
|
||||||
BYTE v;
|
|
||||||
if (component == cSaveLuma)
|
|
||||||
v = (BYTE)(*pSrc).get_luma();
|
|
||||||
else
|
|
||||||
v = (*pSrc)[component];
|
|
||||||
dst_image.setPixelIndex(x, src.get_height() - 1 - y, &v);
|
|
||||||
|
|
||||||
pSrc++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dst_image.saveU(pFilename, fi_flag))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool save_to_file(const wchar_t* pFilename, const image_u8& src, int fi_flag, bool ignore_alpha = false)
|
|
||||||
{
|
|
||||||
const bool save_alpha = src.is_component_valid(3);
|
|
||||||
uint bpp = (save_alpha && !ignore_alpha) ? 32 : 24;
|
|
||||||
|
|
||||||
if (bpp == 32)
|
|
||||||
{
|
|
||||||
dynamic_wstring ext(pFilename);
|
|
||||||
get_extension(ext);
|
|
||||||
|
|
||||||
if ((ext == L"jpg") || (ext == L"jpeg") || (ext == L"gif") || (ext == L"jp2"))
|
|
||||||
bpp = 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((bpp == 24) && (src.is_grayscale()))
|
|
||||||
return save_to_grayscale_file(pFilename, src, cSaveLuma, fi_flag);
|
|
||||||
|
|
||||||
fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), (WORD)bpp);
|
|
||||||
|
|
||||||
for (uint y = 0; y < src.get_height(); y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < src.get_width(); x++)
|
|
||||||
{
|
|
||||||
color_quad_u8 c(src(x, y));
|
|
||||||
|
|
||||||
RGBQUAD quad;
|
|
||||||
quad.rgbRed = c.r;
|
|
||||||
quad.rgbGreen = c.g;
|
|
||||||
quad.rgbBlue = c.b;
|
|
||||||
if (bpp == 32)
|
|
||||||
quad.rgbReserved = c.a;
|
|
||||||
else
|
|
||||||
quad.rgbReserved = 255;
|
|
||||||
|
|
||||||
dst_image.setPixelColor(x, src.get_height() - 1 - y, &quad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dst_image.saveU(pFilename, fi_flag))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace freeimage_image_utils
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
// File: crn_hash.cpp
|
|
||||||
// See Paul Hsieh's page at: http://www.azillionmonkeys.com/qed/hash.html
|
|
||||||
// Also see http://www.concentric.net/~Ttwang/tech/inthash.htm,
|
|
||||||
// http://burtleburtle.net/bob/hash/integer.html
|
|
||||||
#include "crn_core.h"
|
|
||||||
|
|
||||||
#undef get16bits
|
|
||||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
|
||||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
|
||||||
#define get16bits(d) (*((const uint16 *) (d)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined (get16bits)
|
|
||||||
#define get16bits(d) ((((uint32)(((const uint8 *)(d))[1])) << 8)\
|
|
||||||
+(uint32)(((const uint8 *)(d))[0]) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
uint32 fast_hash (const void* p, int len)
|
|
||||||
{
|
|
||||||
const char * data = static_cast<const char *>(p);
|
|
||||||
|
|
||||||
uint32 hash = len, tmp;
|
|
||||||
int rem;
|
|
||||||
|
|
||||||
if (len <= 0 || data == NULL) return 0;
|
|
||||||
|
|
||||||
rem = len & 3;
|
|
||||||
len >>= 2;
|
|
||||||
|
|
||||||
/* Main loop */
|
|
||||||
for (;len > 0; len--) {
|
|
||||||
hash += get16bits (data);
|
|
||||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
|
||||||
hash = (hash << 16) ^ tmp;
|
|
||||||
data += 2*sizeof (uint16);
|
|
||||||
hash += hash >> 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle end cases */
|
|
||||||
switch (rem) {
|
|
||||||
case 3: hash += get16bits (data);
|
|
||||||
hash ^= hash << 16;
|
|
||||||
hash ^= data[sizeof (uint16)] << 18;
|
|
||||||
hash += hash >> 11;
|
|
||||||
break;
|
|
||||||
case 2: hash += get16bits (data);
|
|
||||||
hash ^= hash << 11;
|
|
||||||
hash += hash >> 17;
|
|
||||||
break;
|
|
||||||
case 1: hash += *data;
|
|
||||||
hash ^= hash << 10;
|
|
||||||
hash += hash >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Force "avalanching" of final 127 bits */
|
|
||||||
hash ^= hash << 3;
|
|
||||||
hash += hash >> 5;
|
|
||||||
hash ^= hash << 4;
|
|
||||||
hash += hash >> 17;
|
|
||||||
hash ^= hash << 25;
|
|
||||||
hash += hash >> 6;
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,34 +0,0 @@
|
||||||
// File: crn_hash.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
uint32 fast_hash (const void* p, int len);
|
|
||||||
|
|
||||||
// 4-byte integer hash, full avalanche
|
|
||||||
inline uint32 bitmix32c(uint32 a)
|
|
||||||
{
|
|
||||||
a = (a+0x7ed55d16) + (a<<12);
|
|
||||||
a = (a^0xc761c23c) ^ (a>>19);
|
|
||||||
a = (a+0x165667b1) + (a<<5);
|
|
||||||
a = (a+0xd3a2646c) ^ (a<<9);
|
|
||||||
a = (a+0xfd7046c5) + (a<<3);
|
|
||||||
a = (a^0xb55a4f09) ^ (a>>16);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4-byte integer hash, full avalanche, no constants
|
|
||||||
inline uint32 bitmix32(uint32 a)
|
|
||||||
{
|
|
||||||
a -= (a<<6);
|
|
||||||
a ^= (a>>17);
|
|
||||||
a -= (a<<9);
|
|
||||||
a ^= (a<<4);
|
|
||||||
a -= (a<<3);
|
|
||||||
a ^= (a<<10);
|
|
||||||
a ^= (a>>15);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,155 +0,0 @@
|
||||||
// File: crn_hash_map.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_hash_map.h"
|
|
||||||
#include "crn_rand.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
class counted_obj
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
counted_obj(uint v = 0) :
|
|
||||||
m_val(v)
|
|
||||||
{
|
|
||||||
m_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
counted_obj(const counted_obj& obj) :
|
|
||||||
m_val(obj.m_val)
|
|
||||||
{
|
|
||||||
m_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
~counted_obj()
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_count > 0);
|
|
||||||
m_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint m_count;
|
|
||||||
|
|
||||||
uint m_val;
|
|
||||||
|
|
||||||
operator size_t() const { return m_val; }
|
|
||||||
|
|
||||||
bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }
|
|
||||||
bool operator== (const uint rhs) const { return m_val == rhs; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
uint counted_obj::m_count;
|
|
||||||
|
|
||||||
void hash_map_test()
|
|
||||||
{
|
|
||||||
random r0, r1;
|
|
||||||
|
|
||||||
uint seed = 0;
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
seed++;
|
|
||||||
|
|
||||||
typedef crnlib::hash_map<counted_obj, counted_obj> my_hash_map;
|
|
||||||
my_hash_map m;
|
|
||||||
|
|
||||||
const uint n = r0.irand(1, 100000);
|
|
||||||
|
|
||||||
printf("%u\n", n);
|
|
||||||
|
|
||||||
r1.seed(seed);
|
|
||||||
|
|
||||||
crnlib::vector<int> q;
|
|
||||||
|
|
||||||
uint count = 0;
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
uint v = r1.urand32() & 0x7FFFFFFF;
|
|
||||||
my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));
|
|
||||||
if (res.second)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
q.push_back(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_VERIFY(m.size() == count);
|
|
||||||
|
|
||||||
r1.seed(seed);
|
|
||||||
|
|
||||||
my_hash_map cm(m);
|
|
||||||
m.clear();
|
|
||||||
m = cm;
|
|
||||||
cm.reset();
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
uint v = r1.urand32() & 0x7FFFFFFF;
|
|
||||||
my_hash_map::const_iterator it = m.find(counted_obj(v));
|
|
||||||
CRNLIB_VERIFY(it != m.end());
|
|
||||||
CRNLIB_VERIFY(it->first == v);
|
|
||||||
CRNLIB_VERIFY(it->second == (v ^ 0xdeadbeef));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint t = 0; t < 2; t++)
|
|
||||||
{
|
|
||||||
const uint nd = r0.irand(1, q.size() + 1);
|
|
||||||
for (uint i = 0; i < nd; i++)
|
|
||||||
{
|
|
||||||
uint p = r0.irand(0, q.size());
|
|
||||||
|
|
||||||
int k = q[p];
|
|
||||||
if (k >= 0)
|
|
||||||
{
|
|
||||||
q[p] = -k - 1;
|
|
||||||
|
|
||||||
bool s = m.erase(counted_obj(k));
|
|
||||||
CRNLIB_VERIFY(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef crnlib::hash_map<uint, empty_type> uint_hash_set;
|
|
||||||
uint_hash_set s;
|
|
||||||
|
|
||||||
for (uint i = 0; i < q.size(); i++)
|
|
||||||
{
|
|
||||||
int v = q[i];
|
|
||||||
|
|
||||||
if (v >= 0)
|
|
||||||
{
|
|
||||||
my_hash_map::const_iterator it = m.find(counted_obj(v));
|
|
||||||
CRNLIB_VERIFY(it != m.end());
|
|
||||||
CRNLIB_VERIFY(it->first == (uint)v);
|
|
||||||
CRNLIB_VERIFY(it->second == ((uint)v ^ 0xdeadbeef));
|
|
||||||
|
|
||||||
s.insert(v);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));
|
|
||||||
CRNLIB_VERIFY(it == m.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint found_count = 0;
|
|
||||||
for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)
|
|
||||||
{
|
|
||||||
CRNLIB_VERIFY(it->second == ((uint)it->first ^ 0xdeadbeef));
|
|
||||||
|
|
||||||
uint_hash_set::const_iterator fit(s.find((uint)it->first));
|
|
||||||
CRNLIB_VERIFY(fit != s.end());
|
|
||||||
|
|
||||||
CRNLIB_VERIFY(fit->first == it->first);
|
|
||||||
|
|
||||||
found_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_VERIFY(found_count == s.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_VERIFY(counted_obj::m_count == m.size() * 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,876 +0,0 @@
|
||||||
// File: crn_hash_map.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
//
|
|
||||||
// Notes:
|
|
||||||
// stl-like hash map/hash set, with predictable performance across platforms/compilers/C run times/etc.
|
|
||||||
// Hash function ref: http://www.brpreiss.com/books/opus4/html/page215.html
|
|
||||||
// Compared for performance against VC9's std::hash_map.
|
|
||||||
// Linear probing, auto resizes on ~50% load factor.
|
|
||||||
// Uses Knuth's multiplicative method (Fibonacci hashing).
|
|
||||||
#pragma once
|
|
||||||
#include "crn_sparse_array.h"
|
|
||||||
#include "crn_sparse_bit_array.h"
|
|
||||||
#include "crn_hash.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
template <typename T>
|
|
||||||
struct hasher
|
|
||||||
{
|
|
||||||
inline size_t operator() (const T& key) const { return static_cast<size_t>(key); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct bit_hasher
|
|
||||||
{
|
|
||||||
inline size_t operator() (const T& key) const { return static_cast<size_t>(fast_hash(&key, sizeof(key))); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct equal_to
|
|
||||||
{
|
|
||||||
inline bool operator()(const T& a, const T& b) const { return a == b; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Important: The Hasher and Equals objects must be bitwise movable!
|
|
||||||
template<typename Key, typename Value = empty_type, typename Hasher = hasher<Key>, typename Equals = equal_to<Key> >
|
|
||||||
class hash_map
|
|
||||||
{
|
|
||||||
friend class iterator;
|
|
||||||
friend class const_iterator;
|
|
||||||
|
|
||||||
enum state
|
|
||||||
{
|
|
||||||
cStateInvalid = 0,
|
|
||||||
cStateValid = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cMinHashSize = 4U
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef hash_map<Key, Value, Hasher, Equals> hash_map_type;
|
|
||||||
typedef std::pair<Key, Value> value_type;
|
|
||||||
typedef Key key_type;
|
|
||||||
typedef Value referent_type;
|
|
||||||
typedef Hasher hasher_type;
|
|
||||||
typedef Equals equals_type;
|
|
||||||
|
|
||||||
hash_map() :
|
|
||||||
m_hash_shift(32), m_num_valid(0), m_grow_threshold(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_map(const hash_map& other) :
|
|
||||||
m_values(other.m_values),
|
|
||||||
m_hash_shift(other.m_hash_shift),
|
|
||||||
m_hasher(other.m_hasher),
|
|
||||||
m_equals(other.m_equals),
|
|
||||||
m_num_valid(other.m_num_valid),
|
|
||||||
m_grow_threshold(other.m_grow_threshold)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_map& operator= (const hash_map& other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_values = other.m_values;
|
|
||||||
m_hash_shift = other.m_hash_shift;
|
|
||||||
m_num_valid = other.m_num_valid;
|
|
||||||
m_grow_threshold = other.m_grow_threshold;
|
|
||||||
m_hasher = other.m_hasher;
|
|
||||||
m_equals = other.m_equals;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~hash_map()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Equals& get_equals() const { return m_equals; }
|
|
||||||
Equals& get_equals() { return m_equals; }
|
|
||||||
|
|
||||||
void set_equals(const Equals& equals) { m_equals = equals; }
|
|
||||||
|
|
||||||
const Hasher& get_hasher() const { return m_hasher; }
|
|
||||||
Hasher& get_hasher() { return m_hasher; }
|
|
||||||
|
|
||||||
void set_hasher(const Hasher& hasher) { m_hasher = hasher; }
|
|
||||||
|
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
if (!m_values.empty())
|
|
||||||
{
|
|
||||||
if (CRNLIB_HAS_DESTRUCTOR(Key) || CRNLIB_HAS_DESTRUCTOR(Value))
|
|
||||||
{
|
|
||||||
node* p = &get_node(0);
|
|
||||||
node* p_end = p + m_values.size();
|
|
||||||
|
|
||||||
uint num_remaining = m_num_valid;
|
|
||||||
while (p != p_end)
|
|
||||||
{
|
|
||||||
if (p->state)
|
|
||||||
{
|
|
||||||
destruct_value_type(p);
|
|
||||||
num_remaining--;
|
|
||||||
if (!num_remaining)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_values.clear_no_destruction();
|
|
||||||
|
|
||||||
m_hash_shift = 32;
|
|
||||||
m_num_valid = 0;
|
|
||||||
m_grow_threshold = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void reset()
|
|
||||||
{
|
|
||||||
if (!m_num_valid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (CRNLIB_HAS_DESTRUCTOR(Key) || CRNLIB_HAS_DESTRUCTOR(Value))
|
|
||||||
{
|
|
||||||
node* p = &get_node(0);
|
|
||||||
node* p_end = p + m_values.size();
|
|
||||||
|
|
||||||
uint num_remaining = m_num_valid;
|
|
||||||
while (p != p_end)
|
|
||||||
{
|
|
||||||
if (p->state)
|
|
||||||
{
|
|
||||||
destruct_value_type(p);
|
|
||||||
p->state = cStateInvalid;
|
|
||||||
|
|
||||||
num_remaining--;
|
|
||||||
if (!num_remaining)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (sizeof(node) <= 32)
|
|
||||||
{
|
|
||||||
memset(&m_values[0], 0, m_values.size_in_bytes());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node* p = &get_node(0);
|
|
||||||
node* p_end = p + m_values.size();
|
|
||||||
|
|
||||||
uint num_remaining = m_num_valid;
|
|
||||||
while (p != p_end)
|
|
||||||
{
|
|
||||||
if (p->state)
|
|
||||||
{
|
|
||||||
p->state = cStateInvalid;
|
|
||||||
|
|
||||||
num_remaining--;
|
|
||||||
if (!num_remaining)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_num_valid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint size()
|
|
||||||
{
|
|
||||||
return m_num_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_table_size()
|
|
||||||
{
|
|
||||||
return m_values.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool empty()
|
|
||||||
{
|
|
||||||
return !m_num_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void reserve(uint new_capacity)
|
|
||||||
{
|
|
||||||
uint new_hash_size = math::maximum(1U, new_capacity);
|
|
||||||
|
|
||||||
new_hash_size = new_hash_size * 2U;
|
|
||||||
|
|
||||||
if (!math::is_power_of_2(new_hash_size))
|
|
||||||
new_hash_size = math::next_pow2(new_hash_size);
|
|
||||||
|
|
||||||
new_hash_size = math::maximum<uint>(cMinHashSize, new_hash_size);
|
|
||||||
|
|
||||||
if (new_hash_size > m_values.size())
|
|
||||||
rehash(new_hash_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
class const_iterator;
|
|
||||||
|
|
||||||
class iterator
|
|
||||||
{
|
|
||||||
friend class hash_map<Key, Value, Hasher, Equals>;
|
|
||||||
friend class hash_map<Key, Value, Hasher, Equals>::const_iterator;
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline iterator() : m_pTable(NULL), m_index(0) { }
|
|
||||||
inline iterator(hash_map_type& table, uint index) : m_pTable(&table), m_index(index) { }
|
|
||||||
inline iterator(const iterator& other) : m_pTable(other.m_pTable), m_index(other.m_index) { }
|
|
||||||
|
|
||||||
inline iterator& operator= (const iterator& other)
|
|
||||||
{
|
|
||||||
m_pTable = other.m_pTable;
|
|
||||||
m_index = other.m_index;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// post-increment
|
|
||||||
inline iterator operator++(int)
|
|
||||||
{
|
|
||||||
iterator result(*this);
|
|
||||||
++*this;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pre-increment
|
|
||||||
inline iterator& operator++()
|
|
||||||
{
|
|
||||||
probe();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline value_type& operator*() const { return *get_cur(); }
|
|
||||||
inline value_type* operator->() const { return get_cur(); }
|
|
||||||
|
|
||||||
inline bool operator == (const iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
|
|
||||||
inline bool operator != (const iterator& b) const { return !(*this == b); }
|
|
||||||
inline bool operator == (const const_iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
|
|
||||||
inline bool operator != (const const_iterator& b) const { return !(*this == b); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
hash_map_type* m_pTable;
|
|
||||||
uint m_index;
|
|
||||||
|
|
||||||
inline value_type* get_cur() const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_pTable && (m_index < m_pTable->m_values.size()));
|
|
||||||
CRNLIB_ASSERT(m_pTable->get_node_state(m_index) == cStateValid);
|
|
||||||
|
|
||||||
return &m_pTable->get_node(m_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void probe()
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_pTable);
|
|
||||||
m_index = m_pTable->find_next(m_index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class const_iterator
|
|
||||||
{
|
|
||||||
friend class hash_map<Key, Value, Hasher, Equals>;
|
|
||||||
friend class hash_map<Key, Value, Hasher, Equals>::iterator;
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline const_iterator() : m_pTable(NULL), m_index(0) { }
|
|
||||||
inline const_iterator(const hash_map_type& table, uint index) : m_pTable(&table), m_index(index) { }
|
|
||||||
inline const_iterator(const iterator& other) : m_pTable(other.m_pTable), m_index(other.m_index) { }
|
|
||||||
inline const_iterator(const const_iterator& other) : m_pTable(other.m_pTable), m_index(other.m_index) { }
|
|
||||||
|
|
||||||
inline const_iterator& operator= (const const_iterator& other)
|
|
||||||
{
|
|
||||||
m_pTable = other.m_pTable;
|
|
||||||
m_index = other.m_index;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const_iterator& operator= (const iterator& other)
|
|
||||||
{
|
|
||||||
m_pTable = other.m_pTable;
|
|
||||||
m_index = other.m_index;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// post-increment
|
|
||||||
inline const_iterator operator++(int)
|
|
||||||
{
|
|
||||||
const_iterator result(*this);
|
|
||||||
++*this;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pre-increment
|
|
||||||
inline const_iterator& operator++()
|
|
||||||
{
|
|
||||||
probe();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const value_type& operator*() const { return *get_cur(); }
|
|
||||||
inline const value_type* operator->() const { return get_cur(); }
|
|
||||||
|
|
||||||
inline bool operator == (const const_iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
|
|
||||||
inline bool operator != (const const_iterator& b) const { return !(*this == b); }
|
|
||||||
inline bool operator == (const iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
|
|
||||||
inline bool operator != (const iterator& b) const { return !(*this == b); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const hash_map_type* m_pTable;
|
|
||||||
uint m_index;
|
|
||||||
|
|
||||||
inline const value_type* get_cur() const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_pTable && (m_index < m_pTable->m_values.size()));
|
|
||||||
CRNLIB_ASSERT(m_pTable->get_node_state(m_index) == cStateValid);
|
|
||||||
|
|
||||||
return &m_pTable->get_node(m_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void probe()
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_pTable);
|
|
||||||
m_index = m_pTable->find_next(m_index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline const_iterator begin() const
|
|
||||||
{
|
|
||||||
if (!m_num_valid)
|
|
||||||
return end();
|
|
||||||
|
|
||||||
return const_iterator(*this, find_next(-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const_iterator end() const
|
|
||||||
{
|
|
||||||
return const_iterator(*this, m_values.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline iterator begin()
|
|
||||||
{
|
|
||||||
if (!m_num_valid)
|
|
||||||
return end();
|
|
||||||
|
|
||||||
return iterator(*this, find_next(-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline iterator end()
|
|
||||||
{
|
|
||||||
return iterator(*this, m_values.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert_result.first will always point to inserted key/value (or the already existing key/value).
|
|
||||||
// insert_resutt.second will be true if a new key/value was inserted, or false if the key already existed (in which case first will point to the already existing value).
|
|
||||||
typedef std::pair<iterator, bool> insert_result;
|
|
||||||
|
|
||||||
inline insert_result insert(const Key& k, const Value& v = Value())
|
|
||||||
{
|
|
||||||
insert_result result;
|
|
||||||
if (!insert_no_grow(result, k, v))
|
|
||||||
{
|
|
||||||
grow();
|
|
||||||
|
|
||||||
// This must succeed.
|
|
||||||
if (!insert_no_grow(result, k, v))
|
|
||||||
{
|
|
||||||
CRNLIB_FAIL("insert() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline insert_result insert(const value_type& v)
|
|
||||||
{
|
|
||||||
return insert(v.first, v.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const_iterator find(const Key& k) const
|
|
||||||
{
|
|
||||||
return const_iterator(*this, find_index(k));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline iterator find(const Key& k)
|
|
||||||
{
|
|
||||||
return iterator(*this, find_index(k));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool erase(const Key& k)
|
|
||||||
{
|
|
||||||
int i = find_index(k);
|
|
||||||
|
|
||||||
if (i >= static_cast<int>(m_values.size()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
node* pDst = &get_node(i);
|
|
||||||
destruct_value_type(pDst);
|
|
||||||
pDst->state = cStateInvalid;
|
|
||||||
|
|
||||||
m_num_valid--;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
int r, j = i;
|
|
||||||
|
|
||||||
node* pSrc = pDst;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!i)
|
|
||||||
{
|
|
||||||
i = m_values.size() - 1;
|
|
||||||
pSrc = &get_node(i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i--;
|
|
||||||
pSrc--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pSrc->state)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
r = hash_key(pSrc->first);
|
|
||||||
|
|
||||||
} while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
|
|
||||||
|
|
||||||
move_node(pDst, pSrc);
|
|
||||||
|
|
||||||
pDst = pSrc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swap(hash_map_type& other)
|
|
||||||
{
|
|
||||||
m_values.swap(other.m_values);
|
|
||||||
utils::swap(m_hash_shift, other.m_hash_shift);
|
|
||||||
utils::swap(m_num_valid, other.m_num_valid);
|
|
||||||
utils::swap(m_grow_threshold, other.m_grow_threshold);
|
|
||||||
utils::swap(m_hasher, other.m_hasher);
|
|
||||||
utils::swap(m_equals, other.m_equals);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct node : public value_type
|
|
||||||
{
|
|
||||||
uint8 state;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void construct_value_type(value_type* pDst, const Key& k, const Value& v)
|
|
||||||
{
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE(Key))
|
|
||||||
memcpy(&pDst->first, &k, sizeof(Key));
|
|
||||||
else
|
|
||||||
scalar_type<Key>::construct(&pDst->first, k);
|
|
||||||
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE(Value))
|
|
||||||
memcpy(&pDst->second, &v, sizeof(Value));
|
|
||||||
else
|
|
||||||
scalar_type<Value>::construct(&pDst->second, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void construct_value_type(value_type* pDst, const value_type* pSrc)
|
|
||||||
{
|
|
||||||
if ((CRNLIB_IS_BITWISE_COPYABLE(Key)) && (CRNLIB_IS_BITWISE_COPYABLE(Value)))
|
|
||||||
{
|
|
||||||
memcpy(pDst, pSrc, sizeof(value_type));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE(Key))
|
|
||||||
memcpy(&pDst->first, &pSrc->first, sizeof(Key));
|
|
||||||
else
|
|
||||||
scalar_type<Key>::construct(&pDst->first, pSrc->first);
|
|
||||||
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE(Value))
|
|
||||||
memcpy(&pDst->second, &pSrc->second, sizeof(Value));
|
|
||||||
else
|
|
||||||
scalar_type<Value>::construct(&pDst->second, pSrc->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void destruct_value_type(value_type* p)
|
|
||||||
{
|
|
||||||
scalar_type<Key>::destruct(&p->first);
|
|
||||||
scalar_type<Value>::destruct(&p->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moves *pSrc to *pDst efficiently.
|
|
||||||
// pDst should NOT be constructed on entry.
|
|
||||||
static inline void move_node(node* pDst, node* pSrc)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(!pDst->state);
|
|
||||||
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE_OR_MOVABLE(Key) && CRNLIB_IS_BITWISE_COPYABLE_OR_MOVABLE(Value))
|
|
||||||
{
|
|
||||||
memcpy(pDst, pSrc, sizeof(node));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE_OR_MOVABLE(Key))
|
|
||||||
memcpy(&pDst->first, &pSrc->first, sizeof(Key));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scalar_type<Key>::construct(&pDst->first, pSrc->first);
|
|
||||||
scalar_type<Key>::destruct(&pSrc->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CRNLIB_IS_BITWISE_COPYABLE_OR_MOVABLE(Value))
|
|
||||||
memcpy(&pDst->second, &pSrc->second, sizeof(Value));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scalar_type<Value>::construct(&pDst->second, pSrc->second);
|
|
||||||
scalar_type<Value>::destruct(&pSrc->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
pDst->state = cStateValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
pSrc->state = cStateInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct raw_node
|
|
||||||
{
|
|
||||||
inline raw_node()
|
|
||||||
{
|
|
||||||
node* p = reinterpret_cast<node*>(this);
|
|
||||||
p->state = cStateInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~raw_node()
|
|
||||||
{
|
|
||||||
node* p = reinterpret_cast<node*>(this);
|
|
||||||
if (p->state)
|
|
||||||
hash_map_type::destruct_value_type(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline raw_node(const raw_node& other)
|
|
||||||
{
|
|
||||||
node* pDst = reinterpret_cast<node*>(this);
|
|
||||||
const node* pSrc = reinterpret_cast<const node*>(&other);
|
|
||||||
|
|
||||||
if (pSrc->state)
|
|
||||||
{
|
|
||||||
hash_map_type::construct_value_type(pDst, pSrc);
|
|
||||||
pDst->state = cStateValid;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pDst->state = cStateInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline raw_node& operator= (const raw_node& rhs)
|
|
||||||
{
|
|
||||||
if (this == &rhs)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
node* pDst = reinterpret_cast<node*>(this);
|
|
||||||
const node* pSrc = reinterpret_cast<const node*>(&rhs);
|
|
||||||
|
|
||||||
if (pSrc->state)
|
|
||||||
{
|
|
||||||
if (pDst->state)
|
|
||||||
{
|
|
||||||
pDst->first = pSrc->first;
|
|
||||||
pDst->second = pSrc->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hash_map_type::construct_value_type(pDst, pSrc);
|
|
||||||
pDst->state = cStateValid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pDst->state)
|
|
||||||
{
|
|
||||||
hash_map_type::destruct_value_type(pDst);
|
|
||||||
pDst->state = cStateInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 m_bits[sizeof(node)];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<raw_node> node_vector;
|
|
||||||
|
|
||||||
node_vector m_values;
|
|
||||||
uint m_hash_shift;
|
|
||||||
|
|
||||||
Hasher m_hasher;
|
|
||||||
Equals m_equals;
|
|
||||||
|
|
||||||
uint m_num_valid;
|
|
||||||
|
|
||||||
uint m_grow_threshold;
|
|
||||||
|
|
||||||
inline int hash_key(const Key& k) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((1U << (32U - m_hash_shift)) == m_values.size());
|
|
||||||
|
|
||||||
uint hash = static_cast<uint>(m_hasher(k));
|
|
||||||
|
|
||||||
// Fibonacci hashing
|
|
||||||
hash = (2654435769U * hash) >> m_hash_shift;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(hash < m_values.size());
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const node& get_node(uint index) const
|
|
||||||
{
|
|
||||||
return *reinterpret_cast<const node*>(&m_values[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline node& get_node(uint index)
|
|
||||||
{
|
|
||||||
return *reinterpret_cast<node*>(&m_values[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline state get_node_state(uint index) const
|
|
||||||
{
|
|
||||||
return static_cast<state>(get_node(index).state);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_node_state(uint index, bool valid)
|
|
||||||
{
|
|
||||||
get_node(index).state = valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void grow()
|
|
||||||
{
|
|
||||||
rehash(math::maximum<uint>(cMinHashSize, m_values.size() * 2U));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void rehash(uint new_hash_size)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(new_hash_size >= m_num_valid);
|
|
||||||
CRNLIB_ASSERT(math::is_power_of_2(new_hash_size));
|
|
||||||
|
|
||||||
if ((new_hash_size < m_num_valid) || (new_hash_size == m_values.size()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
hash_map new_map;
|
|
||||||
new_map.m_values.resize(new_hash_size);
|
|
||||||
new_map.m_hash_shift = 32U - math::floor_log2i(new_hash_size);
|
|
||||||
CRNLIB_ASSERT(new_hash_size == (1U << (32U - new_map.m_hash_shift)));
|
|
||||||
new_map.m_grow_threshold = UINT_MAX;
|
|
||||||
|
|
||||||
node* pNode = reinterpret_cast<node*>(m_values.begin());
|
|
||||||
node* pNode_end = pNode + m_values.size();
|
|
||||||
|
|
||||||
while (pNode != pNode_end)
|
|
||||||
{
|
|
||||||
if (pNode->state)
|
|
||||||
{
|
|
||||||
new_map.move_into(pNode);
|
|
||||||
|
|
||||||
if (new_map.m_num_valid == m_num_valid)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pNode++;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_map.m_grow_threshold = (new_hash_size + 1U) >> 1U;
|
|
||||||
|
|
||||||
m_values.clear_no_destruction();
|
|
||||||
m_hash_shift = 32;
|
|
||||||
|
|
||||||
swap(new_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint find_next(int index) const
|
|
||||||
{
|
|
||||||
index++;
|
|
||||||
|
|
||||||
if (index >= static_cast<int>(m_values.size()))
|
|
||||||
return index;
|
|
||||||
|
|
||||||
const node* pNode = &get_node(index);
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if (pNode->state)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (++index >= static_cast<int>(m_values.size()))
|
|
||||||
break;
|
|
||||||
|
|
||||||
pNode++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint find_index(const Key& k) const
|
|
||||||
{
|
|
||||||
if (m_num_valid)
|
|
||||||
{
|
|
||||||
int index = hash_key(k);
|
|
||||||
const node* pNode = &get_node(index);
|
|
||||||
|
|
||||||
if (pNode->state)
|
|
||||||
{
|
|
||||||
if (m_equals(pNode->first, k))
|
|
||||||
return index;
|
|
||||||
|
|
||||||
const int orig_index = index;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if (!index)
|
|
||||||
{
|
|
||||||
index = m_values.size() - 1;
|
|
||||||
pNode = &get_node(index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
pNode--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == orig_index)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!pNode->state)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (m_equals(pNode->first, k))
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_values.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool insert_no_grow(insert_result& result, const Key& k, const Value& v = Value())
|
|
||||||
{
|
|
||||||
if (!m_values.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int index = hash_key(k);
|
|
||||||
node* pNode = &get_node(index);
|
|
||||||
|
|
||||||
if (pNode->state)
|
|
||||||
{
|
|
||||||
if (m_equals(pNode->first, k))
|
|
||||||
{
|
|
||||||
result.first = iterator(*this, index);
|
|
||||||
result.second = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int orig_index = index;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if (!index)
|
|
||||||
{
|
|
||||||
index = m_values.size() - 1;
|
|
||||||
pNode = &get_node(index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
pNode--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orig_index == index)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!pNode->state)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (m_equals(pNode->first, k))
|
|
||||||
{
|
|
||||||
result.first = iterator(*this, index);
|
|
||||||
result.second = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_num_valid >= m_grow_threshold)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
construct_value_type(pNode, k, v);
|
|
||||||
|
|
||||||
pNode->state = cStateValid;
|
|
||||||
|
|
||||||
m_num_valid++;
|
|
||||||
CRNLIB_ASSERT(m_num_valid <= m_values.size());
|
|
||||||
|
|
||||||
result.first = iterator(*this, index);
|
|
||||||
result.second = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void move_into(node* pNode)
|
|
||||||
{
|
|
||||||
int index = hash_key(pNode->first);
|
|
||||||
node* pDst_node = &get_node(index);
|
|
||||||
|
|
||||||
if (pDst_node->state)
|
|
||||||
{
|
|
||||||
const int orig_index = index;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if (!index)
|
|
||||||
{
|
|
||||||
index = m_values.size() - 1;
|
|
||||||
pDst_node = &get_node(index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
pDst_node--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == orig_index)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pDst_node->state)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
move_node(pDst_node, pNode);
|
|
||||||
|
|
||||||
m_num_valid++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Key, typename Value, typename Hasher, typename Equals>
|
|
||||||
struct bitwise_movable< hash_map<Key, Value, Hasher, Equals> > { enum { cFlag = true }; };
|
|
||||||
|
|
||||||
template<typename Key, typename Value, typename Hasher, typename Equals>
|
|
||||||
inline void swap(hash_map<Key, Value, Hasher, Equals>& a, hash_map<Key, Value, Hasher, Equals>& b)
|
|
||||||
{
|
|
||||||
a.swap(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void hash_map_test();
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,64 +0,0 @@
|
||||||
// File: crn_helpers.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(c) c(const c&); c& operator= (const c&);
|
|
||||||
#define CRNLIB_NO_HEAP_ALLOC() private: static void* operator new(size_t); static void* operator new[](size_t);
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace helpers
|
|
||||||
{
|
|
||||||
template<typename T> struct rel_ops
|
|
||||||
{
|
|
||||||
friend bool operator!=(const T& x, const T& y) { return (!(x == y)); }
|
|
||||||
friend bool operator> (const T& x, const T& y) { return (y < x); }
|
|
||||||
friend bool operator<=(const T& x, const T& y) { return (!(y < x)); }
|
|
||||||
friend bool operator>=(const T& x, const T& y) { return (!(x < y)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline T* construct(T* p)
|
|
||||||
{
|
|
||||||
return new (static_cast<void*>(p)) T;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
inline T* construct(T* p, const U& init)
|
|
||||||
{
|
|
||||||
return new (static_cast<void*>(p)) T(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void construct_array(T* p, uint n)
|
|
||||||
{
|
|
||||||
T* q = p + n;
|
|
||||||
for ( ; p != q; ++p)
|
|
||||||
new (static_cast<void*>(p)) T;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
inline void construct_array(T* p, uint n, const U& init)
|
|
||||||
{
|
|
||||||
T* q = p + n;
|
|
||||||
for ( ; p != q; ++p)
|
|
||||||
new (static_cast<void*>(p)) T(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void destruct(T* p)
|
|
||||||
{
|
|
||||||
p;
|
|
||||||
p->~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> inline void destruct_array(T* p, uint n)
|
|
||||||
{
|
|
||||||
T* q = p + n;
|
|
||||||
for ( ; p != q; ++p)
|
|
||||||
p->~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace helpers
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,387 +0,0 @@
|
||||||
// File: crn_huffman_codes.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_huffman_codes.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
struct sym_freq
|
|
||||||
{
|
|
||||||
uint m_freq;
|
|
||||||
uint16 m_left;
|
|
||||||
uint16 m_right;
|
|
||||||
|
|
||||||
inline bool operator< (const sym_freq& other) const
|
|
||||||
{
|
|
||||||
return m_freq > other.m_freq;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* syms0, sym_freq* syms1)
|
|
||||||
{
|
|
||||||
const uint cMaxPasses = 2;
|
|
||||||
uint hist[256 * cMaxPasses];
|
|
||||||
|
|
||||||
memset(hist, 0, sizeof(hist[0]) * 256 * cMaxPasses);
|
|
||||||
|
|
||||||
sym_freq* p = syms0;
|
|
||||||
sym_freq* q = syms0 + (num_syms >> 1) * 2;
|
|
||||||
|
|
||||||
for ( ; p != q; p += 2)
|
|
||||||
{
|
|
||||||
const uint freq0 = p[0].m_freq;
|
|
||||||
const uint freq1 = p[1].m_freq;
|
|
||||||
|
|
||||||
hist[ freq0 & 0xFF]++;
|
|
||||||
hist[256 + ((freq0 >> 8) & 0xFF)]++;
|
|
||||||
|
|
||||||
hist[ freq1 & 0xFF]++;
|
|
||||||
hist[256 + ((freq1 >> 8) & 0xFF)]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_syms & 1)
|
|
||||||
{
|
|
||||||
const uint freq = p->m_freq;
|
|
||||||
|
|
||||||
hist[ freq & 0xFF]++;
|
|
||||||
hist[256 + ((freq >> 8) & 0xFF)]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
sym_freq* pCur_syms = syms0;
|
|
||||||
sym_freq* pNew_syms = syms1;
|
|
||||||
|
|
||||||
for (uint pass = 0; pass < cMaxPasses; pass++)
|
|
||||||
{
|
|
||||||
const uint* pHist = &hist[pass << 8];
|
|
||||||
|
|
||||||
uint offsets[256];
|
|
||||||
|
|
||||||
uint cur_ofs = 0;
|
|
||||||
for (uint i = 0; i < 256; i += 2)
|
|
||||||
{
|
|
||||||
offsets[i] = cur_ofs;
|
|
||||||
cur_ofs += pHist[i];
|
|
||||||
|
|
||||||
offsets[i+1] = cur_ofs;
|
|
||||||
cur_ofs += pHist[i+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint pass_shift = pass << 3;
|
|
||||||
|
|
||||||
sym_freq* p = pCur_syms;
|
|
||||||
sym_freq* q = pCur_syms + (num_syms >> 1) * 2;
|
|
||||||
|
|
||||||
for ( ; p != q; p += 2)
|
|
||||||
{
|
|
||||||
uint c0 = p[0].m_freq;
|
|
||||||
uint c1 = p[1].m_freq;
|
|
||||||
|
|
||||||
if (pass)
|
|
||||||
{
|
|
||||||
c0 >>= 8;
|
|
||||||
c1 >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
c0 &= 0xFF;
|
|
||||||
c1 &= 0xFF;
|
|
||||||
|
|
||||||
if (c0 == c1)
|
|
||||||
{
|
|
||||||
uint dst_offset0 = offsets[c0];
|
|
||||||
|
|
||||||
offsets[c0] = dst_offset0 + 2;
|
|
||||||
|
|
||||||
pNew_syms[dst_offset0] = p[0];
|
|
||||||
pNew_syms[dst_offset0 + 1] = p[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint dst_offset0 = offsets[c0]++;
|
|
||||||
uint dst_offset1 = offsets[c1]++;
|
|
||||||
|
|
||||||
pNew_syms[dst_offset0] = p[0];
|
|
||||||
pNew_syms[dst_offset1] = p[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_syms & 1)
|
|
||||||
{
|
|
||||||
uint c = ((p->m_freq) >> pass_shift) & 0xFF;
|
|
||||||
|
|
||||||
uint dst_offset = offsets[c];
|
|
||||||
offsets[c] = dst_offset + 1;
|
|
||||||
|
|
||||||
pNew_syms[dst_offset] = *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
sym_freq* t = pCur_syms;
|
|
||||||
pCur_syms = pNew_syms;
|
|
||||||
pNew_syms = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CRNLIB_ASSERTS_ENABLED
|
|
||||||
uint prev_freq = 0;
|
|
||||||
for (uint i = 0; i < num_syms; i++)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(!(pCur_syms[i].m_freq < prev_freq));
|
|
||||||
prev_freq = pCur_syms[i].m_freq;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return pCur_syms;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct huffman_work_tables
|
|
||||||
{
|
|
||||||
enum { cMaxInternalNodes = cHuffmanMaxSupportedSyms };
|
|
||||||
|
|
||||||
sym_freq syms0[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
|
|
||||||
sym_freq syms1[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
|
|
||||||
|
|
||||||
uint16 queue[cMaxInternalNodes];
|
|
||||||
};
|
|
||||||
|
|
||||||
void* create_generate_huffman_codes_tables()
|
|
||||||
{
|
|
||||||
return crnlib_new<huffman_work_tables>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_generate_huffman_codes_tables(void* p)
|
|
||||||
{
|
|
||||||
crnlib_delete(static_cast<huffman_work_tables*>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if USE_CALCULATE_MINIMUM_REDUNDANCY
|
|
||||||
/* calculate_minimum_redundancy() written by
|
|
||||||
Alistair Moffat, alistair@cs.mu.oz.au,
|
|
||||||
Jyrki Katajainen, jyrki@diku.dk
|
|
||||||
November 1996.
|
|
||||||
*/
|
|
||||||
static void calculate_minimum_redundancy(int A[], int n) {
|
|
||||||
int root; /* next root node to be used */
|
|
||||||
int leaf; /* next leaf to be used */
|
|
||||||
int next; /* next value to be assigned */
|
|
||||||
int avbl; /* number of available nodes */
|
|
||||||
int used; /* number of internal nodes */
|
|
||||||
int dpth; /* current depth of leaves */
|
|
||||||
|
|
||||||
/* check for pathological cases */
|
|
||||||
if (n==0) { return; }
|
|
||||||
if (n==1) { A[0] = 0; return; }
|
|
||||||
|
|
||||||
/* first pass, left to right, setting parent pointers */
|
|
||||||
A[0] += A[1]; root = 0; leaf = 2;
|
|
||||||
for (next=1; next < n-1; next++) {
|
|
||||||
/* select first item for a pairing */
|
|
||||||
if (leaf>=n || A[root]<A[leaf]) {
|
|
||||||
A[next] = A[root]; A[root++] = next;
|
|
||||||
} else
|
|
||||||
A[next] = A[leaf++];
|
|
||||||
|
|
||||||
/* add on the second item */
|
|
||||||
if (leaf>=n || (root<next && A[root]<A[leaf])) {
|
|
||||||
A[next] += A[root]; A[root++] = next;
|
|
||||||
} else
|
|
||||||
A[next] += A[leaf++];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* second pass, right to left, setting internal depths */
|
|
||||||
A[n-2] = 0;
|
|
||||||
for (next=n-3; next>=0; next--)
|
|
||||||
A[next] = A[A[next]]+1;
|
|
||||||
|
|
||||||
/* third pass, right to left, setting leaf depths */
|
|
||||||
avbl = 1; used = dpth = 0; root = n-2; next = n-1;
|
|
||||||
while (avbl>0) {
|
|
||||||
while (root>=0 && A[root]==dpth) {
|
|
||||||
used++; root--;
|
|
||||||
}
|
|
||||||
while (avbl>used) {
|
|
||||||
A[next--] = dpth; avbl--;
|
|
||||||
}
|
|
||||||
avbl = 2*used; dpth++; used = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret)
|
|
||||||
{
|
|
||||||
if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);;
|
|
||||||
|
|
||||||
uint max_freq = 0;
|
|
||||||
uint total_freq = 0;
|
|
||||||
|
|
||||||
uint num_used_syms = 0;
|
|
||||||
for (uint i = 0; i < num_syms; i++)
|
|
||||||
{
|
|
||||||
uint freq = pFreq[i];
|
|
||||||
|
|
||||||
if (!freq)
|
|
||||||
pCodesizes[i] = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
total_freq += freq;
|
|
||||||
max_freq = math::maximum(max_freq, freq);
|
|
||||||
|
|
||||||
sym_freq& sf = state.syms0[num_used_syms];
|
|
||||||
sf.m_left = (uint16)i;
|
|
||||||
sf.m_right = cUINT16_MAX;
|
|
||||||
sf.m_freq = freq;
|
|
||||||
num_used_syms++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_freq_ret = total_freq;
|
|
||||||
|
|
||||||
if (num_used_syms == 1)
|
|
||||||
{
|
|
||||||
pCodesizes[state.syms0[0].m_left] = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1);
|
|
||||||
|
|
||||||
#if USE_CALCULATE_MINIMUM_REDUNDANCY
|
|
||||||
int x[cHuffmanMaxSupportedSyms];
|
|
||||||
for (uint i = 0; i < num_used_syms; i++)
|
|
||||||
x[i] = state.syms0[i].m_freq;
|
|
||||||
|
|
||||||
calculate_minimum_redundancy(x, num_used_syms);
|
|
||||||
|
|
||||||
uint max_len = 0;
|
|
||||||
for (uint i = 0; i < num_used_syms; i++)
|
|
||||||
{
|
|
||||||
uint len = x[i];
|
|
||||||
max_len = math::maximum(len, max_len);
|
|
||||||
pCodesizes[state.syms0[i].m_left] = static_cast<uint8>(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
// Dummy node
|
|
||||||
sym_freq& sf = state.syms0[num_used_syms];
|
|
||||||
sf.m_left = cUINT16_MAX;
|
|
||||||
sf.m_right = cUINT16_MAX;
|
|
||||||
sf.m_freq = UINT_MAX;
|
|
||||||
|
|
||||||
uint next_internal_node = num_used_syms + 1;
|
|
||||||
|
|
||||||
uint queue_front = 0;
|
|
||||||
uint queue_end = 0;
|
|
||||||
|
|
||||||
uint next_lowest_sym = 0;
|
|
||||||
|
|
||||||
uint num_nodes_remaining = num_used_syms;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint left_freq = syms[next_lowest_sym].m_freq;
|
|
||||||
uint left_child = next_lowest_sym;
|
|
||||||
|
|
||||||
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < left_freq))
|
|
||||||
{
|
|
||||||
left_child = state.queue[queue_front];
|
|
||||||
left_freq = syms[left_child].m_freq;
|
|
||||||
|
|
||||||
queue_front++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
next_lowest_sym++;
|
|
||||||
|
|
||||||
uint right_freq = syms[next_lowest_sym].m_freq;
|
|
||||||
uint right_child = next_lowest_sym;
|
|
||||||
|
|
||||||
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < right_freq))
|
|
||||||
{
|
|
||||||
right_child = state.queue[queue_front];
|
|
||||||
right_freq = syms[right_child].m_freq;
|
|
||||||
|
|
||||||
queue_front++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
next_lowest_sym++;
|
|
||||||
|
|
||||||
const uint internal_node_index = next_internal_node;
|
|
||||||
next_internal_node++;
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(next_internal_node < CRNLIB_ARRAYSIZE(state.syms0));
|
|
||||||
|
|
||||||
syms[internal_node_index].m_freq = left_freq + right_freq;
|
|
||||||
syms[internal_node_index].m_left = static_cast<uint16>(left_child);
|
|
||||||
syms[internal_node_index].m_right = static_cast<uint16>(right_child);
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes);
|
|
||||||
state.queue[queue_end] = static_cast<uint16>(internal_node_index);
|
|
||||||
queue_end++;
|
|
||||||
|
|
||||||
num_nodes_remaining--;
|
|
||||||
|
|
||||||
} while (num_nodes_remaining > 1);
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(next_lowest_sym == num_used_syms);
|
|
||||||
CRNLIB_ASSERT((queue_end - queue_front) == 1);
|
|
||||||
|
|
||||||
uint cur_node_index = state.queue[queue_front];
|
|
||||||
|
|
||||||
uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0;
|
|
||||||
uint32* pStack_top = pStack;
|
|
||||||
|
|
||||||
uint max_level = 0;
|
|
||||||
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
uint level = cur_node_index >> 16;
|
|
||||||
uint node_index = cur_node_index & 0xFFFF;
|
|
||||||
|
|
||||||
uint left_child = syms[node_index].m_left;
|
|
||||||
uint right_child = syms[node_index].m_right;
|
|
||||||
|
|
||||||
uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000;
|
|
||||||
|
|
||||||
if (left_child < num_used_syms)
|
|
||||||
{
|
|
||||||
max_level = math::maximum(max_level, level);
|
|
||||||
|
|
||||||
pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1);
|
|
||||||
|
|
||||||
if (right_child < num_used_syms)
|
|
||||||
{
|
|
||||||
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
|
|
||||||
|
|
||||||
if (pStack == pStack_top) break;
|
|
||||||
cur_node_index = *--pStack;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cur_node_index = next_level | right_child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (right_child < num_used_syms)
|
|
||||||
{
|
|
||||||
max_level = math::maximum(max_level, level);
|
|
||||||
|
|
||||||
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
|
|
||||||
|
|
||||||
cur_node_index = next_level | left_child;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*pStack++ = next_level | left_child;
|
|
||||||
|
|
||||||
cur_node_index = next_level | right_child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
max_code_size = max_level + 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
// File: crn_huffman_codes.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
const uint cHuffmanMaxSupportedSyms = 8192;
|
|
||||||
|
|
||||||
void* create_generate_huffman_codes_tables();
|
|
||||||
void free_generate_huffman_codes_tables(void* p);
|
|
||||||
|
|
||||||
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret);
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,723 +0,0 @@
|
||||||
// File: crn_image.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_color.h"
|
|
||||||
#include "crn_vec.h"
|
|
||||||
#include "crn_pixel_format.h"
|
|
||||||
#include "crn_rect.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
template<typename color_type>
|
|
||||||
class image
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef color_type color_t;
|
|
||||||
|
|
||||||
typedef crnlib::vector<color_type> pixel_buf_t;
|
|
||||||
|
|
||||||
image() :
|
|
||||||
m_width(0),
|
|
||||||
m_height(0),
|
|
||||||
m_pitch(0),
|
|
||||||
m_total(0),
|
|
||||||
m_comp_flags(pixel_format_helpers::cDefaultCompFlags),
|
|
||||||
m_pPixels(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// pitch is in PIXELS, not bytes.
|
|
||||||
image(uint width, uint height, uint pitch = UINT_MAX, const color_type& background = color_type::make_black(), uint flags = pixel_format_helpers::cDefaultCompFlags) :
|
|
||||||
m_comp_flags(flags)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((width > 0) && (height > 0));
|
|
||||||
if (pitch == UINT_MAX)
|
|
||||||
pitch = width;
|
|
||||||
|
|
||||||
m_pixel_buf.resize(pitch * height);
|
|
||||||
|
|
||||||
m_width = width;
|
|
||||||
m_height = height;
|
|
||||||
m_pitch = pitch;
|
|
||||||
m_total = m_pitch * m_height;
|
|
||||||
|
|
||||||
m_pPixels = &m_pixel_buf.front();
|
|
||||||
|
|
||||||
set_all(background);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pitch is in PIXELS, not bytes.
|
|
||||||
image(color_type* pPixels, uint width, uint height, uint pitch = UINT_MAX, uint flags = pixel_format_helpers::cDefaultCompFlags)
|
|
||||||
{
|
|
||||||
alias(pPixels, width, height, pitch, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
image& operator= (const image& other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
if (other.m_pixel_buf.empty())
|
|
||||||
{
|
|
||||||
// This doesn't look very safe - let's make a new instance.
|
|
||||||
//m_pixel_buf.clear();
|
|
||||||
//m_pPixels = other.m_pPixels;
|
|
||||||
|
|
||||||
const uint total_pixels = other.m_pitch * other.m_height;
|
|
||||||
if ((total_pixels) && (other.m_pPixels))
|
|
||||||
{
|
|
||||||
m_pixel_buf.resize(total_pixels);
|
|
||||||
m_pixel_buf.insert(0, other.m_pPixels, m_pixel_buf.size());
|
|
||||||
m_pPixels = &m_pixel_buf.front();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_pixel_buf.clear();
|
|
||||||
m_pPixels = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_pixel_buf = other.m_pixel_buf;
|
|
||||||
m_pPixels = &m_pixel_buf.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_width = other.m_width;
|
|
||||||
m_height = other.m_height;
|
|
||||||
m_pitch = other.m_pitch;
|
|
||||||
m_total = other.m_total;
|
|
||||||
m_comp_flags = other.m_comp_flags;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
image(const image& other) :
|
|
||||||
m_width(0), m_height(0), m_pitch(0), m_total(0), m_comp_flags(pixel_format_helpers::cDefaultCompFlags), m_pPixels(NULL)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pitch is in PIXELS, not bytes.
|
|
||||||
void alias(color_type* pPixels, uint width, uint height, uint pitch = UINT_MAX, uint flags = pixel_format_helpers::cDefaultCompFlags)
|
|
||||||
{
|
|
||||||
m_pixel_buf.clear();
|
|
||||||
|
|
||||||
m_pPixels = pPixels;
|
|
||||||
|
|
||||||
m_width = width;
|
|
||||||
m_height = height;
|
|
||||||
m_pitch = (pitch == UINT_MAX) ? width : pitch;
|
|
||||||
m_total = m_pitch * m_height;
|
|
||||||
m_comp_flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pitch is in PIXELS, not bytes.
|
|
||||||
bool grant_ownership(color_type* pPixels, uint width, uint height, uint pitch = UINT_MAX, uint flags = pixel_format_helpers::cDefaultCompFlags)
|
|
||||||
{
|
|
||||||
if (pitch == UINT_MAX)
|
|
||||||
pitch = width;
|
|
||||||
|
|
||||||
if ((!pPixels) || (!width) || (!height) || (pitch < width))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pPixels == get_ptr())
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if (!m_pixel_buf.grant_ownership(pPixels, height * pitch, height * pitch))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_pPixels = pPixels;
|
|
||||||
|
|
||||||
m_width = width;
|
|
||||||
m_height = height;
|
|
||||||
m_pitch = pitch;
|
|
||||||
m_total = pitch * height;
|
|
||||||
m_comp_flags = flags;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_pPixels = NULL;
|
|
||||||
m_pixel_buf.clear();
|
|
||||||
m_width = 0;
|
|
||||||
m_height = 0;
|
|
||||||
m_pitch = 0;
|
|
||||||
m_total = 0;
|
|
||||||
m_comp_flags = pixel_format_helpers::cDefaultCompFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_valid() const { return m_total > 0; }
|
|
||||||
|
|
||||||
inline pixel_format_helpers::component_flags get_comp_flags() const { return static_cast<pixel_format_helpers::component_flags>(m_comp_flags); }
|
|
||||||
inline void set_comp_flags(pixel_format_helpers::component_flags new_flags) { m_comp_flags = new_flags; }
|
|
||||||
inline void reset_comp_flags() { m_comp_flags = pixel_format_helpers::cDefaultCompFlags; }
|
|
||||||
|
|
||||||
inline bool is_component_valid(uint index) const { CRNLIB_ASSERT(index < 4U); return utils::is_flag_set(m_comp_flags, index); }
|
|
||||||
inline void set_component_valid(uint index, bool state) { CRNLIB_ASSERT(index < 4U); utils::set_flag(m_comp_flags, index, state); }
|
|
||||||
|
|
||||||
inline bool has_rgb() const { return is_component_valid(0) || is_component_valid(1) || is_component_valid(2); }
|
|
||||||
inline bool has_alpha() const { return is_component_valid(3); }
|
|
||||||
|
|
||||||
inline bool is_grayscale() const { return utils::is_bit_set(m_comp_flags, pixel_format_helpers::cCompFlagGrayscale); }
|
|
||||||
inline void set_grayscale(bool state) { utils::set_bit(m_comp_flags, pixel_format_helpers::cCompFlagGrayscale, state); }
|
|
||||||
|
|
||||||
void set_all(const color_type& c)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_total; i++)
|
|
||||||
m_pPixels[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flip_x()
|
|
||||||
{
|
|
||||||
const uint half_width = m_width / 2;
|
|
||||||
for (uint y = 0; y < m_height; y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < half_width; x++)
|
|
||||||
{
|
|
||||||
color_type c((*this)(x, y));
|
|
||||||
(*this)(x, y) = (*this)(m_width - 1 - x, y);
|
|
||||||
(*this)(m_width - 1 - x, y) = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void flip_y()
|
|
||||||
{
|
|
||||||
const uint half_height = m_height / 2;
|
|
||||||
for (uint y = 0; y < half_height; y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < m_width; x++)
|
|
||||||
{
|
|
||||||
color_type c((*this)(x, y));
|
|
||||||
(*this)(x, y) = (*this)(x, m_height - 1 - y);
|
|
||||||
(*this)(x, m_height - 1 - y) = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void convert_to_grayscale()
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < m_height; y++)
|
|
||||||
for (uint x = 0; x < m_width; x++)
|
|
||||||
{
|
|
||||||
color_type c((*this)(x, y));
|
|
||||||
typename color_type::component_t l = static_cast< typename color_type::component_t >(c.get_luma());
|
|
||||||
c.r = l;
|
|
||||||
c.g = l;
|
|
||||||
c.b = l;
|
|
||||||
(*this)(x, y) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_grayscale(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void swizzle(uint r, uint g, uint b, uint a)
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < m_height; y++)
|
|
||||||
for (uint x = 0; x < m_width; x++)
|
|
||||||
{
|
|
||||||
const color_type& c = (*this)(x, y);
|
|
||||||
|
|
||||||
(*this)(x, y) = color_type(c[r], c[g], c[b], c[a]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_alpha_to_luma()
|
|
||||||
{
|
|
||||||
for (uint y = 0; y < m_height; y++)
|
|
||||||
for (uint x = 0; x < m_width; x++)
|
|
||||||
{
|
|
||||||
color_type c((*this)(x, y));
|
|
||||||
typename color_type::component_t l = static_cast< typename color_type::component_t >(c.get_luma());
|
|
||||||
c.a = l;
|
|
||||||
(*this)(x, y) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_component_valid(3, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool extract_block(color_type* pDst, uint x, uint y, uint w, uint h, bool flip_xy = false) const
|
|
||||||
{
|
|
||||||
if ((x >= m_width) || (y >= m_height))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flip_xy)
|
|
||||||
{
|
|
||||||
for (uint y_ofs = 0; y_ofs < h; y_ofs++)
|
|
||||||
for (uint x_ofs = 0; x_ofs < w; x_ofs++)
|
|
||||||
pDst[x_ofs * h + y_ofs] = get_clamped(x_ofs + x, y_ofs + y); // 5/4/12 - this was incorrectly x_ofs * 4
|
|
||||||
}
|
|
||||||
else if (((x + w) > m_width) || ((y + h) > m_height))
|
|
||||||
{
|
|
||||||
for (uint y_ofs = 0; y_ofs < h; y_ofs++)
|
|
||||||
for (uint x_ofs = 0; x_ofs < w; x_ofs++)
|
|
||||||
*pDst++ = get_clamped(x_ofs + x, y_ofs + y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const color_type* pSrc = get_scanline(y) + x;
|
|
||||||
|
|
||||||
for (uint i = h; i; i--)
|
|
||||||
{
|
|
||||||
memcpy(pDst, pSrc, w * sizeof(color_type));
|
|
||||||
pDst += w;
|
|
||||||
|
|
||||||
pSrc += m_pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No clipping!
|
|
||||||
void unclipped_fill_box(uint x, uint y, uint w, uint h, const color_type& c)
|
|
||||||
{
|
|
||||||
if (((x + w) > m_width) || ((y + h) > m_height))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
color_type* p = get_scanline(y) + x;
|
|
||||||
|
|
||||||
for (uint i = h; i; i--)
|
|
||||||
{
|
|
||||||
color_type* q = p;
|
|
||||||
for (uint j = w; j; j--)
|
|
||||||
*q++ = c;
|
|
||||||
p += m_pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_rect(int x, int y, uint width, uint height, const color_type& c)
|
|
||||||
{
|
|
||||||
draw_line(x, y, x + width - 1, y, c);
|
|
||||||
draw_line(x, y, x, y + height - 1, c);
|
|
||||||
draw_line(x + width - 1, y, x + width - 1, y + height - 1, c);
|
|
||||||
draw_line(x, y + height - 1, x + width - 1, y + height - 1, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// No clipping!
|
|
||||||
bool unclipped_blit(uint src_x, uint src_y, uint src_w, uint src_h, uint dst_x, uint dst_y, const image& src)
|
|
||||||
{
|
|
||||||
if ((!is_valid()) || (!src.is_valid()))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ((src_x + src_w) > src.get_width()) || ((src_y + src_h) > src.get_height()) )
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ((dst_x + src_w) > get_width()) || ((dst_y + src_h) > get_height()) )
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const color_type* pS = &src(src_x, src_y);
|
|
||||||
color_type* pD = &(*this)(dst_x, dst_y);
|
|
||||||
|
|
||||||
const uint bytes_to_copy = src_w * sizeof(color_type);
|
|
||||||
for (uint i = src_h; i; i--)
|
|
||||||
{
|
|
||||||
memcpy(pD, pS, bytes_to_copy);
|
|
||||||
|
|
||||||
pS += src.get_pitch();
|
|
||||||
pD += get_pitch();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// With clipping.
|
|
||||||
bool blit(int dst_x, int dst_y, const image& src)
|
|
||||||
{
|
|
||||||
if ((!is_valid()) || (!src.is_valid()))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int src_x = 0;
|
|
||||||
int src_y = 0;
|
|
||||||
|
|
||||||
if (dst_x < 0)
|
|
||||||
{
|
|
||||||
src_x = -dst_x;
|
|
||||||
if (src_x >= static_cast<int>(src.get_width()))
|
|
||||||
return false;
|
|
||||||
dst_x = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dst_y < 0)
|
|
||||||
{
|
|
||||||
src_y = -dst_y;
|
|
||||||
if (src_y >= static_cast<int>(src.get_height()))
|
|
||||||
return false;
|
|
||||||
dst_y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dst_x >= (int)m_width) || (dst_y >= (int)m_height))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint width = math::minimum(m_width - dst_x, src.get_width() - src_x);
|
|
||||||
uint height = math::minimum(m_height - dst_y, src.get_height() - src_y);
|
|
||||||
|
|
||||||
bool success = unclipped_blit(src_x, src_y, width, height, dst_x, dst_y, src);
|
|
||||||
success;
|
|
||||||
CRNLIB_ASSERT(success);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// With clipping.
|
|
||||||
bool blit(int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, const image& src)
|
|
||||||
{
|
|
||||||
if ((!is_valid()) || (!src.is_valid()))
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rect src_rect(src_x, src_y, src_x + src_w, src_y + src_h);
|
|
||||||
if (!src_rect.intersect(src.get_bounds()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
rect dst_rect(dst_x, dst_y, dst_x + src_rect.get_width(), dst_y + src_rect.get_height());
|
|
||||||
if (!dst_rect.intersect(get_bounds()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool success = unclipped_blit(
|
|
||||||
src_rect.get_left(), src_rect.get_top(),
|
|
||||||
math::minimum(src_rect.get_width(), dst_rect.get_width()), math::minimum(src_rect.get_height(), dst_rect.get_height()),
|
|
||||||
dst_rect.get_left(), dst_rect.get_top(), src);
|
|
||||||
success;
|
|
||||||
CRNLIB_ASSERT(success);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In-place resize of image dimensions (cropping).
|
|
||||||
bool resize(uint new_width, uint new_height, uint new_pitch = UINT_MAX, const color_type background = color_type::make_black())
|
|
||||||
{
|
|
||||||
if (new_pitch == UINT_MAX)
|
|
||||||
new_pitch = new_width;
|
|
||||||
|
|
||||||
if ((new_width == m_width) && (new_height == m_height) && (new_pitch == m_pitch))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ((!new_width) || (!new_height) || (!new_pitch))
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixel_buf_t existing_pixels;
|
|
||||||
existing_pixels.swap(m_pixel_buf);
|
|
||||||
|
|
||||||
if (!m_pixel_buf.try_resize(new_height * new_pitch))
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint y = 0; y < new_height; y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x < new_width; x++)
|
|
||||||
{
|
|
||||||
if ((x < m_width) && (y < m_height))
|
|
||||||
m_pixel_buf[x + y * new_pitch] = existing_pixels[x + y * m_pitch];
|
|
||||||
else
|
|
||||||
m_pixel_buf[x + y * new_pitch] = background;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_width = new_width;
|
|
||||||
m_height = new_height;
|
|
||||||
m_pitch = new_pitch;
|
|
||||||
m_total = new_pitch * new_height;
|
|
||||||
m_pPixels = &m_pixel_buf.front();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint get_width() const { return m_width; }
|
|
||||||
inline uint get_height() const { return m_height; }
|
|
||||||
inline uint get_total_pixels() const { return m_width * m_height; }
|
|
||||||
|
|
||||||
inline rect get_bounds() const { return rect(0, 0, m_width, m_height); }
|
|
||||||
|
|
||||||
inline uint get_pitch() const { return m_pitch; }
|
|
||||||
inline uint get_pitch_in_bytes() const { return m_pitch * sizeof(color_type); }
|
|
||||||
|
|
||||||
// Returns pitch * height, NOT width * height!
|
|
||||||
inline uint get_total() const { return m_total; }
|
|
||||||
|
|
||||||
inline uint get_block_width(uint block_size) const { return (m_width + block_size - 1) / block_size; }
|
|
||||||
inline uint get_block_height(uint block_size) const { return (m_height + block_size - 1) / block_size; }
|
|
||||||
inline uint get_total_blocks(uint block_size) const { return get_block_width(block_size) * get_block_height(block_size); }
|
|
||||||
|
|
||||||
inline uint get_size_in_bytes() const { return sizeof(color_type) * m_total; }
|
|
||||||
|
|
||||||
inline const color_type* get_pixels() const { return m_pPixels; }
|
|
||||||
inline color_type* get_pixels() { return m_pPixels; }
|
|
||||||
|
|
||||||
inline const color_type& operator() (uint x, uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < m_width) && (y < m_height));
|
|
||||||
return m_pPixels[x + y * m_pitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_type& operator() (uint x, uint y)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < m_width) && (y < m_height));
|
|
||||||
return m_pPixels[x + y * m_pitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const color_type& get_unclamped(uint x, uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < m_width) && (y < m_height));
|
|
||||||
return m_pPixels[x + y * m_pitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const color_type& get_clamped(int x, int y) const
|
|
||||||
{
|
|
||||||
x = math::clamp<int>(x, 0, m_width - 1);
|
|
||||||
y = math::clamp<int>(y, 0, m_height - 1);
|
|
||||||
return m_pPixels[x + y * m_pitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample image with bilinear filtering.
|
|
||||||
// (x,y) - Continuous coordinates, where pixel centers are at (.5,.5), valid image coords are [0,width] and [0,height].
|
|
||||||
void get_filtered(float x, float y, color_type& result) const
|
|
||||||
{
|
|
||||||
x -= .5f;
|
|
||||||
y -= .5f;
|
|
||||||
|
|
||||||
int ix = (int)floor(x);
|
|
||||||
int iy = (int)floor(y);
|
|
||||||
float wx = x - ix;
|
|
||||||
float wy = y - iy;
|
|
||||||
|
|
||||||
color_type a(get_clamped(ix, iy));
|
|
||||||
color_type b(get_clamped(ix + 1, iy));
|
|
||||||
color_type c(get_clamped(ix, iy + 1));
|
|
||||||
color_type d(get_clamped(ix + 1, iy + 1));
|
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
double top = math::lerp<double>(a[i], b[i], wx);
|
|
||||||
double bot = math::lerp<double>(c[i], d[i], wx);
|
|
||||||
double m = math::lerp<double>(top, bot, wy);
|
|
||||||
|
|
||||||
if (!color_type::component_traits::cFloat)
|
|
||||||
m += .5f;
|
|
||||||
|
|
||||||
result.set_component(i, static_cast< typename color_type::parameter_t >(m));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_filtered(float x, float y, vec4F& result) const
|
|
||||||
{
|
|
||||||
x -= .5f;
|
|
||||||
y -= .5f;
|
|
||||||
|
|
||||||
int ix = (int)floor(x);
|
|
||||||
int iy = (int)floor(y);
|
|
||||||
float wx = x - ix;
|
|
||||||
float wy = y - iy;
|
|
||||||
|
|
||||||
color_type a(get_clamped(ix, iy));
|
|
||||||
color_type b(get_clamped(ix + 1, iy));
|
|
||||||
color_type c(get_clamped(ix, iy + 1));
|
|
||||||
color_type d(get_clamped(ix + 1, iy + 1));
|
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
float top = math::lerp<float>(a[i], b[i], wx);
|
|
||||||
float bot = math::lerp<float>(c[i], d[i], wx);
|
|
||||||
float m = math::lerp<float>(top, bot, wy);
|
|
||||||
|
|
||||||
result[i] = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_pixel_unclipped(uint x, uint y, const color_type& c)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((x < m_width) && (y < m_height));
|
|
||||||
m_pPixels[x + y * m_pitch] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set_pixel_clipped(int x, int y, const color_type& c)
|
|
||||||
{
|
|
||||||
if ((static_cast<uint>(x) >= m_width) || (static_cast<uint>(y) >= m_height))
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_pPixels[x + y * m_pitch] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const color_type* get_scanline(uint y) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(y < m_height);
|
|
||||||
return &m_pPixels[y * m_pitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_type* get_scanline(uint y)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(y < m_height);
|
|
||||||
return &m_pPixels[y * m_pitch];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const color_type* get_ptr() const
|
|
||||||
{
|
|
||||||
return m_pPixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline color_type* get_ptr()
|
|
||||||
{
|
|
||||||
return m_pPixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swap(image& other)
|
|
||||||
{
|
|
||||||
utils::swap(m_width, other.m_width);
|
|
||||||
utils::swap(m_height, other.m_height);
|
|
||||||
utils::swap(m_pitch, other.m_pitch);
|
|
||||||
utils::swap(m_total, other.m_total);
|
|
||||||
utils::swap(m_comp_flags, other.m_comp_flags);
|
|
||||||
utils::swap(m_pPixels, other.m_pPixels);
|
|
||||||
m_pixel_buf.swap(other.m_pixel_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_line(int xs, int ys, int xe, int ye, const color_type& color)
|
|
||||||
{
|
|
||||||
if (xs > xe)
|
|
||||||
{
|
|
||||||
utils::swap(xs, xe);
|
|
||||||
utils::swap(ys, ye);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dx = xe - xs, dy = ye - ys;
|
|
||||||
if (!dx)
|
|
||||||
{
|
|
||||||
if (ys > ye)
|
|
||||||
utils::swap(ys, ye);
|
|
||||||
for (int i = ys ; i <= ye ; i++)
|
|
||||||
set_pixel_clipped(xs, i, color);
|
|
||||||
}
|
|
||||||
else if (!dy)
|
|
||||||
{
|
|
||||||
for (int i = xs ; i < xe ; i++)
|
|
||||||
set_pixel_clipped(i, ys, color);
|
|
||||||
}
|
|
||||||
else if (dy > 0)
|
|
||||||
{
|
|
||||||
if (dy <= dx)
|
|
||||||
{
|
|
||||||
int e = 2 * dy - dx, e_no_inc = 2 * dy, e_inc = 2 * (dy - dx);
|
|
||||||
rasterize_line(xs, ys, xe, ye, 0, 1, e, e_inc, e_no_inc, color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int e = 2 * dx - dy, e_no_inc = 2 * dx, e_inc = 2 * (dx - dy);
|
|
||||||
rasterize_line(xs, ys, xe, ye, 1, 1, e, e_inc, e_no_inc, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dy = -dy;
|
|
||||||
if (dy <= dx)
|
|
||||||
{
|
|
||||||
int e = 2 * dy - dx, e_no_inc = 2 * dy, e_inc = 2 * (dy - dx);
|
|
||||||
rasterize_line(xs, ys, xe, ye, 0, -1, e, e_inc, e_no_inc, color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int e = 2 * dx - dy, e_no_inc = (2 * dx), e_inc = 2 * (dx - dy);
|
|
||||||
rasterize_line(xe, ye, xs, ys, 1, -1, e, e_inc, e_no_inc, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const pixel_buf_t& get_pixel_buf() const { return m_pixel_buf; }
|
|
||||||
pixel_buf_t& get_pixel_buf() { return m_pixel_buf; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint m_width;
|
|
||||||
uint m_height;
|
|
||||||
uint m_pitch;
|
|
||||||
uint m_total;
|
|
||||||
uint m_comp_flags;
|
|
||||||
|
|
||||||
color_type* m_pPixels;
|
|
||||||
|
|
||||||
pixel_buf_t m_pixel_buf;
|
|
||||||
|
|
||||||
void rasterize_line(int xs, int ys, int xe, int ye, int pred, int inc_dec, int e, int e_inc, int e_no_inc, const color_type& color)
|
|
||||||
{
|
|
||||||
int start, end, var;
|
|
||||||
|
|
||||||
if (pred)
|
|
||||||
{
|
|
||||||
start = ys; end = ye; var = xs;
|
|
||||||
for (int i = start; i <= end; i++)
|
|
||||||
{
|
|
||||||
set_pixel_clipped(var, i, color);
|
|
||||||
if (e < 0)
|
|
||||||
e += e_no_inc;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var += inc_dec;
|
|
||||||
e += e_inc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
start = xs; end = xe; var = ys;
|
|
||||||
for (int i = start; i <= end; i++)
|
|
||||||
{
|
|
||||||
set_pixel_clipped(i, var, color);
|
|
||||||
if (e < 0)
|
|
||||||
e += e_no_inc;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var += inc_dec;
|
|
||||||
e += e_inc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef image<color_quad_u8> image_u8;
|
|
||||||
typedef image<color_quad_i16> image_i16;
|
|
||||||
typedef image<color_quad_u16> image_u16;
|
|
||||||
typedef image<color_quad_i32> image_i32;
|
|
||||||
typedef image<color_quad_u32> image_u32;
|
|
||||||
typedef image<color_quad_f> image_f;
|
|
||||||
|
|
||||||
template<typename color_type>
|
|
||||||
inline void swap(image<color_type>& a, image<color_type>& b)
|
|
||||||
{
|
|
||||||
a.swap(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,193 +0,0 @@
|
||||||
// File: crn_image_utils.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_image.h"
|
|
||||||
#include "crn_data_stream_serializer.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
enum pixel_format;
|
|
||||||
|
|
||||||
namespace image_utils
|
|
||||||
{
|
|
||||||
enum read_flags_t
|
|
||||||
{
|
|
||||||
cReadFlagForceSTB = 1,
|
|
||||||
|
|
||||||
cReadFlagsAllFlags = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
bool read_from_stream_stb(data_stream_serializer& serializer, image_u8& img);
|
|
||||||
bool read_from_stream_jpgd(data_stream_serializer& serializer, image_u8& img);
|
|
||||||
bool read_from_stream(image_u8& dest, data_stream_serializer& serializer, uint read_flags = 0);
|
|
||||||
bool read_from_file(image_u8& dest, const char* pFilename, uint read_flags = 0);
|
|
||||||
|
|
||||||
// Reads texture from memory, results returned stb_image.c style.
|
|
||||||
// *pActual_comps is set to 1, 3, or 4. req_comps must range from 1-4.
|
|
||||||
uint8* read_from_memory(const uint8* pImage, int nSize, int* pWidth, int* pHeight, int* pActualComps, int req_comps, const char* pFilename);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cWriteFlagIgnoreAlpha = 0x00000001,
|
|
||||||
cWriteFlagGrayscale = 0x00000002,
|
|
||||||
|
|
||||||
cWriteFlagJPEGH1V1 = 0x00010000,
|
|
||||||
cWriteFlagJPEGH2V1 = 0x00020000,
|
|
||||||
cWriteFlagJPEGH2V2 = 0x00040000,
|
|
||||||
cWriteFlagJPEGTwoPass = 0x00080000,
|
|
||||||
cWriteFlagJPEGNoChromaDiscrim = 0x00100000,
|
|
||||||
cWriteFlagJPEGQualityLevelMask = 0xFF000000,
|
|
||||||
cWriteFlagJPEGQualityLevelShift = 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
const int cLumaComponentIndex = -1;
|
|
||||||
|
|
||||||
inline uint create_jpeg_write_flags(uint base_flags, uint quality_level) { CRNLIB_ASSERT(quality_level <= 100); return base_flags | ((quality_level << cWriteFlagJPEGQualityLevelShift) & cWriteFlagJPEGQualityLevelMask); }
|
|
||||||
|
|
||||||
bool write_to_file(const char* pFilename, const image_u8& img, uint write_flags = 0, int grayscale_comp_index = cLumaComponentIndex);
|
|
||||||
|
|
||||||
bool has_alpha(const image_u8& img);
|
|
||||||
bool is_normal_map(const image_u8& img, const char* pFilename = NULL);
|
|
||||||
void renorm_normal_map(image_u8& img);
|
|
||||||
|
|
||||||
struct resample_params
|
|
||||||
{
|
|
||||||
resample_params() :
|
|
||||||
m_dst_width(0),
|
|
||||||
m_dst_height(0),
|
|
||||||
m_pFilter("lanczos4"),
|
|
||||||
m_filter_scale(1.0f),
|
|
||||||
m_srgb(true),
|
|
||||||
m_wrapping(false),
|
|
||||||
m_first_comp(0),
|
|
||||||
m_num_comps(4),
|
|
||||||
m_source_gamma(2.2f), // 1.75f
|
|
||||||
m_multithreaded(true)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint m_dst_width;
|
|
||||||
uint m_dst_height;
|
|
||||||
const char* m_pFilter;
|
|
||||||
float m_filter_scale;
|
|
||||||
bool m_srgb;
|
|
||||||
bool m_wrapping;
|
|
||||||
uint m_first_comp;
|
|
||||||
uint m_num_comps;
|
|
||||||
float m_source_gamma;
|
|
||||||
bool m_multithreaded;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool resample_single_thread(const image_u8& src, image_u8& dst, const resample_params& params);
|
|
||||||
bool resample_multithreaded(const image_u8& src, image_u8& dst, const resample_params& params);
|
|
||||||
bool resample(const image_u8& src, image_u8& dst, const resample_params& params);
|
|
||||||
|
|
||||||
bool compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2);
|
|
||||||
|
|
||||||
class error_metrics
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
error_metrics() { utils::zero_this(this); }
|
|
||||||
|
|
||||||
void print(const char* pName) const;
|
|
||||||
|
|
||||||
// If num_channels==0, luma error is computed.
|
|
||||||
// If pHist != NULL, it must point to a 256 entry array.
|
|
||||||
bool compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error = true);
|
|
||||||
|
|
||||||
uint mMax;
|
|
||||||
double mMean;
|
|
||||||
double mMeanSquared;
|
|
||||||
double mRootMeanSquared;
|
|
||||||
double mPeakSNR;
|
|
||||||
|
|
||||||
inline bool operator== (const error_metrics& other) const
|
|
||||||
{
|
|
||||||
return mPeakSNR == other.mPeakSNR;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator< (const error_metrics& other) const
|
|
||||||
{
|
|
||||||
return mPeakSNR < other.mPeakSNR;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator> (const error_metrics& other) const
|
|
||||||
{
|
|
||||||
return mPeakSNR > other.mPeakSNR;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void print_image_metrics(const image_u8& src_img, const image_u8& dst_img);
|
|
||||||
|
|
||||||
double compute_block_ssim(uint n, const uint8* pX, const uint8* pY);
|
|
||||||
double compute_ssim(const image_u8& a, const image_u8& b, int channel_index);
|
|
||||||
void print_ssim(const image_u8& src_img, const image_u8& dst_img);
|
|
||||||
|
|
||||||
enum conversion_type
|
|
||||||
{
|
|
||||||
cConversion_Invalid = -1,
|
|
||||||
|
|
||||||
cConversion_To_CCxY,
|
|
||||||
cConversion_From_CCxY,
|
|
||||||
|
|
||||||
cConversion_To_xGxR,
|
|
||||||
cConversion_From_xGxR,
|
|
||||||
|
|
||||||
cConversion_To_xGBR,
|
|
||||||
cConversion_From_xGBR,
|
|
||||||
|
|
||||||
cConversion_To_AGBR,
|
|
||||||
cConversion_From_AGBR,
|
|
||||||
|
|
||||||
cConversion_XY_to_XYZ,
|
|
||||||
|
|
||||||
cConversion_Y_To_A,
|
|
||||||
|
|
||||||
cConversion_A_To_RGBA,
|
|
||||||
cConversion_Y_To_RGB,
|
|
||||||
|
|
||||||
cConversion_To_Y,
|
|
||||||
|
|
||||||
cConversionTotal
|
|
||||||
};
|
|
||||||
|
|
||||||
void convert_image(image_u8& img, conversion_type conv_type);
|
|
||||||
|
|
||||||
template<typename image_type>
|
|
||||||
inline uint8* pack_image(const image_type& img, const pixel_packer& packer, uint& n)
|
|
||||||
{
|
|
||||||
n = 0;
|
|
||||||
|
|
||||||
if (!packer.is_valid())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
const uint width = img.get_width(), height = img.get_height();
|
|
||||||
uint dst_pixel_stride = packer.get_pixel_stride();
|
|
||||||
uint dst_pitch = width * dst_pixel_stride;
|
|
||||||
|
|
||||||
n = dst_pitch * height;
|
|
||||||
|
|
||||||
uint8* pImage = static_cast<uint8*>(crnlib_malloc(n));
|
|
||||||
|
|
||||||
uint8* pDst = pImage;
|
|
||||||
for (uint y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
const typename image_type::color_t* pSrc = img.get_scanline(y);
|
|
||||||
for (uint x = 0; x < width; x++)
|
|
||||||
pDst = (uint8*)packer.pack(*pSrc++, pDst);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
image_utils::conversion_type get_conversion_type(bool cooking, pixel_format fmt);
|
|
||||||
|
|
||||||
image_utils::conversion_type get_image_conversion_type_from_crn_format(crn_format fmt);
|
|
||||||
|
|
||||||
double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels);
|
|
||||||
|
|
||||||
uint8* read_image_from_memory(const uint8* pImage, int nSize, int* pWidth, int* pHeight, int* pActualComps, int req_comps, const char* pFilename);
|
|
||||||
|
|
||||||
} // namespace image_utils
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,123 +0,0 @@
|
||||||
// File: crn_intersect.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_ray.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace intersection
|
|
||||||
{
|
|
||||||
enum result
|
|
||||||
{
|
|
||||||
cBackfacing = -1,
|
|
||||||
cFailure = 0,
|
|
||||||
cSuccess,
|
|
||||||
cParallel,
|
|
||||||
cInside,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns cInside, cSuccess, or cFailure.
|
|
||||||
// Algorithm: Graphics Gems 1
|
|
||||||
template<typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
|
|
||||||
result ray_aabb(vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
cNumDim = vector_type::num_elements,
|
|
||||||
cRight = 0,
|
|
||||||
cLeft = 1,
|
|
||||||
cMiddle = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
bool inside = true;
|
|
||||||
int quadrant[cNumDim];
|
|
||||||
scalar_type candidate_plane[cNumDim];
|
|
||||||
|
|
||||||
for (int i = 0; i < cNumDim; i++)
|
|
||||||
{
|
|
||||||
if (ray.get_origin()[i] < box[0][i])
|
|
||||||
{
|
|
||||||
quadrant[i] = cLeft;
|
|
||||||
candidate_plane[i] = box[0][i];
|
|
||||||
inside = false;
|
|
||||||
}
|
|
||||||
else if (ray.get_origin()[i] > box[1][i])
|
|
||||||
{
|
|
||||||
quadrant[i] = cRight;
|
|
||||||
candidate_plane[i] = box[1][i];
|
|
||||||
inside = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
quadrant[i] = cMiddle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inside)
|
|
||||||
{
|
|
||||||
coord = ray.get_origin();
|
|
||||||
t = 0.0f;
|
|
||||||
return cInside;
|
|
||||||
}
|
|
||||||
|
|
||||||
scalar_type max_t[cNumDim];
|
|
||||||
for (int i = 0; i < cNumDim; i++)
|
|
||||||
{
|
|
||||||
if ((quadrant[i] != cMiddle) && (ray.get_direction()[i] != 0.0f))
|
|
||||||
max_t[i] = (candidate_plane[i] - ray.get_origin()[i]) / ray.get_direction()[i];
|
|
||||||
else
|
|
||||||
max_t[i] = -1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int which_plane = 0;
|
|
||||||
for (int i = 1; i < cNumDim; i++)
|
|
||||||
if (max_t[which_plane] < max_t[i])
|
|
||||||
which_plane = i;
|
|
||||||
|
|
||||||
if (max_t[which_plane] < 0.0f)
|
|
||||||
return cFailure;
|
|
||||||
|
|
||||||
for (int i = 0; i < cNumDim; i++)
|
|
||||||
{
|
|
||||||
if (i != which_plane)
|
|
||||||
{
|
|
||||||
coord[i] = ray.get_origin()[i] + max_t[which_plane] * ray.get_direction()[i];
|
|
||||||
|
|
||||||
if ( (coord[i] < box[0][i]) || (coord[i] > box[1][i]) )
|
|
||||||
return cFailure;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
coord[i] = candidate_plane[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(coord[i] >= box[0][i] && coord[i] <= box[1][i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
t = max_t[which_plane];
|
|
||||||
return cSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
|
|
||||||
result ray_aabb(bool& started_within, vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
|
|
||||||
{
|
|
||||||
if (!box.contains(ray.get_origin()))
|
|
||||||
{
|
|
||||||
started_within = false;
|
|
||||||
return ray_aabb(coord, t, ray, box);
|
|
||||||
}
|
|
||||||
|
|
||||||
started_within = true;
|
|
||||||
|
|
||||||
float diag_dist = box.diagonal_length() * 1.5f;
|
|
||||||
ray_type outside_ray(ray.eval(diag_dist), -ray.get_direction());
|
|
||||||
|
|
||||||
result res(ray_aabb(coord, t, outside_ray, box));
|
|
||||||
if (res != cSuccess)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
t = math::maximum(0.0f, diag_dist - t);
|
|
||||||
return cSuccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,319 +0,0 @@
|
||||||
// jpgd.h - C++ class for JPEG decompression.
|
|
||||||
// Public domain, Rich Geldreich <richgel99@gmail.com>
|
|
||||||
#ifndef JPEG_DECODER_H
|
|
||||||
#define JPEG_DECODER_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define JPGD_NORETURN __declspec(noreturn)
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#define JPGD_NORETURN __attribute__ ((noreturn))
|
|
||||||
#else
|
|
||||||
#define JPGD_NORETURN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace jpgd
|
|
||||||
{
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
typedef signed short int16;
|
|
||||||
typedef unsigned short uint16;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef signed int int32;
|
|
||||||
|
|
||||||
// Loads a JPEG image from a memory buffer or a file.
|
|
||||||
// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
|
|
||||||
// On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
|
|
||||||
// Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
|
|
||||||
// Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
|
|
||||||
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps);
|
|
||||||
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps);
|
|
||||||
|
|
||||||
// Success/failure error codes.
|
|
||||||
enum jpgd_status
|
|
||||||
{
|
|
||||||
JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
|
|
||||||
JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
|
|
||||||
JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
|
|
||||||
JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
|
|
||||||
JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
|
|
||||||
JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
|
|
||||||
JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
|
|
||||||
JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR,
|
|
||||||
JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM
|
|
||||||
};
|
|
||||||
|
|
||||||
// Input stream interface.
|
|
||||||
// Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available.
|
|
||||||
// The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set.
|
|
||||||
// It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer.
|
|
||||||
// Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding.
|
|
||||||
class jpeg_decoder_stream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
jpeg_decoder_stream() { }
|
|
||||||
virtual ~jpeg_decoder_stream() { }
|
|
||||||
|
|
||||||
// The read() method is called when the internal input buffer is empty.
|
|
||||||
// Parameters:
|
|
||||||
// pBuf - input buffer
|
|
||||||
// max_bytes_to_read - maximum bytes that can be written to pBuf
|
|
||||||
// pEOF_flag - set this to true if at end of stream (no more bytes remaining)
|
|
||||||
// Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
|
|
||||||
// Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
|
|
||||||
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// stdio FILE stream class.
|
|
||||||
class jpeg_decoder_file_stream : public jpeg_decoder_stream
|
|
||||||
{
|
|
||||||
jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
|
|
||||||
jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
|
|
||||||
|
|
||||||
FILE *m_pFile;
|
|
||||||
bool m_eof_flag, m_error_flag;
|
|
||||||
|
|
||||||
public:
|
|
||||||
jpeg_decoder_file_stream();
|
|
||||||
virtual ~jpeg_decoder_file_stream();
|
|
||||||
|
|
||||||
bool open(const char *Pfilename);
|
|
||||||
void close();
|
|
||||||
|
|
||||||
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Memory stream class.
|
|
||||||
class jpeg_decoder_mem_stream : public jpeg_decoder_stream
|
|
||||||
{
|
|
||||||
const uint8 *m_pSrc_data;
|
|
||||||
uint m_ofs, m_size;
|
|
||||||
|
|
||||||
public:
|
|
||||||
jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { }
|
|
||||||
jpeg_decoder_mem_stream(const uint8 *pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { }
|
|
||||||
|
|
||||||
virtual ~jpeg_decoder_mem_stream() { }
|
|
||||||
|
|
||||||
bool open(const uint8 *pSrc_data, uint size);
|
|
||||||
void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; }
|
|
||||||
|
|
||||||
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Loads JPEG file from a jpeg_decoder_stream.
|
|
||||||
unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
|
|
||||||
JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int16 jpgd_quant_t;
|
|
||||||
typedef int16 jpgd_block_t;
|
|
||||||
|
|
||||||
class jpeg_decoder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc.
|
|
||||||
// methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
|
|
||||||
jpeg_decoder(jpeg_decoder_stream *pStream);
|
|
||||||
|
|
||||||
~jpeg_decoder();
|
|
||||||
|
|
||||||
// Call this method after constructing the object to begin decompression.
|
|
||||||
// If JPGD_SUCCESS is returned you may then call decode() on each scanline.
|
|
||||||
int begin_decoding();
|
|
||||||
|
|
||||||
// Returns the next scan line.
|
|
||||||
// For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
|
|
||||||
// Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
|
|
||||||
// Returns JPGD_SUCCESS if a scan line has been returned.
|
|
||||||
// Returns JPGD_DONE if all scan lines have been returned.
|
|
||||||
// Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info.
|
|
||||||
int decode(const void** pScan_line, uint* pScan_line_len);
|
|
||||||
|
|
||||||
inline jpgd_status get_error_code() const { return m_error_code; }
|
|
||||||
|
|
||||||
inline int get_width() const { return m_image_x_size; }
|
|
||||||
inline int get_height() const { return m_image_y_size; }
|
|
||||||
|
|
||||||
inline int get_num_components() const { return m_comps_in_frame; }
|
|
||||||
|
|
||||||
inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; }
|
|
||||||
inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); }
|
|
||||||
|
|
||||||
// Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
|
|
||||||
inline int get_total_bytes_read() const { return m_total_bytes_read; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
jpeg_decoder(const jpeg_decoder &);
|
|
||||||
jpeg_decoder &operator =(const jpeg_decoder &);
|
|
||||||
|
|
||||||
typedef void (*pDecode_block_func)(jpeg_decoder *, int, int, int);
|
|
||||||
|
|
||||||
struct huff_tables
|
|
||||||
{
|
|
||||||
bool ac_table;
|
|
||||||
uint look_up[256];
|
|
||||||
uint look_up2[256];
|
|
||||||
uint8 code_size[256];
|
|
||||||
uint tree[512];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct coeff_buf
|
|
||||||
{
|
|
||||||
uint8 *pData;
|
|
||||||
int block_num_x, block_num_y;
|
|
||||||
int block_len_x, block_len_y;
|
|
||||||
int block_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mem_block
|
|
||||||
{
|
|
||||||
mem_block *m_pNext;
|
|
||||||
size_t m_used_count;
|
|
||||||
size_t m_size;
|
|
||||||
char m_data[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
jmp_buf m_jmp_state;
|
|
||||||
mem_block *m_pMem_blocks;
|
|
||||||
int m_image_x_size;
|
|
||||||
int m_image_y_size;
|
|
||||||
jpeg_decoder_stream *m_pStream;
|
|
||||||
int m_progressive_flag;
|
|
||||||
uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES];
|
|
||||||
uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size
|
|
||||||
uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size
|
|
||||||
jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables
|
|
||||||
int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
|
|
||||||
int m_comps_in_frame; // # of components in frame
|
|
||||||
int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor
|
|
||||||
int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor
|
|
||||||
int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector
|
|
||||||
int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID
|
|
||||||
int m_comp_h_blocks[JPGD_MAX_COMPONENTS];
|
|
||||||
int m_comp_v_blocks[JPGD_MAX_COMPONENTS];
|
|
||||||
int m_comps_in_scan; // # of components in scan
|
|
||||||
int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan
|
|
||||||
int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector
|
|
||||||
int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector
|
|
||||||
int m_spectral_start; // spectral selection start
|
|
||||||
int m_spectral_end; // spectral selection end
|
|
||||||
int m_successive_low; // successive approximation low
|
|
||||||
int m_successive_high; // successive approximation high
|
|
||||||
int m_max_mcu_x_size; // MCU's max. X size in pixels
|
|
||||||
int m_max_mcu_y_size; // MCU's max. Y size in pixels
|
|
||||||
int m_blocks_per_mcu;
|
|
||||||
int m_max_blocks_per_row;
|
|
||||||
int m_mcus_per_row, m_mcus_per_col;
|
|
||||||
int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU];
|
|
||||||
int m_total_lines_left; // total # lines left in image
|
|
||||||
int m_mcu_lines_left; // total # lines left in this MCU
|
|
||||||
int m_real_dest_bytes_per_scan_line;
|
|
||||||
int m_dest_bytes_per_scan_line; // rounded up
|
|
||||||
int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y)
|
|
||||||
huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES];
|
|
||||||
coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS];
|
|
||||||
coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS];
|
|
||||||
int m_eob_run;
|
|
||||||
int m_block_y_mcu[JPGD_MAX_COMPONENTS];
|
|
||||||
uint8* m_pIn_buf_ofs;
|
|
||||||
int m_in_buf_left;
|
|
||||||
int m_tem_flag;
|
|
||||||
bool m_eof_flag;
|
|
||||||
uint8 m_in_buf_pad_start[128];
|
|
||||||
uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128];
|
|
||||||
uint8 m_in_buf_pad_end[128];
|
|
||||||
int m_bits_left;
|
|
||||||
uint m_bit_buf;
|
|
||||||
int m_restart_interval;
|
|
||||||
int m_restarts_left;
|
|
||||||
int m_next_restart_num;
|
|
||||||
int m_max_mcus_per_row;
|
|
||||||
int m_max_blocks_per_mcu;
|
|
||||||
int m_expanded_blocks_per_mcu;
|
|
||||||
int m_expanded_blocks_per_row;
|
|
||||||
int m_expanded_blocks_per_component;
|
|
||||||
bool m_freq_domain_chroma_upsample;
|
|
||||||
int m_max_mcus_per_col;
|
|
||||||
uint m_last_dc_val[JPGD_MAX_COMPONENTS];
|
|
||||||
jpgd_block_t* m_pMCU_coefficients;
|
|
||||||
int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU];
|
|
||||||
uint8* m_pSample_buf;
|
|
||||||
int m_crr[256];
|
|
||||||
int m_cbb[256];
|
|
||||||
int m_crg[256];
|
|
||||||
int m_cbg[256];
|
|
||||||
uint8* m_pScan_line_0;
|
|
||||||
uint8* m_pScan_line_1;
|
|
||||||
jpgd_status m_error_code;
|
|
||||||
bool m_ready_flag;
|
|
||||||
int m_total_bytes_read;
|
|
||||||
|
|
||||||
void free_all_blocks();
|
|
||||||
JPGD_NORETURN void stop_decoding(jpgd_status status);
|
|
||||||
void *alloc(size_t n, bool zero = false);
|
|
||||||
void word_clear(void *p, uint16 c, uint n);
|
|
||||||
void prep_in_buffer();
|
|
||||||
void read_dht_marker();
|
|
||||||
void read_dqt_marker();
|
|
||||||
void read_sof_marker();
|
|
||||||
void skip_variable_marker();
|
|
||||||
void read_dri_marker();
|
|
||||||
void read_sos_marker();
|
|
||||||
int next_marker();
|
|
||||||
int process_markers();
|
|
||||||
void locate_soi_marker();
|
|
||||||
void locate_sof_marker();
|
|
||||||
int locate_sos_marker();
|
|
||||||
void init(jpeg_decoder_stream * pStream);
|
|
||||||
void create_look_ups();
|
|
||||||
void fix_in_buffer();
|
|
||||||
void transform_mcu(int mcu_row);
|
|
||||||
void transform_mcu_expand(int mcu_row);
|
|
||||||
coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y);
|
|
||||||
inline jpgd_block_t *coeff_buf_getp(coeff_buf *cb, int block_x, int block_y);
|
|
||||||
void load_next_row();
|
|
||||||
void decode_next_row();
|
|
||||||
void make_huff_table(int index, huff_tables *pH);
|
|
||||||
void check_quant_tables();
|
|
||||||
void check_huff_tables();
|
|
||||||
void calc_mcu_block_order();
|
|
||||||
int init_scan();
|
|
||||||
void init_frame();
|
|
||||||
void process_restart();
|
|
||||||
void decode_scan(pDecode_block_func decode_block_func);
|
|
||||||
void init_progressive();
|
|
||||||
void init_sequential();
|
|
||||||
void decode_start();
|
|
||||||
void decode_init(jpeg_decoder_stream * pStream);
|
|
||||||
void H2V2Convert();
|
|
||||||
void H2V1Convert();
|
|
||||||
void H1V2Convert();
|
|
||||||
void H1V1Convert();
|
|
||||||
void gray_convert();
|
|
||||||
void expanded_convert();
|
|
||||||
void find_eoi();
|
|
||||||
inline uint get_char();
|
|
||||||
inline uint get_char(bool *pPadding_flag);
|
|
||||||
inline void stuff_char(uint8 q);
|
|
||||||
inline uint8 get_octet();
|
|
||||||
inline uint get_bits(int num_bits);
|
|
||||||
inline uint get_bits_no_markers(int numbits);
|
|
||||||
inline int huff_decode(huff_tables *pH);
|
|
||||||
inline int huff_decode(huff_tables *pH, int& extrabits);
|
|
||||||
static inline uint8 clamp(int i);
|
|
||||||
static void decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
|
|
||||||
static void decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
|
|
||||||
static void decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
|
|
||||||
static void decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace jpgd
|
|
||||||
|
|
||||||
#endif // JPEG_DECODER_H
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,169 +0,0 @@
|
||||||
// jpge.h - C++ class for JPEG compression.
|
|
||||||
// Public domain, Rich Geldreich <richgel99@gmail.com>
|
|
||||||
// Alex Evans: Added RGBA support, linear memory allocator.
|
|
||||||
#ifndef JPEG_ENCODER_H
|
|
||||||
#define JPEG_ENCODER_H
|
|
||||||
|
|
||||||
namespace jpge
|
|
||||||
{
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
typedef signed short int16;
|
|
||||||
typedef signed int int32;
|
|
||||||
typedef unsigned short uint16;
|
|
||||||
typedef unsigned int uint32;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
|
|
||||||
// JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common.
|
|
||||||
enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 };
|
|
||||||
|
|
||||||
// JPEG compression parameters structure.
|
|
||||||
struct params
|
|
||||||
{
|
|
||||||
inline params() : m_quality(85), m_subsampling(H2V2), m_no_chroma_discrim_flag(false), m_two_pass_flag(false) { }
|
|
||||||
|
|
||||||
inline bool check() const
|
|
||||||
{
|
|
||||||
if ((m_quality < 1) || (m_quality > 100)) return false;
|
|
||||||
if ((uint)m_subsampling > (uint)H2V2) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quality: 1-100, higher is better. Typical values are around 50-95.
|
|
||||||
int m_quality;
|
|
||||||
|
|
||||||
// m_subsampling:
|
|
||||||
// 0 = Y (grayscale) only
|
|
||||||
// 1 = YCbCr, no subsampling (H1V1, YCbCr 1x1x1, 3 blocks per MCU)
|
|
||||||
// 2 = YCbCr, H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU)
|
|
||||||
// 3 = YCbCr, H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common)
|
|
||||||
subsampling_t m_subsampling;
|
|
||||||
|
|
||||||
// Disables CbCr discrimination - only intended for testing.
|
|
||||||
// If true, the Y quantization table is also used for the CbCr channels.
|
|
||||||
bool m_no_chroma_discrim_flag;
|
|
||||||
|
|
||||||
bool m_two_pass_flag;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Writes JPEG image to a file.
|
|
||||||
// num_channels must be 1 (Y) or 3 (RGB), image pitch must be width*num_channels.
|
|
||||||
bool compress_image_to_jpeg_file(const char *pFilename, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params = params());
|
|
||||||
|
|
||||||
// Writes JPEG image to memory buffer.
|
|
||||||
// On entry, buf_size is the size of the output buffer pointed at by pBuf, which should be at least ~1024 bytes.
|
|
||||||
// If return value is true, buf_size will be set to the size of the compressed data.
|
|
||||||
bool compress_image_to_jpeg_file_in_memory(void *pBuf, int &buf_size, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params = params());
|
|
||||||
|
|
||||||
// Output stream abstract class - used by the jpeg_encoder class to write to the output stream.
|
|
||||||
// put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts.
|
|
||||||
class output_stream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~output_stream() { };
|
|
||||||
virtual bool put_buf(const void* Pbuf, int len) = 0;
|
|
||||||
template<class T> inline bool put_obj(const T& obj) { return put_buf(&obj, sizeof(T)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Lower level jpeg_encoder class - useful if more control is needed than the above helper functions.
|
|
||||||
class jpeg_encoder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
jpeg_encoder();
|
|
||||||
~jpeg_encoder();
|
|
||||||
|
|
||||||
// Initializes the compressor.
|
|
||||||
// pStream: The stream object to use for writing compressed data.
|
|
||||||
// params - Compression parameters structure, defined above.
|
|
||||||
// width, height - Image dimensions.
|
|
||||||
// channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data.
|
|
||||||
// Returns false on out of memory or if a stream write fails.
|
|
||||||
bool init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params = params());
|
|
||||||
|
|
||||||
const params &get_params() const { return m_params; }
|
|
||||||
|
|
||||||
// Deinitializes the compressor, freeing any allocated memory. May be called at any time.
|
|
||||||
void deinit();
|
|
||||||
|
|
||||||
uint get_total_passes() const { return m_params.m_two_pass_flag ? 2 : 1; }
|
|
||||||
inline uint get_cur_pass() { return m_pass_num; }
|
|
||||||
|
|
||||||
// Call this method with each source scanline.
|
|
||||||
// width * src_channels bytes per scanline is expected (RGB or Y format).
|
|
||||||
// You must call with NULL after all scanlines are processed to finish compression.
|
|
||||||
// Returns false on out of memory or if a stream write fails.
|
|
||||||
bool process_scanline(const void* pScanline);
|
|
||||||
|
|
||||||
private:
|
|
||||||
jpeg_encoder(const jpeg_encoder &);
|
|
||||||
jpeg_encoder &operator =(const jpeg_encoder &);
|
|
||||||
|
|
||||||
typedef int32 sample_array_t;
|
|
||||||
|
|
||||||
output_stream *m_pStream;
|
|
||||||
params m_params;
|
|
||||||
uint8 m_num_components;
|
|
||||||
uint8 m_comp_h_samp[3], m_comp_v_samp[3];
|
|
||||||
int m_image_x, m_image_y, m_image_bpp, m_image_bpl;
|
|
||||||
int m_image_x_mcu, m_image_y_mcu;
|
|
||||||
int m_image_bpl_xlt, m_image_bpl_mcu;
|
|
||||||
int m_mcus_per_row;
|
|
||||||
int m_mcu_x, m_mcu_y;
|
|
||||||
uint8 *m_mcu_lines[16];
|
|
||||||
uint8 m_mcu_y_ofs;
|
|
||||||
sample_array_t m_sample_array[64];
|
|
||||||
int16 m_coefficient_array[64];
|
|
||||||
int32 m_quantization_tables[2][64];
|
|
||||||
uint m_huff_codes[4][256];
|
|
||||||
uint8 m_huff_code_sizes[4][256];
|
|
||||||
uint8 m_huff_bits[4][17];
|
|
||||||
uint8 m_huff_val[4][256];
|
|
||||||
uint32 m_huff_count[4][256];
|
|
||||||
int m_last_dc_val[3];
|
|
||||||
enum { JPGE_OUT_BUF_SIZE = 2048 };
|
|
||||||
uint8 m_out_buf[JPGE_OUT_BUF_SIZE];
|
|
||||||
uint8 *m_pOut_buf;
|
|
||||||
uint m_out_buf_left;
|
|
||||||
uint32 m_bit_buffer;
|
|
||||||
uint m_bits_in;
|
|
||||||
uint8 m_pass_num;
|
|
||||||
bool m_all_stream_writes_succeeded;
|
|
||||||
|
|
||||||
void optimize_huffman_table(int table_num, int table_len);
|
|
||||||
void emit_byte(uint8 i);
|
|
||||||
void emit_word(uint i);
|
|
||||||
void emit_marker(int marker);
|
|
||||||
void emit_jfif_app0();
|
|
||||||
void emit_dqt();
|
|
||||||
void emit_sof();
|
|
||||||
void emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag);
|
|
||||||
void emit_dhts();
|
|
||||||
void emit_sos();
|
|
||||||
void emit_markers();
|
|
||||||
void compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val);
|
|
||||||
void compute_quant_table(int32 *dst, int16 *src);
|
|
||||||
void adjust_quant_table(int32 *dst, int32 *src);
|
|
||||||
void first_pass_init();
|
|
||||||
bool second_pass_init();
|
|
||||||
bool jpg_open(int p_x_res, int p_y_res, int src_channels);
|
|
||||||
void load_block_8_8_grey(int x);
|
|
||||||
void load_block_8_8(int x, int y, int c);
|
|
||||||
void load_block_16_8(int x, int c);
|
|
||||||
void load_block_16_8_8(int x, int c);
|
|
||||||
void load_quantized_coefficients(int component_num);
|
|
||||||
void flush_output_buffer();
|
|
||||||
void put_bits(uint bits, uint len);
|
|
||||||
void code_coefficients_pass_one(int component_num);
|
|
||||||
void code_coefficients_pass_two(int component_num);
|
|
||||||
void code_block(int component_num);
|
|
||||||
void process_mcu_row();
|
|
||||||
bool terminate_pass_one();
|
|
||||||
bool terminate_pass_two();
|
|
||||||
bool process_end_of_image();
|
|
||||||
void load_mcu(const void* src);
|
|
||||||
void clear();
|
|
||||||
void init();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace jpge
|
|
||||||
|
|
||||||
#endif // JPEG_ENCODER
|
|
|
@ -1,920 +0,0 @@
|
||||||
// File: crn_ktx_texture.cpp
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_ktx_texture.h"
|
|
||||||
#include "crn_console.h"
|
|
||||||
|
|
||||||
// Set #if CRNLIB_KTX_PVRTEX_WORKAROUNDS to 1 to enable various workarounds for oddball KTX files written by PVRTexTool.
|
|
||||||
#define CRNLIB_KTX_PVRTEX_WORKAROUNDS 1
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
const uint8 s_ktx_file_id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
|
|
||||||
|
|
||||||
bool is_packed_pixel_ogl_type(uint32 ogl_type)
|
|
||||||
{
|
|
||||||
switch (ogl_type)
|
|
||||||
{
|
|
||||||
case KTX_UNSIGNED_BYTE_3_3_2:
|
|
||||||
case KTX_UNSIGNED_BYTE_2_3_3_REV:
|
|
||||||
case KTX_UNSIGNED_SHORT_5_6_5:
|
|
||||||
case KTX_UNSIGNED_SHORT_5_6_5_REV:
|
|
||||||
case KTX_UNSIGNED_SHORT_4_4_4_4:
|
|
||||||
case KTX_UNSIGNED_SHORT_4_4_4_4_REV:
|
|
||||||
case KTX_UNSIGNED_SHORT_5_5_5_1:
|
|
||||||
case KTX_UNSIGNED_SHORT_1_5_5_5_REV:
|
|
||||||
case KTX_UNSIGNED_INT_8_8_8_8:
|
|
||||||
case KTX_UNSIGNED_INT_8_8_8_8_REV:
|
|
||||||
case KTX_UNSIGNED_INT_10_10_10_2:
|
|
||||||
case KTX_UNSIGNED_INT_2_10_10_10_REV:
|
|
||||||
case KTX_UNSIGNED_INT_24_8:
|
|
||||||
case KTX_UNSIGNED_INT_10F_11F_11F_REV:
|
|
||||||
case KTX_UNSIGNED_INT_5_9_9_9_REV:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_ogl_type_size(uint32 ogl_type)
|
|
||||||
{
|
|
||||||
switch (ogl_type)
|
|
||||||
{
|
|
||||||
case KTX_UNSIGNED_BYTE:
|
|
||||||
case KTX_BYTE:
|
|
||||||
return 1;
|
|
||||||
case KTX_HALF_FLOAT:
|
|
||||||
case KTX_UNSIGNED_SHORT:
|
|
||||||
case KTX_SHORT:
|
|
||||||
return 2;
|
|
||||||
case KTX_FLOAT:
|
|
||||||
case KTX_UNSIGNED_INT:
|
|
||||||
case KTX_INT:
|
|
||||||
return 4;
|
|
||||||
case KTX_UNSIGNED_BYTE_3_3_2:
|
|
||||||
case KTX_UNSIGNED_BYTE_2_3_3_REV:
|
|
||||||
return 1;
|
|
||||||
case KTX_UNSIGNED_SHORT_5_6_5:
|
|
||||||
case KTX_UNSIGNED_SHORT_5_6_5_REV:
|
|
||||||
case KTX_UNSIGNED_SHORT_4_4_4_4:
|
|
||||||
case KTX_UNSIGNED_SHORT_4_4_4_4_REV:
|
|
||||||
case KTX_UNSIGNED_SHORT_5_5_5_1:
|
|
||||||
case KTX_UNSIGNED_SHORT_1_5_5_5_REV:
|
|
||||||
return 2;
|
|
||||||
case KTX_UNSIGNED_INT_8_8_8_8:
|
|
||||||
case KTX_UNSIGNED_INT_8_8_8_8_REV:
|
|
||||||
case KTX_UNSIGNED_INT_10_10_10_2:
|
|
||||||
case KTX_UNSIGNED_INT_2_10_10_10_REV:
|
|
||||||
case KTX_UNSIGNED_INT_24_8:
|
|
||||||
case KTX_UNSIGNED_INT_10F_11F_11F_REV:
|
|
||||||
case KTX_UNSIGNED_INT_5_9_9_9_REV:
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 get_ogl_base_internal_fmt(uint32 ogl_fmt)
|
|
||||||
{
|
|
||||||
switch (ogl_fmt)
|
|
||||||
{
|
|
||||||
case KTX_ETC1_RGB8_OES:
|
|
||||||
case KTX_RGB_S3TC:
|
|
||||||
case KTX_RGB4_S3TC:
|
|
||||||
case KTX_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT:
|
|
||||||
return KTX_RGB;
|
|
||||||
case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
|
|
||||||
case KTX_RGBA_S3TC:
|
|
||||||
case KTX_RGBA4_S3TC:
|
|
||||||
case KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
|
|
||||||
case KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
|
||||||
case KTX_RGBA_DXT5_S3TC:
|
|
||||||
case KTX_RGBA4_DXT5_S3TC:
|
|
||||||
return KTX_RGBA;
|
|
||||||
case 1:
|
|
||||||
case KTX_RED:
|
|
||||||
case KTX_RED_INTEGER:
|
|
||||||
case KTX_GREEN:
|
|
||||||
case KTX_GREEN_INTEGER:
|
|
||||||
case KTX_BLUE:
|
|
||||||
case KTX_BLUE_INTEGER:
|
|
||||||
case KTX_R8:
|
|
||||||
case KTX_R8UI:
|
|
||||||
case KTX_LUMINANCE8:
|
|
||||||
case KTX_ALPHA:
|
|
||||||
case KTX_LUMINANCE:
|
|
||||||
case KTX_COMPRESSED_RED_RGTC1_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT:
|
|
||||||
case KTX_COMPRESSED_LUMINANCE_LATC1_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
|
|
||||||
return KTX_RED;
|
|
||||||
case 2:
|
|
||||||
case KTX_RG:
|
|
||||||
case KTX_RG8:
|
|
||||||
case KTX_RG_INTEGER:
|
|
||||||
case KTX_LUMINANCE_ALPHA:
|
|
||||||
case KTX_COMPRESSED_RED_GREEN_RGTC2_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
|
|
||||||
case KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
|
|
||||||
return KTX_RG;
|
|
||||||
case 3:
|
|
||||||
case KTX_SRGB:
|
|
||||||
case KTX_RGB:
|
|
||||||
case KTX_RGB_INTEGER:
|
|
||||||
case KTX_BGR:
|
|
||||||
case KTX_BGR_INTEGER:
|
|
||||||
case KTX_RGB8:
|
|
||||||
case KTX_SRGB8:
|
|
||||||
return KTX_RGB;
|
|
||||||
case 4:
|
|
||||||
case KTX_RGBA:
|
|
||||||
case KTX_BGRA:
|
|
||||||
case KTX_RGBA_INTEGER:
|
|
||||||
case KTX_BGRA_INTEGER:
|
|
||||||
case KTX_SRGB_ALPHA:
|
|
||||||
case KTX_SRGB8_ALPHA8:
|
|
||||||
case KTX_RGBA8:
|
|
||||||
return KTX_RGBA;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint& block_dim, uint& bytes_per_block)
|
|
||||||
{
|
|
||||||
uint ogl_type_size = get_ogl_type_size(ogl_type);
|
|
||||||
|
|
||||||
block_dim = 1;
|
|
||||||
bytes_per_block = 0;
|
|
||||||
|
|
||||||
switch (ogl_fmt)
|
|
||||||
{
|
|
||||||
case KTX_COMPRESSED_RED_RGTC1_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT:
|
|
||||||
case KTX_COMPRESSED_LUMINANCE_LATC1_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
|
|
||||||
case KTX_ETC1_RGB8_OES:
|
|
||||||
case KTX_RGB_S3TC:
|
|
||||||
case KTX_RGB4_S3TC:
|
|
||||||
case KTX_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
||||||
case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
|
|
||||||
{
|
|
||||||
block_dim = 4;
|
|
||||||
bytes_per_block = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
|
|
||||||
case KTX_COMPRESSED_RED_GREEN_RGTC2_EXT:
|
|
||||||
case KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
|
|
||||||
case KTX_RGBA_S3TC:
|
|
||||||
case KTX_RGBA4_S3TC:
|
|
||||||
case KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
|
|
||||||
case KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
|
||||||
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
|
||||||
case KTX_RGBA_DXT5_S3TC:
|
|
||||||
case KTX_RGBA4_DXT5_S3TC:
|
|
||||||
{
|
|
||||||
block_dim = 4;
|
|
||||||
bytes_per_block = 16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
case KTX_ALPHA:
|
|
||||||
case KTX_RED:
|
|
||||||
case KTX_GREEN:
|
|
||||||
case KTX_BLUE:
|
|
||||||
case KTX_RED_INTEGER:
|
|
||||||
case KTX_GREEN_INTEGER:
|
|
||||||
case KTX_BLUE_INTEGER:
|
|
||||||
case KTX_LUMINANCE:
|
|
||||||
{
|
|
||||||
bytes_per_block = ogl_type_size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KTX_R8:
|
|
||||||
case KTX_R8UI:
|
|
||||||
case KTX_ALPHA8:
|
|
||||||
case KTX_LUMINANCE8:
|
|
||||||
{
|
|
||||||
bytes_per_block = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
case KTX_RG:
|
|
||||||
case KTX_RG_INTEGER:
|
|
||||||
case KTX_LUMINANCE_ALPHA:
|
|
||||||
{
|
|
||||||
bytes_per_block = 2 * ogl_type_size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KTX_RG8:
|
|
||||||
case KTX_LUMINANCE8_ALPHA8:
|
|
||||||
{
|
|
||||||
bytes_per_block = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
case KTX_SRGB:
|
|
||||||
case KTX_RGB:
|
|
||||||
case KTX_BGR:
|
|
||||||
case KTX_RGB_INTEGER:
|
|
||||||
case KTX_BGR_INTEGER:
|
|
||||||
{
|
|
||||||
bytes_per_block = is_packed_pixel_ogl_type(ogl_type) ? ogl_type_size : (3 * ogl_type_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KTX_RGB8:
|
|
||||||
case KTX_SRGB8:
|
|
||||||
{
|
|
||||||
bytes_per_block = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
case KTX_RGBA:
|
|
||||||
case KTX_BGRA:
|
|
||||||
case KTX_RGBA_INTEGER:
|
|
||||||
case KTX_BGRA_INTEGER:
|
|
||||||
case KTX_SRGB_ALPHA:
|
|
||||||
{
|
|
||||||
bytes_per_block = is_packed_pixel_ogl_type(ogl_type) ? ogl_type_size : (4 * ogl_type_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KTX_SRGB8_ALPHA8:
|
|
||||||
case KTX_RGBA8:
|
|
||||||
{
|
|
||||||
bytes_per_block = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::compute_pixel_info()
|
|
||||||
{
|
|
||||||
if ((!m_header.m_glType) || (!m_header.m_glFormat))
|
|
||||||
{
|
|
||||||
if ((m_header.m_glType) || (m_header.m_glFormat))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Must be a compressed format.
|
|
||||||
if (!get_ogl_fmt_desc(m_header.m_glInternalFormat, m_header.m_glType, m_block_dim, m_bytes_per_block))
|
|
||||||
{
|
|
||||||
#if CRNLIB_KTX_PVRTEX_WORKAROUNDS
|
|
||||||
if ((!m_header.m_glInternalFormat) && (!m_header.m_glType) && (!m_header.m_glTypeSize) && (!m_header.m_glBaseInternalFormat))
|
|
||||||
{
|
|
||||||
// PVRTexTool writes bogus headers when outputting ETC1.
|
|
||||||
console::warning("ktx_texture::compute_pixel_info: Header doesn't specify any format, assuming ETC1 and hoping for the best");
|
|
||||||
m_header.m_glBaseInternalFormat = KTX_RGB;
|
|
||||||
m_header.m_glInternalFormat = KTX_ETC1_RGB8_OES;
|
|
||||||
m_header.m_glTypeSize = 1;
|
|
||||||
m_block_dim = 4;
|
|
||||||
m_bytes_per_block = 8;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_block_dim == 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Must be an uncompressed format.
|
|
||||||
if (!get_ogl_fmt_desc(m_header.m_glFormat, m_header.m_glType, m_block_dim, m_bytes_per_block))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_block_dim > 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::read_from_stream(data_stream_serializer& serializer)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
// Read header
|
|
||||||
if (serializer.read(&m_header, 1, sizeof(m_header)) != sizeof(ktx_header))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check header
|
|
||||||
if (memcmp(s_ktx_file_id, m_header.m_identifier, sizeof(m_header.m_identifier)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((m_header.m_endianness != KTX_OPPOSITE_ENDIAN) && (m_header.m_endianness != KTX_ENDIAN))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_opposite_endianness = (m_header.m_endianness == KTX_OPPOSITE_ENDIAN);
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
{
|
|
||||||
m_header.endian_swap();
|
|
||||||
|
|
||||||
if ((m_header.m_glTypeSize != sizeof(uint8)) && (m_header.m_glTypeSize != sizeof(uint16)) && (m_header.m_glTypeSize != sizeof(uint32)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!check_header())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!compute_pixel_info())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint8 pad_bytes[3];
|
|
||||||
|
|
||||||
// Read the key value entries
|
|
||||||
uint num_key_value_bytes_remaining = m_header.m_bytesOfKeyValueData;
|
|
||||||
while (num_key_value_bytes_remaining)
|
|
||||||
{
|
|
||||||
if (num_key_value_bytes_remaining < sizeof(uint32))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32 key_value_byte_size;
|
|
||||||
if (serializer.read(&key_value_byte_size, 1, sizeof(uint32)) != sizeof(uint32))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
num_key_value_bytes_remaining -= sizeof(uint32);
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
key_value_byte_size = utils::swap32(key_value_byte_size);
|
|
||||||
|
|
||||||
if (key_value_byte_size > num_key_value_bytes_remaining)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint8_vec key_value_data;
|
|
||||||
if (key_value_byte_size)
|
|
||||||
{
|
|
||||||
key_value_data.resize(key_value_byte_size);
|
|
||||||
if (serializer.read(&key_value_data[0], 1, key_value_byte_size) != key_value_byte_size)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_key_values.push_back(key_value_data);
|
|
||||||
|
|
||||||
uint padding = 3 - ((key_value_byte_size + 3) % 4);
|
|
||||||
if (padding)
|
|
||||||
{
|
|
||||||
if (serializer.read(pad_bytes, 1, padding) != padding)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
num_key_value_bytes_remaining -= key_value_byte_size;
|
|
||||||
if (num_key_value_bytes_remaining < padding)
|
|
||||||
return false;
|
|
||||||
num_key_value_bytes_remaining -= padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now read the mip levels
|
|
||||||
uint total_faces = get_num_mips() * get_array_size() * get_num_faces() * get_depth();
|
|
||||||
if ((!total_faces) || (total_faces > 65535))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// See Section 2.8 of KTX file format: No rounding to block sizes should be applied for block compressed textures.
|
|
||||||
// OK, I'm going to break that rule otherwise KTX can only store a subset of textures that DDS can handle for no good reason.
|
|
||||||
#if 0
|
|
||||||
const uint mip0_row_blocks = m_header.m_pixelWidth / m_block_dim;
|
|
||||||
const uint mip0_col_blocks = CRNLIB_MAX(1, m_header.m_pixelHeight) / m_block_dim;
|
|
||||||
#else
|
|
||||||
const uint mip0_row_blocks = (m_header.m_pixelWidth + m_block_dim - 1) / m_block_dim;
|
|
||||||
const uint mip0_col_blocks = (CRNLIB_MAX(1, m_header.m_pixelHeight) + m_block_dim - 1) / m_block_dim;
|
|
||||||
#endif
|
|
||||||
if ((!mip0_row_blocks) || (!mip0_col_blocks))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const uint mip0_depth = CRNLIB_MAX(1, m_header.m_pixelDepth); mip0_depth;
|
|
||||||
|
|
||||||
bool has_valid_image_size_fields = true;
|
|
||||||
bool disable_mip_and_cubemap_padding = false;
|
|
||||||
|
|
||||||
#if CRNLIB_KTX_PVRTEX_WORKAROUNDS
|
|
||||||
{
|
|
||||||
// PVRTexTool has a bogus KTX writer that doesn't write any imageSize fields. Nice.
|
|
||||||
size_t expected_bytes_remaining = 0;
|
|
||||||
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
|
|
||||||
{
|
|
||||||
uint mip_width, mip_height, mip_depth;
|
|
||||||
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
|
|
||||||
|
|
||||||
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
|
|
||||||
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
|
|
||||||
if ((!mip_row_blocks) || (!mip_col_blocks))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
expected_bytes_remaining += sizeof(uint32);
|
|
||||||
|
|
||||||
if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6))
|
|
||||||
{
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
|
|
||||||
expected_bytes_remaining += slice_size;
|
|
||||||
|
|
||||||
uint num_cube_pad_bytes = 3 - ((slice_size + 3) % 4);
|
|
||||||
expected_bytes_remaining += num_cube_pad_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint total_mip_size = 0;
|
|
||||||
for (uint array_element = 0; array_element < get_array_size(); array_element++)
|
|
||||||
{
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
for (uint zslice = 0; zslice < mip_depth; zslice++)
|
|
||||||
{
|
|
||||||
uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
|
|
||||||
total_mip_size += slice_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expected_bytes_remaining += total_mip_size;
|
|
||||||
|
|
||||||
uint num_mip_pad_bytes = 3 - ((total_mip_size + 3) % 4);
|
|
||||||
expected_bytes_remaining += num_mip_pad_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serializer.get_stream()->get_remaining() < expected_bytes_remaining)
|
|
||||||
{
|
|
||||||
has_valid_image_size_fields = false;
|
|
||||||
disable_mip_and_cubemap_padding = true;
|
|
||||||
console::warning("ktx_texture::read_from_stream: KTX file size is smaller than expected - trying to read anyway without imageSize fields");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
|
|
||||||
{
|
|
||||||
uint mip_width, mip_height, mip_depth;
|
|
||||||
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
|
|
||||||
|
|
||||||
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
|
|
||||||
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
|
|
||||||
if ((!mip_row_blocks) || (!mip_col_blocks))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32 image_size = 0;
|
|
||||||
if (!has_valid_image_size_fields)
|
|
||||||
image_size = mip_depth * mip_row_blocks * mip_col_blocks * m_bytes_per_block * get_array_size() * get_num_faces();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (serializer.read(&image_size, 1, sizeof(image_size)) != sizeof(image_size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
image_size = utils::swap32(image_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!image_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint total_mip_size = 0;
|
|
||||||
|
|
||||||
if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6))
|
|
||||||
{
|
|
||||||
// plain non-array cubemap
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_image_data.size() == get_image_index(mip_level, 0, face, 0));
|
|
||||||
|
|
||||||
m_image_data.push_back(uint8_vec());
|
|
||||||
uint8_vec& image_data = m_image_data.back();
|
|
||||||
|
|
||||||
image_data.resize(image_size);
|
|
||||||
if (serializer.read(&image_data[0], 1, image_size) != image_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
utils::endian_swap_mem(&image_data[0], image_size, m_header.m_glTypeSize);
|
|
||||||
|
|
||||||
uint num_cube_pad_bytes = disable_mip_and_cubemap_padding ? 0 : (3 - ((image_size + 3) % 4));
|
|
||||||
if (serializer.read(pad_bytes, 1, num_cube_pad_bytes) != num_cube_pad_bytes)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
total_mip_size += image_size + num_cube_pad_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 1D, 2D, 3D (normal or array texture), or array cubemap
|
|
||||||
uint num_image_bytes_remaining = image_size;
|
|
||||||
|
|
||||||
for (uint array_element = 0; array_element < get_array_size(); array_element++)
|
|
||||||
{
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
for (uint zslice = 0; zslice < mip_depth; zslice++)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(m_image_data.size() == get_image_index(mip_level, array_element, face, zslice));
|
|
||||||
|
|
||||||
uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
|
|
||||||
if ((!slice_size) || (slice_size > num_image_bytes_remaining))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_image_data.push_back(uint8_vec());
|
|
||||||
uint8_vec& image_data = m_image_data.back();
|
|
||||||
|
|
||||||
image_data.resize(slice_size);
|
|
||||||
if (serializer.read(&image_data[0], 1, slice_size) != slice_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
utils::endian_swap_mem(&image_data[0], slice_size, m_header.m_glTypeSize);
|
|
||||||
|
|
||||||
num_image_bytes_remaining -= slice_size;
|
|
||||||
|
|
||||||
total_mip_size += slice_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_image_bytes_remaining)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint num_mip_pad_bytes = disable_mip_and_cubemap_padding ? 0 : (3 - ((total_mip_size + 3) % 4));
|
|
||||||
if (serializer.read(pad_bytes, 1, num_mip_pad_bytes) != num_mip_pad_bytes)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::write_to_stream(data_stream_serializer& serializer, bool no_keyvalue_data)
|
|
||||||
{
|
|
||||||
if (!consistency_check())
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(m_header.m_identifier, s_ktx_file_id, sizeof(m_header.m_identifier));
|
|
||||||
m_header.m_endianness = m_opposite_endianness ? KTX_OPPOSITE_ENDIAN : KTX_ENDIAN;
|
|
||||||
|
|
||||||
if (m_block_dim == 1)
|
|
||||||
{
|
|
||||||
m_header.m_glTypeSize = get_ogl_type_size(m_header.m_glType);
|
|
||||||
m_header.m_glBaseInternalFormat = m_header.m_glFormat;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_header.m_glBaseInternalFormat = get_ogl_base_internal_fmt(m_header.m_glInternalFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_header.m_bytesOfKeyValueData = 0;
|
|
||||||
if (!no_keyvalue_data)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_key_values.size(); i++)
|
|
||||||
m_header.m_bytesOfKeyValueData += sizeof(uint32) + ((m_key_values[i].size() + 3) & ~3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
m_header.endian_swap();
|
|
||||||
|
|
||||||
bool success = (serializer.write(&m_header, sizeof(m_header), 1) == 1);
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
m_header.endian_swap();
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return success;
|
|
||||||
|
|
||||||
uint total_key_value_bytes = 0;
|
|
||||||
const uint8 padding[3] = { 0, 0, 0 };
|
|
||||||
|
|
||||||
if (!no_keyvalue_data)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_key_values.size(); i++)
|
|
||||||
{
|
|
||||||
uint32 key_value_size = m_key_values[i].size();
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
key_value_size = utils::swap32(key_value_size);
|
|
||||||
|
|
||||||
success = (serializer.write(&key_value_size, sizeof(key_value_size), 1) == 1);
|
|
||||||
total_key_value_bytes += sizeof(key_value_size);
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
key_value_size = utils::swap32(key_value_size);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (key_value_size)
|
|
||||||
{
|
|
||||||
if (serializer.write(&m_key_values[i][0], key_value_size, 1) != 1)
|
|
||||||
return false;
|
|
||||||
total_key_value_bytes += key_value_size;
|
|
||||||
|
|
||||||
uint num_padding = 3 - ((key_value_size + 3) % 4);
|
|
||||||
if ((num_padding) && (serializer.write(padding, num_padding, 1) != 1))
|
|
||||||
return false;
|
|
||||||
total_key_value_bytes += num_padding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(void)total_key_value_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
CRNLIB_ASSERT(total_key_value_bytes == m_header.m_bytesOfKeyValueData);
|
|
||||||
|
|
||||||
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
|
|
||||||
{
|
|
||||||
uint mip_width, mip_height, mip_depth;
|
|
||||||
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
|
|
||||||
|
|
||||||
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
|
|
||||||
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
|
|
||||||
if ((!mip_row_blocks) || (!mip_col_blocks))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32 image_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
|
|
||||||
if ((m_header.m_numberOfArrayElements) || (get_num_faces() == 1))
|
|
||||||
image_size *= (get_array_size() * get_num_faces() * get_depth());
|
|
||||||
|
|
||||||
if (!image_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
image_size = utils::swap32(image_size);
|
|
||||||
|
|
||||||
success = (serializer.write(&image_size, sizeof(image_size), 1) == 1);
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
image_size = utils::swap32(image_size);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint total_mip_size = 0;
|
|
||||||
|
|
||||||
if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6))
|
|
||||||
{
|
|
||||||
// plain non-array cubemap
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
const uint8_vec& image_data = get_image_data(get_image_index(mip_level, 0, face, 0));
|
|
||||||
if ((!image_data.size()) || (image_data.size() != image_size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
{
|
|
||||||
uint8_vec tmp_image_data(image_data);
|
|
||||||
utils::endian_swap_mem(&tmp_image_data[0], tmp_image_data.size(), m_header.m_glTypeSize);
|
|
||||||
if (serializer.write(&tmp_image_data[0], tmp_image_data.size(), 1) != 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (serializer.write(&image_data[0], image_data.size(), 1) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint num_cube_pad_bytes = 3 - ((image_data.size() + 3) % 4);
|
|
||||||
if ((num_cube_pad_bytes) && (serializer.write(padding, num_cube_pad_bytes, 1) != 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
total_mip_size += image_size + num_cube_pad_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 1D, 2D, 3D (normal or array texture), or array cubemap
|
|
||||||
for (uint array_element = 0; array_element < get_array_size(); array_element++)
|
|
||||||
{
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
for (uint zslice = 0; zslice < mip_depth; zslice++)
|
|
||||||
{
|
|
||||||
const uint8_vec& image_data = get_image_data(get_image_index(mip_level, array_element, face, zslice));
|
|
||||||
if (!image_data.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_opposite_endianness)
|
|
||||||
{
|
|
||||||
uint8_vec tmp_image_data(image_data);
|
|
||||||
utils::endian_swap_mem(&tmp_image_data[0], tmp_image_data.size(), m_header.m_glTypeSize);
|
|
||||||
if (serializer.write(&tmp_image_data[0], tmp_image_data.size(), 1) != 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (serializer.write(&image_data[0], image_data.size(), 1) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
total_mip_size += image_data.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint num_mip_pad_bytes = 3 - ((total_mip_size + 3) % 4);
|
|
||||||
if ((num_mip_pad_bytes) && (serializer.write(padding, num_mip_pad_bytes, 1) != 1))
|
|
||||||
return false;
|
|
||||||
total_mip_size += num_mip_pad_bytes;
|
|
||||||
}
|
|
||||||
CRNLIB_ASSERT((total_mip_size & 3) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_header.m_pixelWidth = width;
|
|
||||||
m_header.m_pixelHeight = height;
|
|
||||||
m_header.m_numberOfMipmapLevels = num_mips;
|
|
||||||
m_header.m_glInternalFormat = ogl_internal_fmt;
|
|
||||||
m_header.m_glFormat = ogl_fmt;
|
|
||||||
m_header.m_glType = ogl_type;
|
|
||||||
m_header.m_numberOfFaces = 1;
|
|
||||||
|
|
||||||
if (!compute_pixel_info())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_header.m_pixelWidth = width;
|
|
||||||
m_header.m_pixelHeight = height;
|
|
||||||
m_header.m_numberOfMipmapLevels = num_mips;
|
|
||||||
m_header.m_numberOfArrayElements = array_size;
|
|
||||||
m_header.m_glInternalFormat = ogl_internal_fmt;
|
|
||||||
m_header.m_glFormat = ogl_fmt;
|
|
||||||
m_header.m_glType = ogl_type;
|
|
||||||
m_header.m_numberOfFaces = 1;
|
|
||||||
|
|
||||||
if (!compute_pixel_info())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_header.m_pixelWidth = width;
|
|
||||||
m_header.m_pixelHeight = height;
|
|
||||||
m_header.m_pixelDepth = depth;
|
|
||||||
m_header.m_numberOfMipmapLevels = num_mips;
|
|
||||||
m_header.m_glInternalFormat = ogl_internal_fmt;
|
|
||||||
m_header.m_glFormat = ogl_fmt;
|
|
||||||
m_header.m_glType = ogl_type;
|
|
||||||
m_header.m_numberOfFaces = 1;
|
|
||||||
|
|
||||||
if (!compute_pixel_info())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_header.m_pixelWidth = dim;
|
|
||||||
m_header.m_pixelHeight = dim;
|
|
||||||
m_header.m_numberOfMipmapLevels = num_mips;
|
|
||||||
m_header.m_glInternalFormat = ogl_internal_fmt;
|
|
||||||
m_header.m_glFormat = ogl_fmt;
|
|
||||||
m_header.m_glType = ogl_type;
|
|
||||||
m_header.m_numberOfFaces = 6;
|
|
||||||
|
|
||||||
if (!compute_pixel_info())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::check_header() const
|
|
||||||
{
|
|
||||||
if (((get_num_faces() != 1) && (get_num_faces() != 6)) || (!m_header.m_pixelWidth))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((!m_header.m_pixelHeight) && (m_header.m_pixelDepth))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((get_num_faces() == 6) && ((m_header.m_pixelDepth) || (!m_header.m_pixelHeight)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_header.m_numberOfMipmapLevels)
|
|
||||||
{
|
|
||||||
const uint max_mipmap_dimension = 1U << (m_header.m_numberOfMipmapLevels - 1U);
|
|
||||||
if (max_mipmap_dimension > (CRNLIB_MAX(CRNLIB_MAX(m_header.m_pixelWidth, m_header.m_pixelHeight), m_header.m_pixelDepth)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::consistency_check() const
|
|
||||||
{
|
|
||||||
if (!check_header())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint block_dim = 0, bytes_per_block = 0;
|
|
||||||
if ((!m_header.m_glType) || (!m_header.m_glFormat))
|
|
||||||
{
|
|
||||||
if ((m_header.m_glType) || (m_header.m_glFormat))
|
|
||||||
return false;
|
|
||||||
if (!get_ogl_fmt_desc(m_header.m_glInternalFormat, m_header.m_glType, block_dim, bytes_per_block))
|
|
||||||
return false;
|
|
||||||
if (block_dim == 1)
|
|
||||||
return false;
|
|
||||||
//if ((get_width() % block_dim) || (get_height() % block_dim))
|
|
||||||
// return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!get_ogl_fmt_desc(m_header.m_glFormat, m_header.m_glType, block_dim, bytes_per_block))
|
|
||||||
return false;
|
|
||||||
if (block_dim > 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((m_block_dim != block_dim) || (m_bytes_per_block != bytes_per_block))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_image_data.size() != get_total_images())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
|
|
||||||
{
|
|
||||||
uint mip_width, mip_height, mip_depth;
|
|
||||||
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
|
|
||||||
|
|
||||||
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
|
|
||||||
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
|
|
||||||
if ((!mip_row_blocks) || (!mip_col_blocks))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (uint array_element = 0; array_element < get_array_size(); array_element++)
|
|
||||||
{
|
|
||||||
for (uint face = 0; face < get_num_faces(); face++)
|
|
||||||
{
|
|
||||||
for (uint zslice = 0; zslice < mip_depth; zslice++)
|
|
||||||
{
|
|
||||||
const uint8_vec& image_data = get_image_data(get_image_index(mip_level, array_element, face, zslice));
|
|
||||||
|
|
||||||
uint expected_image_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
|
|
||||||
if (image_data.size() != expected_image_size)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_vec* ktx_texture::find_key(const char* pKey) const
|
|
||||||
{
|
|
||||||
const size_t n = strlen(pKey) + 1;
|
|
||||||
for (uint i = 0; i < m_key_values.size(); i++)
|
|
||||||
{
|
|
||||||
const uint8_vec& v = m_key_values[i];
|
|
||||||
if ((v.size() >= n) && (!memcmp(&v[0], pKey, n)))
|
|
||||||
return &v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ktx_texture::get_key_value_as_string(const char* pKey, dynamic_string& str) const
|
|
||||||
{
|
|
||||||
const uint8_vec* p = find_key(pKey);
|
|
||||||
if (!p)
|
|
||||||
{
|
|
||||||
str.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint ofs = (static_cast<uint>(strlen(pKey)) + 1);
|
|
||||||
const uint8* pValue = p->get_ptr() + ofs;
|
|
||||||
const uint n = p->size() - ofs;
|
|
||||||
|
|
||||||
uint i;
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
if (!pValue[i])
|
|
||||||
break;
|
|
||||||
|
|
||||||
str.set_from_buf(pValue, i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint ktx_texture::add_key_value(const char* pKey, const void* pVal, uint val_size)
|
|
||||||
{
|
|
||||||
const uint idx = m_key_values.size();
|
|
||||||
m_key_values.resize(idx + 1);
|
|
||||||
uint8_vec& v = m_key_values.back();
|
|
||||||
v.append(reinterpret_cast<const uint8*>(pKey), static_cast<uint>(strlen(pKey)) + 1);
|
|
||||||
v.append(static_cast<const uint8*>(pVal), val_size);
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,244 +0,0 @@
|
||||||
// File: crn_ktx_texture.h
|
|
||||||
#ifndef _KTX_TEXTURE_H_
|
|
||||||
#define _KTX_TEXTURE_H_
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma once
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "crn_data_stream_serializer.h"
|
|
||||||
|
|
||||||
#define KTX_ENDIAN 0x04030201
|
|
||||||
#define KTX_OPPOSITE_ENDIAN 0x01020304
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
extern const uint8 s_ktx_file_id[12];
|
|
||||||
|
|
||||||
struct ktx_header
|
|
||||||
{
|
|
||||||
uint8 m_identifier[12];
|
|
||||||
uint32 m_endianness;
|
|
||||||
uint32 m_glType;
|
|
||||||
uint32 m_glTypeSize;
|
|
||||||
uint32 m_glFormat;
|
|
||||||
uint32 m_glInternalFormat;
|
|
||||||
uint32 m_glBaseInternalFormat;
|
|
||||||
uint32 m_pixelWidth;
|
|
||||||
uint32 m_pixelHeight;
|
|
||||||
uint32 m_pixelDepth;
|
|
||||||
uint32 m_numberOfArrayElements;
|
|
||||||
uint32 m_numberOfFaces;
|
|
||||||
uint32 m_numberOfMipmapLevels;
|
|
||||||
uint32 m_bytesOfKeyValueData;
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
memset(this, 0, sizeof(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
void endian_swap()
|
|
||||||
{
|
|
||||||
utils::endian_swap_mem32(&m_endianness, (sizeof(*this) - sizeof(m_identifier)) / sizeof(uint32));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef crnlib::vector<uint8_vec> ktx_key_value_vec;
|
|
||||||
typedef crnlib::vector<uint8_vec> ktx_image_data_vec;
|
|
||||||
|
|
||||||
// Compressed pixel data formats: ETC1, DXT1, DXT3, DXT5
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
KTX_ETC1_RGB8_OES = 0x8D64, KTX_RGB_S3TC = 0x83A0, KTX_RGB4_S3TC = 0x83A1, KTX_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0,
|
|
||||||
KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1, KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C, KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
|
|
||||||
KTX_RGBA_S3TC = 0x83A2, KTX_RGBA4_S3TC = 0x83A3, KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2, KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
|
|
||||||
KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3, KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F, KTX_RGBA_DXT5_S3TC = 0x83A4, KTX_RGBA4_DXT5_S3TC = 0x83A5,
|
|
||||||
KTX_COMPRESSED_RED_RGTC1_EXT = 0x8DBB, KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC, KTX_COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD, KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE,
|
|
||||||
KTX_COMPRESSED_LUMINANCE_LATC1_EXT = 0x8C70, KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = 0x8C71, KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C72, KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C73
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pixel formats (various internal, base, and base internal formats)
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
KTX_R8 = 0x8229, KTX_R8UI = 0x8232, KTX_RGB8 = 0x8051, KTX_SRGB8 = 0x8C41, KTX_SRGB = 0x8C40, KTX_SRGB_ALPHA = 0x8C42,
|
|
||||||
KTX_SRGB8_ALPHA8 = 0x8C43, KTX_RGBA8 = 0x8058, KTX_STENCIL_INDEX = 0x1901, KTX_DEPTH_COMPONENT = 0x1902, KTX_DEPTH_STENCIL = 0x84F9, KTX_RED = 0x1903,
|
|
||||||
KTX_GREEN = 0x1904, KTX_BLUE = 0x1905, KTX_ALPHA = 0x1906, KTX_RG = 0x8227, KTX_RGB = 0x1907, KTX_RGBA = 0x1908, KTX_BGR = 0x80E0, KTX_BGRA = 0x80E1,
|
|
||||||
KTX_RED_INTEGER = 0x8D94, KTX_GREEN_INTEGER = 0x8D95, KTX_BLUE_INTEGER = 0x8D96, KTX_ALPHA_INTEGER = 0x8D97, KTX_RGB_INTEGER = 0x8D98, KTX_RGBA_INTEGER = 0x8D99,
|
|
||||||
KTX_BGR_INTEGER = 0x8D9A, KTX_BGRA_INTEGER = 0x8D9B, KTX_LUMINANCE = 0x1909, KTX_LUMINANCE_ALPHA = 0x190A, KTX_RG_INTEGER = 0x8228, KTX_RG8 = 0x822B,
|
|
||||||
KTX_ALPHA8 = 0x803C, KTX_LUMINANCE8 = 0x8040, KTX_LUMINANCE8_ALPHA8 = 0x8045
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pixel data types
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
KTX_UNSIGNED_BYTE = 0x1401, KTX_BYTE = 0x1400, KTX_UNSIGNED_SHORT = 0x1403, KTX_SHORT = 0x1402,
|
|
||||||
KTX_UNSIGNED_INT = 0x1405, KTX_INT = 0x1404, KTX_HALF_FLOAT = 0x140B, KTX_FLOAT = 0x1406,
|
|
||||||
KTX_UNSIGNED_BYTE_3_3_2 = 0x8032, KTX_UNSIGNED_BYTE_2_3_3_REV = 0x8362, KTX_UNSIGNED_SHORT_5_6_5 = 0x8363,
|
|
||||||
KTX_UNSIGNED_SHORT_5_6_5_REV = 0x8364, KTX_UNSIGNED_SHORT_4_4_4_4 = 0x8033, KTX_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
|
|
||||||
KTX_UNSIGNED_SHORT_5_5_5_1 = 0x8034, KTX_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366, KTX_UNSIGNED_INT_8_8_8_8 = 0x8035,
|
|
||||||
KTX_UNSIGNED_INT_8_8_8_8_REV = 0x8367, KTX_UNSIGNED_INT_10_10_10_2 = 0x8036, KTX_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
|
|
||||||
KTX_UNSIGNED_INT_24_8 = 0x84FA, KTX_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B, KTX_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
|
|
||||||
KTX_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD
|
|
||||||
};
|
|
||||||
|
|
||||||
bool is_packed_pixel_ogl_type(uint32 ogl_type);
|
|
||||||
uint get_ogl_type_size(uint32 ogl_type);
|
|
||||||
bool get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint& block_dim, uint& bytes_per_block);
|
|
||||||
uint get_ogl_type_size(uint32 ogl_type);
|
|
||||||
uint32 get_ogl_base_internal_fmt(uint32 ogl_fmt);
|
|
||||||
|
|
||||||
class ktx_texture
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ktx_texture()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ktx_texture(const ktx_texture& other)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
ktx_texture& operator= (const ktx_texture& rhs)
|
|
||||||
{
|
|
||||||
if (this == &rhs)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
m_header = rhs.m_header;
|
|
||||||
m_key_values = rhs.m_key_values;
|
|
||||||
m_image_data = rhs.m_image_data;
|
|
||||||
m_block_dim = rhs.m_block_dim;
|
|
||||||
m_bytes_per_block = rhs.m_bytes_per_block;
|
|
||||||
m_opposite_endianness = rhs.m_opposite_endianness;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_header.clear();
|
|
||||||
m_key_values.clear();
|
|
||||||
m_image_data.clear();
|
|
||||||
|
|
||||||
m_block_dim = 0;
|
|
||||||
m_bytes_per_block = 0;
|
|
||||||
|
|
||||||
m_opposite_endianness = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// High level methods
|
|
||||||
bool read_from_stream(data_stream_serializer& serializer);
|
|
||||||
bool write_to_stream(data_stream_serializer& serializer, bool no_keyvalue_data = false);
|
|
||||||
|
|
||||||
bool init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
|
|
||||||
bool init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
|
|
||||||
bool init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
|
|
||||||
bool init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
|
|
||||||
|
|
||||||
bool check_header() const;
|
|
||||||
bool consistency_check() const;
|
|
||||||
|
|
||||||
// General info
|
|
||||||
|
|
||||||
bool is_valid() const { return (m_header.m_pixelWidth > 0) && (m_image_data.size() > 0); }
|
|
||||||
|
|
||||||
uint get_width() const { return m_header.m_pixelWidth; }
|
|
||||||
uint get_height() const { return CRNLIB_MAX(m_header.m_pixelHeight, 1); }
|
|
||||||
uint get_depth() const { return CRNLIB_MAX(m_header.m_pixelDepth, 1); }
|
|
||||||
uint get_num_mips() const { return CRNLIB_MAX(m_header.m_numberOfMipmapLevels, 1); }
|
|
||||||
uint get_array_size() const { return CRNLIB_MAX(m_header.m_numberOfArrayElements, 1); }
|
|
||||||
uint get_num_faces() const { return m_header.m_numberOfFaces; }
|
|
||||||
|
|
||||||
uint32 get_ogl_type() const { return m_header.m_glType; }
|
|
||||||
uint32 get_ogl_fmt() const { return m_header.m_glFormat; }
|
|
||||||
uint32 get_ogl_base_fmt() const { return m_header.m_glBaseInternalFormat; }
|
|
||||||
uint32 get_ogl_internal_fmt() const { return m_header.m_glInternalFormat; }
|
|
||||||
|
|
||||||
uint get_total_images() const { return get_num_mips() * (get_depth() * get_num_faces() * get_array_size()); }
|
|
||||||
|
|
||||||
bool is_compressed() const { return m_block_dim > 1; }
|
|
||||||
bool is_uncompressed() const { return !is_compressed(); }
|
|
||||||
|
|
||||||
bool get_opposite_endianness() const { return m_opposite_endianness; }
|
|
||||||
void set_opposite_endianness(bool flag) { m_opposite_endianness = flag; }
|
|
||||||
|
|
||||||
uint32 get_block_dim() const { return m_block_dim; }
|
|
||||||
uint32 get_bytes_per_block() const { return m_bytes_per_block; }
|
|
||||||
|
|
||||||
const ktx_header& get_header() const { return m_header; }
|
|
||||||
|
|
||||||
// Key values
|
|
||||||
const ktx_key_value_vec& get_key_value_vec() const { return m_key_values; }
|
|
||||||
ktx_key_value_vec& get_key_value_vec() { return m_key_values; }
|
|
||||||
|
|
||||||
const uint8_vec* find_key(const char* pKey) const;
|
|
||||||
bool get_key_value_as_string(const char* pKey, dynamic_string& str) const;
|
|
||||||
|
|
||||||
uint add_key_value(const char* pKey, const void* pVal, uint val_size);
|
|
||||||
uint add_key_value(const char* pKey, const char* pVal) { return add_key_value(pKey, pVal, static_cast<uint>(strlen(pVal)) + 1); }
|
|
||||||
|
|
||||||
// Image data
|
|
||||||
uint get_num_images() const { return m_image_data.size(); }
|
|
||||||
|
|
||||||
const uint8_vec& get_image_data(uint image_index) const { return m_image_data[image_index]; }
|
|
||||||
uint8_vec& get_image_data(uint image_index) { return m_image_data[image_index]; }
|
|
||||||
|
|
||||||
const uint8_vec& get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) const { return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index)); }
|
|
||||||
uint8_vec& get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) { return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index)); }
|
|
||||||
|
|
||||||
const ktx_image_data_vec& get_image_data_vec() const { return m_image_data; }
|
|
||||||
ktx_image_data_vec& get_image_data_vec() { return m_image_data; }
|
|
||||||
|
|
||||||
void add_image(uint face_index, uint mip_index, const void* pImage, uint image_size)
|
|
||||||
{
|
|
||||||
const uint image_index = get_image_index(mip_index, 0, face_index, 0);
|
|
||||||
if (image_index >= m_image_data.size())
|
|
||||||
m_image_data.resize(image_index + 1);
|
|
||||||
if (image_size)
|
|
||||||
{
|
|
||||||
uint8_vec& v = m_image_data[image_index];
|
|
||||||
v.resize(image_size);
|
|
||||||
memcpy(&v[0], pImage, image_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_image_index(uint mip_index, uint array_index, uint face_index, uint zslice_index) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT((mip_index < get_num_mips()) && (array_index < get_array_size()) && (face_index < get_num_faces()) && (zslice_index < get_depth()));
|
|
||||||
return zslice_index + (face_index * get_depth()) + (array_index * (get_depth() * get_num_faces())) + (mip_index * (get_depth() * get_num_faces() * get_array_size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_mip_dim(uint mip_index, uint& mip_width, uint& mip_height) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(mip_index < get_num_mips());
|
|
||||||
mip_width = CRNLIB_MAX(get_width() >> mip_index, 1);
|
|
||||||
mip_height = CRNLIB_MAX(get_height() >> mip_index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_mip_dim(uint mip_index, uint& mip_width, uint& mip_height, uint& mip_depth) const
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(mip_index < get_num_mips());
|
|
||||||
mip_width = CRNLIB_MAX(get_width() >> mip_index, 1);
|
|
||||||
mip_height = CRNLIB_MAX(get_height() >> mip_index, 1);
|
|
||||||
mip_depth = CRNLIB_MAX(get_depth() >> mip_index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ktx_header m_header;
|
|
||||||
|
|
||||||
ktx_key_value_vec m_key_values;
|
|
||||||
ktx_image_data_vec m_image_data;
|
|
||||||
|
|
||||||
uint32 m_block_dim;
|
|
||||||
uint32 m_bytes_per_block;
|
|
||||||
|
|
||||||
bool m_opposite_endianness;
|
|
||||||
|
|
||||||
bool compute_pixel_info();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
#endif // #ifndef _KTX_TEXTURE_H_
|
|
|
@ -1,142 +0,0 @@
|
||||||
// File: crn_lzma_codec.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
#include "crn_lzma_codec.h"
|
|
||||||
#include "crn_strutils.h"
|
|
||||||
#include "crn_checksum.h"
|
|
||||||
#include "lzma_LzmaLib.h"
|
|
||||||
#include "crn_threading.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
lzma_codec::lzma_codec() :
|
|
||||||
m_pCompress(LzmaCompress),
|
|
||||||
m_pUncompress(LzmaUncompress)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lzma_codec::~lzma_codec()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzma_codec::pack(const void* p, uint n, crnlib::vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
if (n > 1024U*1024U*1024U)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint max_comp_size = n + math::maximum<uint>(128, n >> 8);
|
|
||||||
buf.resize(sizeof(header) + max_comp_size);
|
|
||||||
|
|
||||||
header* pHDR = reinterpret_cast<header*>(&buf[0]);
|
|
||||||
uint8* pComp_data = &buf[sizeof(header)];
|
|
||||||
|
|
||||||
utils::zero_object(*pHDR);
|
|
||||||
|
|
||||||
pHDR->m_uncomp_size = n;
|
|
||||||
pHDR->m_adler32 = adler32(p, n);
|
|
||||||
|
|
||||||
if (n)
|
|
||||||
{
|
|
||||||
size_t destLen = 0;
|
|
||||||
size_t outPropsSize = 0;
|
|
||||||
int status = SZ_ERROR_INPUT_EOF;
|
|
||||||
|
|
||||||
for (uint trial = 0; trial < 3; trial++)
|
|
||||||
{
|
|
||||||
destLen = max_comp_size;
|
|
||||||
outPropsSize = cLZMAPropsSize;
|
|
||||||
|
|
||||||
status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
|
|
||||||
pHDR->m_lzma_props, &outPropsSize,
|
|
||||||
-1, /* 0 <= level <= 9, default = 5 */
|
|
||||||
0, /* default = (1 << 24) */
|
|
||||||
-1, /* 0 <= lc <= 8, default = 3 */
|
|
||||||
-1, /* 0 <= lp <= 4, default = 0 */
|
|
||||||
-1, /* 0 <= pb <= 4, default = 2 */
|
|
||||||
-1, /* 5 <= fb <= 273, default = 32 */
|
|
||||||
#ifdef WIN32
|
|
||||||
(g_number_of_processors > 1) ? 2 : 1
|
|
||||||
#else
|
|
||||||
1
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
if (status != SZ_ERROR_OUTPUT_EOF)
|
|
||||||
break;
|
|
||||||
|
|
||||||
max_comp_size += ((n+1)/2);
|
|
||||||
buf.resize(sizeof(header) + max_comp_size);
|
|
||||||
pHDR = reinterpret_cast<header*>(&buf[0]);
|
|
||||||
pComp_data = &buf[sizeof(header)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != SZ_OK)
|
|
||||||
{
|
|
||||||
buf.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pHDR->m_comp_size = static_cast<uint>(destLen);
|
|
||||||
|
|
||||||
buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
|
|
||||||
}
|
|
||||||
|
|
||||||
pHDR->m_sig = header::cSig;
|
|
||||||
pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf)
|
|
||||||
{
|
|
||||||
buf.resize(0);
|
|
||||||
|
|
||||||
if (n < sizeof(header))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const header& hdr = *static_cast<const header*>(p);
|
|
||||||
if (hdr.m_sig != header::cSig)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!hdr.m_uncomp_size)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!hdr.m_comp_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (hdr.m_uncomp_size > 1024U*1024U*1024U)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!buf.try_resize(hdr.m_uncomp_size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header);
|
|
||||||
size_t srcLen = n - sizeof(header);
|
|
||||||
if (srcLen < hdr.m_comp_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
size_t destLen = hdr.m_uncomp_size;
|
|
||||||
|
|
||||||
int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen,
|
|
||||||
hdr.m_lzma_props, cLZMAPropsSize);
|
|
||||||
|
|
||||||
if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size))
|
|
||||||
{
|
|
||||||
buf.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adler32(&buf[0], buf.size()) != hdr.m_adler32)
|
|
||||||
{
|
|
||||||
buf.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,60 +0,0 @@
|
||||||
// File: crn_lzma_codec.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
#include "crn_packed_uint.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
class lzma_codec
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
lzma_codec();
|
|
||||||
~lzma_codec();
|
|
||||||
|
|
||||||
// Always available, because we're statically linking in lzmalib now vs. dynamically loading the DLL.
|
|
||||||
bool is_initialized() const { return true; }
|
|
||||||
|
|
||||||
bool pack(const void* p, uint n, crnlib::vector<uint8>& buf);
|
|
||||||
|
|
||||||
bool unpack(const void* p, uint n, crnlib::vector<uint8>& buf);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef int (CRNLIB_STDCALL *LzmaCompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
|
|
||||||
unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
|
|
||||||
int level, /* 0 <= level <= 9, default = 5 */
|
|
||||||
unsigned dictSize, /* default = (1 << 24) */
|
|
||||||
int lc, /* 0 <= lc <= 8, default = 3 */
|
|
||||||
int lp, /* 0 <= lp <= 4, default = 0 */
|
|
||||||
int pb, /* 0 <= pb <= 4, default = 2 */
|
|
||||||
int fb, /* 5 <= fb <= 273, default = 32 */
|
|
||||||
int numThreads /* 1 or 2, default = 2 */
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef int (CRNLIB_STDCALL *LzmaUncompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
|
|
||||||
const unsigned char *props, size_t propsSize);
|
|
||||||
|
|
||||||
LzmaCompressFuncPtr m_pCompress;
|
|
||||||
LzmaUncompressFuncPtr m_pUncompress;
|
|
||||||
|
|
||||||
enum { cLZMAPropsSize = 5 };
|
|
||||||
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
struct header
|
|
||||||
{
|
|
||||||
enum { cSig = 'L' | ('0' << 8), cChecksumSkipBytes = 3 };
|
|
||||||
packed_uint<2> m_sig;
|
|
||||||
uint8 m_checksum;
|
|
||||||
|
|
||||||
uint8 m_lzma_props[cLZMAPropsSize];
|
|
||||||
|
|
||||||
packed_uint<4> m_comp_size;
|
|
||||||
packed_uint<4> m_uncomp_size;
|
|
||||||
|
|
||||||
packed_uint<4> m_adler32;
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,76 +0,0 @@
|
||||||
// File: crn_math.cpp
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#include "crn_core.h"
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace math
|
|
||||||
{
|
|
||||||
uint g_bitmasks[32] =
|
|
||||||
{
|
|
||||||
1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U,
|
|
||||||
1U << 4U, 1U << 5U, 1U << 6U, 1U << 7U,
|
|
||||||
1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U,
|
|
||||||
1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U,
|
|
||||||
1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U,
|
|
||||||
1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U,
|
|
||||||
1U << 24U, 1U << 25U, 1U << 26U, 1U << 27U,
|
|
||||||
1U << 28U, 1U << 29U, 1U << 30U, 1U << 31U
|
|
||||||
};
|
|
||||||
|
|
||||||
double compute_entropy(const uint8* p, uint n)
|
|
||||||
{
|
|
||||||
uint hist[256];
|
|
||||||
utils::zero_object(hist);
|
|
||||||
|
|
||||||
for (uint i = 0; i < n; i++)
|
|
||||||
hist[*p++]++;
|
|
||||||
|
|
||||||
double entropy = 0.0f;
|
|
||||||
|
|
||||||
const double invln2 = 1.0f/log(2.0f);
|
|
||||||
for (uint i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
if (!hist[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
double prob = static_cast<double>(hist[i]) / n;
|
|
||||||
entropy += (-log(prob) * invln2) * hist[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return entropy;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compute_lower_pow2_dim(int& width, int& height)
|
|
||||||
{
|
|
||||||
const int tex_width = width;
|
|
||||||
const int tex_height = height;
|
|
||||||
|
|
||||||
width = 1;
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if ((width * 2) > tex_width)
|
|
||||||
break;
|
|
||||||
width *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
height = 1;
|
|
||||||
for ( ; ; )
|
|
||||||
{
|
|
||||||
if ((height * 2) > tex_height)
|
|
||||||
break;
|
|
||||||
height *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compute_upper_pow2_dim(int& width, int& height)
|
|
||||||
{
|
|
||||||
if (!math::is_power_of_2((uint32)width))
|
|
||||||
width = math::next_pow2((uint32)width);
|
|
||||||
|
|
||||||
if (!math::is_power_of_2((uint32)height))
|
|
||||||
height = math::next_pow2((uint32)height);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace math
|
|
||||||
} // namespace crnlib
|
|
|
@ -1,237 +0,0 @@
|
||||||
// File: crn_math.h
|
|
||||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(_M_IX86) && defined(_MSC_VER)
|
|
||||||
#include <intrin.h>
|
|
||||||
#pragma intrinsic(__emulu)
|
|
||||||
unsigned __int64 __emulu(unsigned int a,unsigned int b );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace crnlib
|
|
||||||
{
|
|
||||||
namespace math
|
|
||||||
{
|
|
||||||
const float cNearlyInfinite = 1.0e+37f;
|
|
||||||
|
|
||||||
const float cDegToRad = 0.01745329252f;
|
|
||||||
const float cRadToDeg = 57.29577951f;
|
|
||||||
|
|
||||||
extern uint g_bitmasks[32];
|
|
||||||
|
|
||||||
template<typename T> inline bool within_closed_range(T a, T b, T c) { return (a >= b) && (a <= c); }
|
|
||||||
|
|
||||||
template<typename T> inline bool within_open_range(T a, T b, T c) { return (a >= b) && (a < c); }
|
|
||||||
|
|
||||||
// Yes I know these should probably be pass by ref, not val:
|
|
||||||
// http://www.stepanovpapers.com/notes.pdf
|
|
||||||
// Just don't use them on non-simple (non built-in) types!
|
|
||||||
template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; }
|
|
||||||
|
|
||||||
template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
|
|
||||||
|
|
||||||
template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; }
|
|
||||||
|
|
||||||
template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
|
|
||||||
|
|
||||||
template<typename T, typename U> inline T lerp(T a, T b, U c) { return a + (b - a) * c; }
|
|
||||||
|
|
||||||
template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
|
|
||||||
|
|
||||||
template<typename T> inline T saturate(T value) { return (value < 0.0f) ? 0.0f : ((value > 1.0f) ? 1.0f : value); }
|
|
||||||
|
|
||||||
inline int float_to_int(float f) { return static_cast<int>(f); }
|
|
||||||
|
|
||||||
inline uint float_to_uint(float f) { return static_cast<uint>(f); }
|
|
||||||
|
|
||||||
inline int float_to_int(double f) { return static_cast<int>(f); }
|
|
||||||
|
|
||||||
inline uint float_to_uint(double f) { return static_cast<uint>(f); }
|
|
||||||
|
|
||||||
inline int float_to_int_round(float f) { return static_cast<int>((f < 0.0f) ? -floor(-f + .5f) : floor(f + .5f)); }
|
|
||||||
|
|
||||||
inline uint float_to_uint_round(float f) { return static_cast<uint>((f < 0.0f) ? 0.0f : floor(f + .5f)); }
|
|
||||||
|
|
||||||
template<typename T> inline int sign(T value) { return (value < 0) ? -1 : ((value > 0) ? 1 : 0); }
|
|
||||||
|
|
||||||
template<typename T> inline T square(T value) { return value * value; }
|
|
||||||
|
|
||||||
inline bool is_power_of_2(uint32 x) { return x && ((x & (x - 1U)) == 0U); }
|
|
||||||
inline bool is_power_of_2(uint64 x) { return x && ((x & (x - 1U)) == 0U); }
|
|
||||||
|
|
||||||
template<typename T> inline T align_up_value(T x, uint alignment)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(is_power_of_2(alignment));
|
|
||||||
uint q = static_cast<uint>(x);
|
|
||||||
q = (q + alignment - 1) & (~(alignment - 1));
|
|
||||||
return static_cast<T>(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> inline T align_down_value(T x, uint alignment)
|
|
||||||
{
|
|
||||||
CRNLIB_ASSERT(is_power_of_2(alignment));
|
|
||||||
uint q = static_cast<uint>(x);
|
|
||||||
q = q & (~(alignment - 1));
|
|
||||||
return static_cast<T>(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> inline T get_align_up_value_delta(T x, uint alignment)
|
|
||||||
{
|
|
||||||
return align_up_value(x, alignment) - x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From "Hackers Delight"
|
|
||||||
inline uint32 next_pow2(uint32 val)
|
|
||||||
{
|
|
||||||
val--;
|
|
||||||
val |= val >> 16;
|
|
||||||
val |= val >> 8;
|
|
||||||
val |= val >> 4;
|
|
||||||
val |= val >> 2;
|
|
||||||
val |= val >> 1;
|
|
||||||
return val + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64 next_pow2(uint64 val)
|
|
||||||
{
|
|
||||||
val--;
|
|
||||||
val |= val >> 32;
|
|
||||||
val |= val >> 16;
|
|
||||||
val |= val >> 8;
|
|
||||||
val |= val >> 4;
|
|
||||||
val |= val >> 2;
|
|
||||||
val |= val >> 1;
|
|
||||||
return val + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint floor_log2i(uint v)
|
|
||||||
{
|
|
||||||
uint l = 0;
|
|
||||||
while (v > 1U)
|
|
||||||
{
|
|
||||||
v >>= 1;
|
|
||||||
l++;
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint ceil_log2i(uint v)
|
|
||||||
{
|
|
||||||
uint l = floor_log2i(v);
|
|
||||||
if ((l != cIntBits) && (v > (1U << l)))
|
|
||||||
l++;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the total number of bits needed to encode v.
|
|
||||||
inline uint total_bits(uint v)
|
|
||||||
{
|
|
||||||
uint l = 0;
|
|
||||||
while (v > 0U)
|
|
||||||
{
|
|
||||||
v >>= 1;
|
|
||||||
l++;
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actually counts the number of set bits, but hey
|
|
||||||
inline uint bitmask_size(uint mask)
|
|
||||||
{
|
|
||||||
uint size = 0;
|
|
||||||
while (mask)
|
|
||||||
{
|
|
||||||
mask &= (mask - 1U);
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint bitmask_ofs(uint mask)
|
|
||||||
{
|
|
||||||
if (!mask)
|
|
||||||
return 0;
|
|
||||||
uint ofs = 0;
|
|
||||||
while ((mask & 1U) == 0)
|
|
||||||
{
|
|
||||||
mask >>= 1U;
|
|
||||||
ofs++;
|
|
||||||
}
|
|
||||||
return ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See Bit Twiddling Hacks (public domain)
|
|
||||||
// http://www-graphics.stanford.edu/~seander/bithacks.html
|
|
||||||
inline uint count_trailing_zero_bits(uint v)
|
|
||||||
{
|
|
||||||
uint c = 32; // c will be the number of zero bits on the right
|
|
||||||
|
|
||||||
static const unsigned int B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF };
|
|
||||||
static const unsigned int S[] = { 1, 2, 4, 8, 16 }; // Our Magic Binary Numbers
|
|
||||||
|
|
||||||
for (int i = 4; i >= 0; --i) // unroll for more speed
|
|
||||||
{
|
|
||||||
if (v & B[i])
|
|
||||||
{
|
|
||||||
v <<= S[i];
|
|
||||||
c -= S[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v)
|
|
||||||
{
|
|
||||||
c--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint count_leading_zero_bits(uint v)
|
|
||||||
{
|
|
||||||
uint temp;
|
|
||||||
uint result = 32U;
|
|
||||||
|
|
||||||
temp = (v >> 16U); if (temp) { result -= 16U; v = temp; }
|
|
||||||
temp = (v >> 8U); if (temp) { result -= 8U; v = temp; }
|
|
||||||
temp = (v >> 4U); if (temp) { result -= 4U; v = temp; }
|
|
||||||
temp = (v >> 2U); if (temp) { result -= 2U; v = temp; }
|
|
||||||
temp = (v >> 1U); if (temp) { result -= 1U; v = temp; }
|
|
||||||
|
|
||||||
if (v & 1U)
|
|
||||||
result--;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64 emulu(uint32 a, uint32 b)
|
|
||||||
{
|
|
||||||
#if defined(_M_IX86) && defined(_MSC_VER)
|
|
||||||
return __emulu(a, b);
|
|
||||||
#else
|
|
||||||
return static_cast<uint64>(a) * static_cast<uint64>(b);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
double compute_entropy(const uint8* p, uint n);
|
|
||||||
|
|
||||||
void compute_lower_pow2_dim(int& width, int& height);
|
|
||||||
void compute_upper_pow2_dim(int& width, int& height);
|
|
||||||
|
|
||||||
inline bool equal_tol(float a, float b, float t)
|
|
||||||
{
|
|
||||||
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool equal_tol(double a, double b, double t)
|
|
||||||
{
|
|
||||||
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crnlib
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue