├── .clang-format ├── .gitignore ├── .gitmodules ├── 1-Deploy.bat ├── 1-Deploy.sh ├── 2-Build.bat ├── 2-Build.sh ├── 4-Clean.bat ├── 4-Clean.sh ├── CMakeLists.txt ├── External ├── Detex │ ├── _LICENSES.txt │ ├── bits.c │ ├── bits.h │ ├── bptc-tables.c │ ├── bptc-tables.h │ ├── clamp.c │ ├── convert.c │ ├── dds.c │ ├── decompress-bc.c │ ├── decompress-bptc-float.c │ ├── decompress-bptc.c │ ├── decompress-eac.c │ ├── decompress-etc.c │ ├── decompress-rgtc.c │ ├── detex.h │ ├── division-tables.c │ ├── file-info.c │ ├── file-info.h │ ├── half-float.c │ ├── half-float.h │ ├── hdr.c │ ├── hdr.h │ ├── ktx.c │ ├── misc.c │ ├── misc.h │ ├── stb.c │ ├── stb_image.h │ ├── stb_image_write.h │ └── texture.c └── MetalUtility │ ├── MetalUtility.h │ └── MetalUtility.m ├── Include ├── Camera.h ├── CmdLine.h ├── Controls.h ├── Helper.h ├── NRIFramework.h ├── Timer.h └── Utils.h ├── README.md └── Source ├── Camera.cpp ├── DebugAllocator.cpp ├── SampleBase.cpp ├── Timer.cpp └── Utils.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: DontAlign 5 | AlignArrayOfStructures: None 6 | AlignConsecutiveAssignments: 7 | Enabled: false 8 | AcrossEmptyLines: false 9 | AcrossComments: false 10 | AlignCompound: false 11 | AlignFunctionPointers: false 12 | PadOperators: true 13 | AlignConsecutiveBitFields: 14 | Enabled: true 15 | AcrossEmptyLines: false 16 | AcrossComments: false 17 | AlignCompound: false 18 | AlignFunctionPointers: false 19 | PadOperators: false 20 | AlignConsecutiveDeclarations: 21 | Enabled: false 22 | AcrossEmptyLines: false 23 | AcrossComments: false 24 | AlignCompound: false 25 | AlignFunctionPointers: false 26 | PadOperators: false 27 | AlignConsecutiveMacros: 28 | Enabled: true 29 | AcrossEmptyLines: false 30 | AcrossComments: false 31 | AlignCompound: false 32 | AlignFunctionPointers: false 33 | PadOperators: false 34 | AlignConsecutiveShortCaseStatements: 35 | Enabled: false 36 | AcrossEmptyLines: false 37 | AcrossComments: false 38 | AlignCaseArrows: false 39 | AlignCaseColons: false 40 | AlignConsecutiveTableGenBreakingDAGArgColons: 41 | Enabled: false 42 | AcrossEmptyLines: false 43 | AcrossComments: false 44 | AlignCompound: false 45 | AlignFunctionPointers: false 46 | PadOperators: false 47 | AlignConsecutiveTableGenCondOperatorColons: 48 | Enabled: false 49 | AcrossEmptyLines: false 50 | AcrossComments: false 51 | AlignCompound: false 52 | AlignFunctionPointers: false 53 | PadOperators: false 54 | AlignConsecutiveTableGenDefinitionColons: 55 | Enabled: false 56 | AcrossEmptyLines: false 57 | AcrossComments: false 58 | AlignCompound: false 59 | AlignFunctionPointers: false 60 | PadOperators: false 61 | AlignEscapedNewlines: DontAlign 62 | AlignOperands: DontAlign 63 | AlignTrailingComments: 64 | Kind: Always 65 | OverEmptyLines: 0 66 | AllowAllArgumentsOnNextLine: true 67 | AllowAllParametersOfDeclarationOnNextLine: true 68 | AllowBreakBeforeNoexceptSpecifier: Never 69 | AllowShortBlocksOnASingleLine: Never 70 | AllowShortCaseExpressionOnASingleLine: true 71 | AllowShortCaseLabelsOnASingleLine: false 72 | AllowShortCompoundRequirementOnASingleLine: true 73 | AllowShortEnumsOnASingleLine: false 74 | AllowShortFunctionsOnASingleLine: None 75 | AllowShortIfStatementsOnASingleLine: Never 76 | AllowShortLambdasOnASingleLine: All 77 | AllowShortLoopsOnASingleLine: false 78 | AlwaysBreakAfterDefinitionReturnType: None 79 | AlwaysBreakBeforeMultilineStrings: true 80 | AttributeMacros: 81 | - CPP 82 | BinPackArguments: true 83 | BinPackParameters: true 84 | BitFieldColonSpacing: Both 85 | BraceWrapping: 86 | AfterCaseLabel: false 87 | AfterClass: false 88 | AfterControlStatement: Never 89 | AfterEnum: false 90 | AfterFunction: false 91 | AfterNamespace: false 92 | AfterObjCDeclaration: false 93 | AfterStruct: false 94 | AfterUnion: false 95 | AfterExternBlock: false 96 | BeforeCatch: false 97 | BeforeElse: false 98 | BeforeLambdaBody: false 99 | BeforeWhile: false 100 | IndentBraces: false 101 | SplitEmptyFunction: true 102 | SplitEmptyRecord: true 103 | SplitEmptyNamespace: true 104 | BreakAdjacentStringLiterals: true 105 | BreakAfterAttributes: Leave 106 | BreakAfterJavaFieldAnnotations: false 107 | BreakAfterReturnType: None 108 | BreakArrays: true 109 | BreakBeforeBinaryOperators: All 110 | BreakBeforeBraces: Attach 111 | BreakBeforeConceptDeclarations: Always 112 | BreakBeforeInlineASMColon: OnlyMultiline 113 | BreakBeforeTernaryOperators: true 114 | BreakConstructorInitializers: BeforeComma 115 | BreakFunctionDefinitionParameters: false 116 | BreakInheritanceList: BeforeColon 117 | BreakStringLiterals: true 118 | BreakTemplateDeclarations: Yes 119 | ColumnLimit: 0 120 | CommentPragmas: "^ IWYU pragma:" 121 | CompactNamespaces: false 122 | ConstructorInitializerIndentWidth: 4 123 | ContinuationIndentWidth: 4 124 | Cpp11BracedListStyle: true 125 | DerivePointerAlignment: false 126 | DisableFormat: false 127 | EmptyLineAfterAccessModifier: Never 128 | EmptyLineBeforeAccessModifier: LogicalBlock 129 | ExperimentalAutoDetectBinPacking: false 130 | FixNamespaceComments: true 131 | ForEachMacros: 132 | - BLABLA 133 | IfMacros: 134 | - BLABLA 135 | IncludeBlocks: Preserve 136 | IncludeCategories: 137 | - Regex: ^ 138 | Priority: 2 139 | SortPriority: 0 140 | CaseSensitive: false 141 | - Regex: ^<.*\.h> 142 | Priority: 1 143 | SortPriority: 0 144 | CaseSensitive: false 145 | - Regex: ^<.* 146 | Priority: 2 147 | SortPriority: 0 148 | CaseSensitive: false 149 | - Regex: .* 150 | Priority: 3 151 | SortPriority: 0 152 | CaseSensitive: false 153 | IncludeIsMainRegex: ([-_](test|unittest))?$ 154 | IncludeIsMainSourceRegex: "" 155 | IndentAccessModifiers: false 156 | IndentCaseBlocks: false 157 | IndentCaseLabels: true 158 | IndentExternBlock: NoIndent 159 | IndentGotoLabels: true 160 | IndentPPDirectives: AfterHash 161 | IndentRequiresClause: true 162 | IndentWidth: 4 163 | IndentWrappedFunctionNames: false 164 | InsertBraces: false 165 | InsertNewlineAtEOF: false 166 | InsertTrailingCommas: None 167 | IntegerLiteralSeparator: 168 | Binary: 0 169 | BinaryMinDigits: 0 170 | Decimal: 0 171 | DecimalMinDigits: 0 172 | Hex: 0 173 | HexMinDigits: 0 174 | JavaScriptQuotes: Leave 175 | JavaScriptWrapImports: true 176 | KeepEmptyLines: 177 | AtEndOfFile: false 178 | AtStartOfBlock: false 179 | AtStartOfFile: true 180 | LambdaBodyIndentation: Signature 181 | LineEnding: DeriveLF 182 | MacroBlockBegin: "" 183 | MacroBlockEnd: "" 184 | MainIncludeChar: Quote 185 | MaxEmptyLinesToKeep: 1 186 | NamespaceIndentation: None 187 | ObjCBinPackProtocolList: Never 188 | ObjCBlockIndentWidth: 2 189 | ObjCBreakBeforeNestedBlockParam: true 190 | ObjCSpaceAfterProperty: false 191 | ObjCSpaceBeforeProtocolList: true 192 | PPIndentWidth: -1 193 | PackConstructorInitializers: NextLine 194 | PenaltyBreakAssignment: 2 195 | PenaltyBreakBeforeFirstCallParameter: 1 196 | PenaltyBreakComment: 300 197 | PenaltyBreakFirstLessLess: 120 198 | PenaltyBreakOpenParenthesis: 0 199 | PenaltyBreakScopeResolution: 500 200 | PenaltyBreakString: 1000 201 | PenaltyBreakTemplateDeclaration: 10 202 | PenaltyExcessCharacter: 1000000 203 | PenaltyIndentedWhitespace: 0 204 | PenaltyReturnTypeOnItsOwnLine: 200 205 | PointerAlignment: Left 206 | QualifierAlignment: Leave 207 | RawStringFormats: 208 | - Language: Cpp 209 | Delimiters: 210 | - cc 211 | - CC 212 | - cpp 213 | - Cpp 214 | - CPP 215 | - c++ 216 | - C++ 217 | CanonicalDelimiter: "" 218 | BasedOnStyle: google 219 | - Language: TextProto 220 | Delimiters: 221 | - pb 222 | - PB 223 | - proto 224 | - PROTO 225 | EnclosingFunctions: 226 | - EqualsProto 227 | - EquivToProto 228 | - PARSE_PARTIAL_TEXT_PROTO 229 | - PARSE_TEST_PROTO 230 | - PARSE_TEXT_PROTO 231 | - ParseTextOrDie 232 | - ParseTextProtoOrDie 233 | - ParseTestProto 234 | - ParsePartialTestProto 235 | CanonicalDelimiter: pb 236 | BasedOnStyle: google 237 | ReferenceAlignment: Pointer 238 | ReflowComments: true 239 | RemoveBracesLLVM: false 240 | RemoveParentheses: Leave 241 | RemoveSemicolon: false 242 | RequiresClausePosition: OwnLine 243 | RequiresExpressionIndentation: OuterScope 244 | SeparateDefinitionBlocks: Always 245 | ShortNamespaceLines: 1 246 | SkipMacroDefinitionBody: false 247 | SortIncludes: CaseSensitive 248 | SortJavaStaticImport: Before 249 | SortUsingDeclarations: LexicographicNumeric 250 | SpaceAfterCStyleCast: false 251 | SpaceAfterLogicalNot: false 252 | SpaceAfterTemplateKeyword: true 253 | SpaceAroundPointerQualifiers: Default 254 | SpaceBeforeAssignmentOperators: true 255 | SpaceBeforeCaseColon: false 256 | SpaceBeforeCpp11BracedList: false 257 | SpaceBeforeCtorInitializerColon: true 258 | SpaceBeforeInheritanceColon: true 259 | SpaceBeforeJsonColon: false 260 | SpaceBeforeParens: ControlStatements 261 | SpaceBeforeParensOptions: 262 | AfterControlStatements: true 263 | AfterForeachMacros: true 264 | AfterFunctionDeclarationName: false 265 | AfterFunctionDefinitionName: false 266 | AfterIfMacros: true 267 | AfterOverloadedOperator: false 268 | AfterPlacementOperator: true 269 | AfterRequiresInClause: false 270 | AfterRequiresInExpression: false 271 | BeforeNonEmptyParentheses: false 272 | SpaceBeforeRangeBasedForLoopColon: true 273 | SpaceBeforeSquareBrackets: false 274 | SpaceInEmptyBlock: false 275 | SpacesBeforeTrailingComments: 1 276 | SpacesInAngles: Never 277 | SpacesInContainerLiterals: true 278 | SpacesInLineCommentPrefix: 279 | Minimum: 1 280 | Maximum: -1 281 | SpacesInParens: Never 282 | SpacesInParensOptions: 283 | ExceptDoubleParentheses: false 284 | InConditionalStatements: false 285 | InCStyleCasts: false 286 | InEmptyParentheses: false 287 | Other: false 288 | SpacesInSquareBrackets: false 289 | Standard: Auto 290 | StatementAttributeLikeMacros: 291 | - BLABLA 292 | StatementMacros: 293 | - BLABLA 294 | TabWidth: 4 295 | TableGenBreakInsideDAGArg: DontBreak 296 | UseTab: Never 297 | VerilogBreakBetweenInstancePorts: true 298 | WhitespaceSensitiveMacros: 299 | - BLABLA 300 | AlwaysBreakAfterReturnType: None 301 | AlwaysBreakTemplateDeclarations: Yes 302 | KeepEmptyLinesAtTheStartOfBlocks: false 303 | Language: Cpp 304 | SpaceInEmptyParentheses: false 305 | SpacesInCStyleCastParentheses: false 306 | SpacesInConditionalStatement: false 307 | SpacesInParentheses: false 308 | TypenameMacros: 309 | - BLABLA 310 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # VS Code 2 | .vscode/ 3 | 4 | # ninja 5 | .ninja_deps 6 | .ninja_log 7 | build.ninja 8 | compile_commands.json 9 | *.log 10 | 11 | # generated 12 | _Bin/ 13 | _Build/ 14 | _Shaders/ 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "External/MathLib"] 2 | path = External/MathLib 3 | url = https://github.com/NVIDIA-RTX/MathLib.git 4 | branch = main 5 | update = merge 6 | [submodule "External/NRI"] 7 | path = External/NRI 8 | url = https://github.com/NVIDIA-RTX/NRI.git 9 | branch = main 10 | update = merge 11 | -------------------------------------------------------------------------------- /1-Deploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | git submodule update --init --recursive 4 | 5 | mkdir "_Build" 6 | 7 | cd "_Build" 8 | cmake .. -A x64 9 | cd .. 10 | -------------------------------------------------------------------------------- /1-Deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git submodule update --init --recursive 4 | 5 | mkdir -p "_Build" 6 | 7 | cd "_Build" 8 | cmake .. 9 | cd .. 10 | -------------------------------------------------------------------------------- /2-Build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd "_Build" 4 | cmake --build . --config Release -j %NUMBER_OF_PROCESSORS% 5 | cmake --build . --config Debug -j %NUMBER_OF_PROCESSORS% 6 | cd .. 7 | -------------------------------------------------------------------------------- /2-Build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p "_Build" 4 | 5 | cd "_Build" 6 | cmake .. 7 | cmake --build . --config Release -j $(nproc) 8 | cmake --build . --config Debug -j $(nproc) 9 | cd .. 10 | -------------------------------------------------------------------------------- /4-Clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if exist "build" rd /q /s "build" 4 | 5 | if exist "_Bin" rd /q /s "_Bin" 6 | if exist "_Build" rd /q /s "_Build" 7 | if exist "_Shaders" rd /q /s "_Shaders" 8 | 9 | cd "External/NRI" 10 | call "4-Clean.bat" 11 | cd "../.." 12 | -------------------------------------------------------------------------------- /4-Clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf "build" 4 | 5 | rm -rf "_Bin" 6 | rm -rf "_Build" 7 | rm -rf "_Shaders" 8 | rm -rf "_NRI_SDK" 9 | 10 | cd "External/NRI" 11 | source "4-Clean.sh" 12 | cd "../.." 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.30) 2 | 3 | include(FetchContent) 4 | 5 | # Is submodule? 6 | if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) 7 | set(IS_SUBMODULE OFF) 8 | else() 9 | set(IS_SUBMODULE ON) 10 | endif() 11 | 12 | # Cached 13 | if(NOT IS_SUBMODULE) 14 | get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | 16 | if(IS_MULTI_CONFIG) 17 | set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "") 18 | endif() 19 | 20 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/_Bin" CACHE STRING "") 21 | endif() 22 | 23 | option(NRIF_USE_WAYLAND "Use Wayland instead of X11 on Linux" OFF) 24 | 25 | # Create project 26 | file(READ "${CMAKE_CURRENT_SOURCE_DIR}/Include/NRIFramework.h" ver_h) 27 | string(REGEX MATCH "NRI_FRAMEWORK_VERSION_MAJOR ([0-9]*)" _ ${ver_h}) 28 | set(VERSION_MAJOR ${CMAKE_MATCH_1}) 29 | string(REGEX MATCH "NRI_FRAMEWORK_VERSION_MINOR ([0-9]*)" _ ${ver_h}) 30 | set(VERSION_MINOR ${CMAKE_MATCH_1}) 31 | 32 | message("NRI framework v${VERSION_MAJOR}.${VERSION_MINOR}") 33 | project(NRIFramework LANGUAGES C CXX) 34 | 35 | # Globals? 36 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 37 | 38 | set(CMAKE_CXX_STANDARD 17) 39 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 40 | 41 | # Compile options 42 | if(NOT((CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") OR(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64"))) 43 | set(SIMD -mssse3) 44 | endif() 45 | 46 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 47 | set(COMPILE_OPTIONS ${SIMD} -Wextra) 48 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 49 | set(COMPILE_OPTIONS ${SIMD} -Wextra) 50 | elseif(MSVC) 51 | set(COMPILE_OPTIONS /W4 /WX 52 | /wd4324 # padding was added at the end of a structure because you specified an alignment specifier 53 | ) 54 | else() 55 | message(WARNING "Unknown compiler!") 56 | endif() 57 | 58 | # Compile definitions 59 | if(WIN32) 60 | set(COMPILE_DEFINITIONS WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS) 61 | elseif(NRIF_USE_WAYLAND) 62 | set(COMPILE_DEFINITIONS NRIF_USE_WAYLAND=1) 63 | endif() 64 | 65 | # Download dependencies 66 | set(DEPS) 67 | 68 | # ImGui 69 | FetchContent_Declare( 70 | imgui 71 | GIT_REPOSITORY https://github.com/ocornut/imgui.git 72 | GIT_TAG master 73 | GIT_SHALLOW 1 74 | ) 75 | list(APPEND DEPS imgui) 76 | 77 | # GLFW 78 | option(GLFW_BUILD_WAYLAND "" ${NRIF_USE_WAYLAND}) 79 | option(GLFW_BUILD_EXAMPLES "" OFF) 80 | option(GLFW_BUILD_TESTS "" OFF) 81 | option(GLFW_BUILD_DOCS "" OFF) 82 | option(GLFW_INSTALL "" OFF) 83 | 84 | FetchContent_Declare( 85 | glfw 86 | GIT_REPOSITORY https://github.com/glfw/glfw.git 87 | GIT_TAG master 88 | GIT_SHALLOW 1 89 | ) 90 | list(APPEND DEPS glfw) 91 | 92 | # cgltf 93 | FetchContent_Declare( 94 | cgltf 95 | GIT_REPOSITORY https://github.com/jkuhlmann/cgltf.git 96 | GIT_TAG master 97 | GIT_SHALLOW 1 98 | ) 99 | list(APPEND DEPS cgltf) 100 | 101 | if(DEPS) 102 | message("NRI framework: downloading dependencies:") 103 | message(STATUS "${DEPS} ...") 104 | 105 | FetchContent_MakeAvailable(${DEPS}) 106 | endif() 107 | 108 | # External/Imgui 109 | file(GLOB IMGUI_SOURCE "${imgui_SOURCE_DIR}/*.cpp" "${imgui_SOURCE_DIR}/*.h") 110 | source_group("" FILES ${IMGUI_SOURCE}) 111 | add_library(imgui STATIC ${IMGUI_SOURCE}) 112 | target_compile_definitions(imgui PRIVATE ${COMPILE_DEFINITIONS}) 113 | target_include_directories(imgui PUBLIC "${imgui_SOURCE_DIR}") 114 | set_property(TARGET imgui PROPERTY FOLDER "${PROJECT_NAME}") 115 | 116 | # External/Detex 117 | file(GLOB DETEX_SOURCE "External/Detex/*.c" "External/Detex/*.h") 118 | source_group("" FILES ${DETEX_SOURCE}) 119 | add_library(detex STATIC ${DETEX_SOURCE}) 120 | target_compile_definitions(detex PRIVATE ${COMPILE_DEFINITIONS}) 121 | set_property(TARGET detex PROPERTY FOLDER "${PROJECT_NAME}") 122 | 123 | # External/NRI 124 | option(NRI_ENABLE_WAYLAND_SUPPORT "" ${NRIF_USE_WAYLAND}) 125 | option(NRI_ENABLE_IMGUI_EXTENSION "" ON) 126 | add_subdirectory("External/NRI") 127 | 128 | # External/MathLib 129 | add_subdirectory("External/MathLib") 130 | 131 | # External/MetalUtility 132 | if(APPLE) 133 | find_library(COCOA_LIBRARY Cocoa REQUIRED) 134 | find_library(QUARTZ_CORE QuartzCore REQUIRED) 135 | add_library(MetalUtility SHARED "External/MetalUtility/MetalUtility.m") 136 | target_link_libraries(MetalUtility 137 | ${QUARTZ_CORE} 138 | ${COCOA_LIBRARY} 139 | glfw 140 | ) 141 | endif() 142 | 143 | # NRIFramework 144 | file(GLOB FRAMEWORK_SOURCE "Source/*.cpp" "Source/*.h") 145 | source_group("Source" FILES ${FRAMEWORK_SOURCE}) 146 | file(GLOB FRAMEWORK_HEADERS "Include/*.hpp" "Include/*.h" "${cgltf_SOURCE_DIR}/cgltf.h") 147 | source_group("Include" FILES ${FRAMEWORK_HEADERS}) 148 | add_library(${PROJECT_NAME} STATIC ${FRAMEWORK_SOURCE} ${FRAMEWORK_HEADERS}) 149 | target_link_libraries(${PROJECT_NAME} PRIVATE 150 | detex 151 | glfw 152 | ) 153 | target_link_libraries(${PROJECT_NAME} PUBLIC 154 | NRI 155 | imgui 156 | MathLib 157 | ) 158 | 159 | if(APPLE) 160 | target_link_libraries(${PROJECT_NAME} PRIVATE 161 | ${CMAKE_DL_LIBS} 162 | pthread 163 | MetalUtility 164 | ) 165 | elseif(UNIX) 166 | target_link_libraries(${PROJECT_NAME} PRIVATE 167 | ${CMAKE_DL_LIBS} 168 | pthread 169 | X11 170 | ) 171 | endif() 172 | 173 | if(NRIF_USE_WAYLAND) # TODO: looks like a workaround... 174 | target_include_directories(${PROJECT_NAME} PRIVATE 175 | "/usr/include/wayland" 176 | ) 177 | endif() 178 | 179 | target_include_directories(${PROJECT_NAME} PRIVATE 180 | "Source" 181 | "External" 182 | "${cgltf_SOURCE_DIR}" 183 | ) 184 | target_include_directories(${PROJECT_NAME} PUBLIC 185 | "Include" 186 | "${glfw_SOURCE_DIR}/include" 187 | ) 188 | target_compile_definitions(${PROJECT_NAME} PRIVATE ${COMPILE_DEFINITIONS}) 189 | target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS}) 190 | set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "${PROJECT_NAME}") 191 | -------------------------------------------------------------------------------- /External/Detex/_LICENSES.txt: -------------------------------------------------------------------------------- 1 | // Detex 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | // STB 18 | 19 | This software is available under 2 licenses -- choose whichever you prefer. 20 | ------------------------------------------------------------------------------ 21 | ALTERNATIVE A - MIT License 22 | Copyright (c) 2017 Sean Barrett 23 | Permission is hereby granted, free of charge, to any person obtaining a copy of 24 | this software and associated documentation files (the "Software"), to deal in 25 | the Software without restriction, including without limitation the rights to 26 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 27 | of the Software, and to permit persons to whom the Software is furnished to do 28 | so, subject to the following conditions: 29 | The above copyright notice and this permission notice shall be included in all 30 | copies or substantial portions of the Software. 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | ------------------------------------------------------------------------------ 39 | ALTERNATIVE B - Public Domain (www.unlicense.org) 40 | This is free and unencumbered software released into the public domain. 41 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 42 | software, either in source code form or as a compiled binary, for any purpose, 43 | commercial or non-commercial, and by any means. 44 | In jurisdictions that recognize copyright laws, the author or authors of this 45 | software dedicate any and all copyright interest in the software to the public 46 | domain. We make this dedication for the benefit of the public at large and to 47 | the detriment of our heirs and successors. We intend this dedication to be an 48 | overt act of relinquishment in perpetuity of all present and future rights to 49 | this software under copyright law. 50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 51 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 52 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 53 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 54 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 55 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /External/Detex/bits.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | #include "bits.h" 21 | 22 | uint32_t detexBlock128ExtractBits(detexBlock128 *block, int nu_bits) { 23 | uint32_t value = 0; 24 | for (int i = 0; i < nu_bits; i++) { 25 | if (block->index < 64) { 26 | int shift = block->index - i; 27 | if (shift < 0) 28 | value |= (block->data0 & ((uint64_t)1 << block->index)) << (- shift); 29 | else 30 | value |= (block->data0 & ((uint64_t)1 << block->index)) >> shift; 31 | } 32 | else { 33 | int shift = ((block->index - 64) - i); 34 | if (shift < 0) 35 | value |= (block->data1 & ((uint64_t)1 << (block->index - 64))) << (- shift); 36 | else 37 | value |= (block->data1 & ((uint64_t)1 << (block->index - 64))) >> shift; 38 | } 39 | block->index++; 40 | } 41 | // if (block->index > 128) 42 | // printf("Block overflow (%d)\n", block->index); 43 | return value; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /External/Detex/bits.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | /* Data structure used to extract bits from 128-bit bitstring. */ 20 | 21 | typedef struct { 22 | uint64_t data0; 23 | uint64_t data1; 24 | int index; 25 | } detexBlock128; 26 | 27 | uint32_t detexBlock128ExtractBits(detexBlock128 *block, int nu_bits); 28 | 29 | /* Return bitfield from bit0 to bit1 from 64-bit bitstring. */ 30 | static DETEX_INLINE_ONLY uint32_t detexGetBits64(uint64_t data, int bit0, int bit1) { 31 | uint64_t mask; 32 | if (bit1 == 63) 33 | mask = UINT64_MAX; 34 | else 35 | mask = ((uint64_t)1 << (bit1 + 1)) - 1; 36 | 37 | return (uint32_t)((data & mask) >> bit0); 38 | } 39 | 40 | /* Return reversed bitfield (bit1 to bit0) from 64-bit bitstring. */ 41 | static DETEX_INLINE_ONLY uint32_t detexGetBits64Reversed(uint64_t data, int bit0, int bit1) { 42 | // Assumes bit0 > bit1. 43 | // Reverse the bits. 44 | uint32_t val = 0; 45 | for (int i = 0; i <= bit0 - bit1; i++) { 46 | int shift_right = bit0 - 2 * i; 47 | if (shift_right >= 0) 48 | val |= (data & ((uint64_t)1 << (bit0 - i))) >> shift_right; 49 | else 50 | val |= (data & ((uint64_t)1 << (bit0 - i))) << (- shift_right); 51 | } 52 | return val; 53 | } 54 | 55 | /* Clear bit0 to bit1 of 64-bit bitstring. */ 56 | static DETEX_INLINE_ONLY uint64_t detexClearBits64(uint64_t data, int bit0, int bit1) { 57 | uint64_t mask = ~(((uint64_t)1 << (bit1 + 1)) - 1); 58 | mask |= ((uint64_t)1 << bit0) - 1; 59 | return data & mask; 60 | } 61 | 62 | /* Set bit0 to bit1 of 64-bit bitstring. */ 63 | static DETEX_INLINE_ONLY uint64_t detexSetBits64(uint64_t data, int bit0, int bit1, uint64_t val) { 64 | uint64_t d = detexClearBits64(data, bit0, bit1); 65 | d |= val << bit0; 66 | return d; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /External/Detex/bptc-tables.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | #include "bits.h" 21 | #include "bptc-tables.h" 22 | 23 | const uint8_t detex_bptc_table_P2[64 * 16] = { 24 | 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 25 | 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 26 | 0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 27 | 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1, 28 | 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 29 | 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1, 30 | 0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 31 | 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1, 32 | 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 33 | 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, 34 | 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 35 | 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1, 36 | 0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1, 37 | 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, 38 | 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 39 | 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, 40 | 0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 41 | 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 42 | 0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 43 | 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0, 44 | 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 45 | 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0, 46 | 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 47 | 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1, 48 | 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 49 | 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0, 50 | 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 51 | 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0, 52 | 0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 53 | 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 54 | 0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 55 | 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0, 56 | 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 57 | 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 58 | 0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 59 | 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0, 60 | 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 61 | 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0, 62 | 0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 63 | 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1, 64 | 0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 65 | 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0, 66 | 0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 67 | 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0, 68 | 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 69 | 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1, 70 | 0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 71 | 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0, 72 | 0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 73 | 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0, 74 | 0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 75 | 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0, 76 | 0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 77 | 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1, 78 | 0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 79 | 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0, 80 | 0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 81 | 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1, 82 | 0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 83 | 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1, 84 | 0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 85 | 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0, 86 | 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 87 | 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1 88 | }; 89 | 90 | const uint8_t detex_bptc_table_P3[64 * 16] = { 91 | 0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 92 | 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1, 93 | 0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 94 | 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1, 95 | 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 96 | 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2, 97 | 0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 98 | 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1, 99 | 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 100 | 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, 101 | 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 102 | 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2, 103 | 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 104 | 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2, 105 | 0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 106 | 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0, 107 | 0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 108 | 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0, 109 | 0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 110 | 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1, 111 | 0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 112 | 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1, 113 | 0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 114 | 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0, 115 | 0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 116 | 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2, 117 | 0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 118 | 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1, 119 | 0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 120 | 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2, 121 | 0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 122 | 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1, 123 | 0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 124 | 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1, 125 | 0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 126 | 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0, 127 | 0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 128 | 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0, 129 | 0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 130 | 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1, 131 | 0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 132 | 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, 133 | 0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 134 | 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2, 135 | 0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 136 | 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1, 137 | 0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 138 | 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1, 139 | 0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 140 | 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1, 141 | 0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 142 | 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2, 143 | 0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 144 | 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2, 145 | 0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 146 | 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2, 147 | 0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 148 | 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2, 149 | 0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 150 | 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2, 151 | 0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 152 | 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2, 153 | 0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 154 | 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0, 155 | }; 156 | 157 | const uint8_t detex_bptc_table_anchor_index_second_subset[64] = { 158 | 15,15,15,15,15,15,15,15, 159 | 15,15,15,15,15,15,15,15, 160 | 15, 2, 8, 2, 2, 8, 8,15, 161 | 2, 8, 2, 2, 8, 8, 2, 2, 162 | 15,15, 6, 8, 2, 8,15,15, 163 | 2, 8, 2, 2, 2,15,15, 6, 164 | 6, 2, 6, 8,15,15, 2, 2, 165 | 15,15,15,15,15, 2, 2,15 166 | }; 167 | 168 | const uint8_t detex_bptc_table_anchor_index_second_subset_of_three[64] = { 169 | 3, 3,15,15, 8, 3,15,15, 170 | 8, 8, 6, 6, 6, 5, 3, 3, 171 | 3, 3, 8,15, 3, 3, 6,10, 172 | 5, 8, 8, 6, 8, 5,15,15, 173 | 8,15, 3, 5, 6,10, 8,15, 174 | 15, 3,15, 5,15,15,15,15, 175 | 3,15, 5, 5, 5, 8, 5,10, 176 | 5,10, 8,13,15,12, 3, 3 177 | }; 178 | 179 | const uint8_t detex_bptc_table_anchor_index_third_subset[64] = { 180 | 15, 8, 8, 3,15,15, 3, 8, 181 | 15,15,15,15,15,15,15, 8, 182 | 15, 8,15, 3,15, 8,15, 8, 183 | 3,15, 6,10,15,15,10, 8, 184 | 15, 3,15,10,10, 8, 9,10, 185 | 6,15, 8,15, 3, 6, 6, 8, 186 | 15, 3,15,15,15,15,15,15, 187 | 15,15,15,15, 3,15,15, 8 188 | }; 189 | 190 | const uint16_t detex_bptc_table_aWeight2[4] = { 191 | 0, 21, 43, 64 192 | }; 193 | 194 | const uint16_t detex_bptc_table_aWeight3[8] = { 195 | 0, 9, 18, 27, 37, 46, 55, 64 196 | }; 197 | 198 | const uint16_t detex_bptc_table_aWeight4[16] = { 199 | 0, 4, 9, 13, 17, 21, 26, 30, 200 | 34, 38, 43, 47, 51, 55, 60, 64 201 | }; 202 | 203 | 204 | -------------------------------------------------------------------------------- /External/Detex/bptc-tables.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | extern const uint8_t detex_bptc_table_P2[64 * 16]; 20 | extern const uint8_t detex_bptc_table_P3[64 * 16]; 21 | 22 | extern const uint8_t detex_bptc_table_anchor_index_second_subset[64]; 23 | extern const uint8_t detex_bptc_table_anchor_index_second_subset_of_three[64]; 24 | extern const uint8_t detex_bptc_table_anchor_index_third_subset[64]; 25 | 26 | extern const uint16_t detex_bptc_table_aWeight2[4]; 27 | extern const uint16_t detex_bptc_table_aWeight3[8]; 28 | extern const uint16_t detex_bptc_table_aWeight4[16]; 29 | 30 | -------------------------------------------------------------------------------- /External/Detex/clamp.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | 21 | // Define an array to speed up clamping of values to the ranges 0 to 255. 22 | 23 | const uint8_t detex_clamp0to255_table[255 + 256 + 256] = { 24 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 41 | 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 42 | 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 43 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 44 | 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 45 | 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 46 | 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 47 | 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 48 | 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 49 | 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 50 | 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 51 | 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 52 | 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 53 | 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 54 | 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 55 | 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 56 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 57 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 58 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 59 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 60 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 61 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 65 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 66 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 67 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 68 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 69 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 70 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 71 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 72 | }; 73 | 74 | 75 | -------------------------------------------------------------------------------- /External/Detex/dds.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "detex.h" 24 | #include "file-info.h" 25 | #include "misc.h" 26 | 27 | // Load texture from DDS file with mip-maps. Returns true if successful. 28 | // nu_levels is a return parameter that returns the number of mipmap levels found. 29 | // textures_out is a return parameter for an array of detexTexture pointers that is allocated, 30 | // free with free(). textures_out[i] are allocated textures corresponding to each level, free 31 | // with free(); 32 | bool detexLoadDDSFileWithMipmaps(const char *filename, int max_mipmaps, detexTexture ***textures_out, 33 | int *nu_levels_out) { 34 | FILE *f = fopen(filename, "rb"); 35 | if (f == NULL) { 36 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Could not open file %s", filename); 37 | return false; 38 | } 39 | // Read signature. 40 | char id[4]; 41 | size_t s = fread(id, 1, 4, f); 42 | if (s != 4) { 43 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Error reading file %s", filename); 44 | return false; 45 | } 46 | if (id[0] != 'D' || id[1] != 'D' || id[2] != 'S' || id[3] != ' ') { 47 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Couldn't find DDS signature"); 48 | return false; 49 | } 50 | uint8_t header[124]; 51 | s = fread(header, 1, 124, f); 52 | if (s != 124) { 53 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Error reading file %s", filename); 54 | return false; 55 | } 56 | uint8_t *headerp = &header[0]; 57 | int width = *(uint32_t *)(headerp + 12); 58 | int height = *(uint32_t *)(headerp + 8); 59 | // int pitch = *(uint32_t *)(headerp + 16); 60 | int pixel_format_flags = *(uint32_t *)(headerp + 76); 61 | int block_width = 4; 62 | int block_height = 4; 63 | int bitcount = *(uint32_t *)(headerp + 84); 64 | uint32_t red_mask = *(uint32_t *)(headerp + 88); 65 | uint32_t green_mask = *(uint32_t *)(headerp + 92); 66 | uint32_t blue_mask = *(uint32_t *)(headerp + 96); 67 | uint32_t alpha_mask = *(uint32_t *)(headerp + 100); 68 | char four_cc[5]; 69 | strncpy(four_cc, (char *)&header[80], 4); 70 | four_cc[4] = '\0'; 71 | uint32_t dx10_format = 0; 72 | if (strncmp(four_cc, "DX10", 4) == 0) { 73 | uint32_t dx10_header[5]; 74 | s = fread(dx10_header, 1, 20, f); 75 | if (s != 20) { 76 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Error reading file %s", filename); 77 | return false; 78 | } 79 | dx10_format = dx10_header[0]; 80 | uint32_t resource_dimension = dx10_header[1]; 81 | if (resource_dimension != 3) { 82 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Only 2D textures supported for .dds files"); 83 | return false; 84 | } 85 | } 86 | const detexTextureFileInfo *info = detexLookupDDSFileInfo(four_cc, dx10_format, pixel_format_flags, bitcount, 87 | red_mask, green_mask, blue_mask, alpha_mask); 88 | if (info == NULL) { 89 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Unsupported format in .dds file (fourCC = %s, " 90 | "DX10 format = %d).", four_cc, dx10_format); 91 | return false; 92 | } 93 | // Maybe implement option to treat BC1 as BC1A? 94 | int bytes_per_block; 95 | if (detexFormatIsCompressed(info->texture_format)) 96 | bytes_per_block = detexGetCompressedBlockSize(info->texture_format); 97 | else 98 | bytes_per_block = detexGetPixelSize(info->texture_format); 99 | block_width = info->block_width; 100 | block_height = info->block_height; 101 | int extended_width = ((width + block_width - 1) / block_width) * block_width; 102 | int extended_height = ((height + block_height - 1) / block_height) * block_height; 103 | uint32_t flags = *(uint32_t *)(headerp + 4); 104 | int nu_file_mipmaps = 1; 105 | if (flags & 0x20000) { 106 | nu_file_mipmaps = *(uint32_t *)(headerp + 24); 107 | // if (nu_file_mipmaps > 1 && max_mipmaps == 1) { 108 | // detexSetErrorMessage("Disregarding mipmaps beyond the first level.\n"); 109 | // } 110 | } 111 | int nu_mipmaps; 112 | if (nu_file_mipmaps > max_mipmaps) 113 | nu_mipmaps = max_mipmaps; 114 | else 115 | nu_mipmaps = nu_file_mipmaps; 116 | detexTexture **textures = (detexTexture **)malloc(sizeof(detexTexture *) * nu_mipmaps); 117 | for (int i = 0; i < nu_mipmaps; i++) { 118 | int n = (extended_height / block_width) * (extended_width / block_height); 119 | // Allocate texture. 120 | textures[i] = (detexTexture *)malloc(sizeof(detexTexture)); 121 | textures[i]->format = info->texture_format; 122 | textures[i]->data = (uint8_t *)malloc(n * bytes_per_block); 123 | textures[i]->width = width; 124 | textures[i]->height = height; 125 | textures[i]->width_in_blocks = extended_width / block_width; 126 | textures[i]->height_in_blocks = extended_height / block_height; 127 | size_t r = fread(textures[i]->data, 1, n * bytes_per_block, f); 128 | if (r < n * bytes_per_block) { 129 | detexSetErrorMessage("detexLoadDDSFileWithMipmaps: Error reading file %s", filename); 130 | return false; 131 | } 132 | // Divide by two for the next mipmap level, rounding down. 133 | if (width > 1) 134 | width >>= 1; 135 | if (height > 1) 136 | height >>= 1; 137 | extended_width = ((width + block_width - 1) / block_width) * block_width; 138 | extended_height = ((height + block_height - 1) / block_height) * block_height; 139 | } 140 | fclose(f); 141 | *nu_levels_out = nu_mipmaps; 142 | *textures_out = textures; 143 | return true; 144 | } 145 | 146 | 147 | // Load texture from DDS file (first mip-map only). Returns true if successful. 148 | // The texture is allocated, free with free(). 149 | bool detexLoadDDSFile(const char *filename, detexTexture **texture_out) { 150 | int nu_mipmaps; 151 | detexTexture **textures; 152 | bool r = detexLoadDDSFileWithMipmaps(filename, 1, &textures, &nu_mipmaps); 153 | if (!r) 154 | return false; 155 | *texture_out = textures[0]; 156 | free(textures); 157 | return true; 158 | } 159 | 160 | static const char dds_id[4] = { 161 | 'D', 'D', 'S', ' ' 162 | }; 163 | 164 | // Save textures to DDS file (multiple mip-maps levels). Return true if succesful. 165 | bool detexSaveDDSFileWithMipmaps(detexTexture **textures, int nu_levels, const char *filename) { 166 | FILE *f = fopen(filename, "wb"); 167 | if (f == NULL) { 168 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Could not open file %s for writing", filename); 169 | return false; 170 | } 171 | const detexTextureFileInfo *info = detexLookupTextureFormatFileInfo(textures[0]->format); 172 | if (info == NULL) { 173 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Could not match texture format with file format"); 174 | return false; 175 | } 176 | if (!info->dds_support) { 177 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Could not match texture format with DDS file format"); 178 | return false; 179 | } 180 | size_t r = fwrite(dds_id, 1, 4, f); 181 | if (r != 4) { 182 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Error writing to file %s", filename); 183 | return false; 184 | } 185 | int n; 186 | int block_size; 187 | if (detexFormatIsCompressed(textures[0]->format)) { 188 | n = textures[0]->width_in_blocks * textures[0]->height_in_blocks; 189 | block_size = detexGetCompressedBlockSize(textures[0]->format); 190 | } 191 | else { 192 | n = textures[0]->width * textures[0]->height; 193 | block_size = detexGetPixelSize(textures[0]->format); 194 | } 195 | uint8_t header[124]; 196 | uint8_t dx10_header[20]; 197 | memset(header, 0, 124); 198 | memset(dx10_header, 0, 20); 199 | uint32_t *header32 = (uint32_t *)header; 200 | *(uint32_t *)header32 = 124; 201 | uint32_t flags = 0x1007; 202 | if (nu_levels > 1) 203 | flags |= 0x20000; 204 | if (!detexFormatIsCompressed(textures[0]->format)) 205 | flags |= 0x8; // Pitch specified. 206 | else 207 | flags |= 0x80000; // Linear size specified. 208 | *(uint32_t *)(header + 4) = flags; // Flags 209 | *(uint32_t *)(header + 8) = textures[0]->height; 210 | *(uint32_t *)(header + 12) = textures[0]->width; 211 | *(uint32_t *)(header + 16) = n * block_size; // Linear size for compressed textures. 212 | *(uint32_t *)(header + 24) = nu_levels; // Mipmap count. 213 | *(uint32_t *)(header + 72) = 32; 214 | *(uint32_t *)(header + 76) = 0x4; // Pixel format flags (fourCC present). 215 | bool write_dx10_header = false; 216 | if (strncmp(info->dx_four_cc, "DX10", 4) == 0) { 217 | write_dx10_header = true; 218 | uint32_t *dx10_header32 = (uint32_t *)dx10_header; 219 | *(uint32_t *)dx10_header32 = info->dx10_format; 220 | *(uint32_t *)(dx10_header + 4) = 3; // Resource dimensions = 2D. 221 | *(uint32_t *)(dx10_header + 12) = 1; // Array size. 222 | } 223 | if (!detexFormatIsCompressed(info->texture_format)) { 224 | uint64_t red_mask, green_mask, blue_mask, alpha_mask; 225 | detexGetComponentMasks(info->texture_format, &red_mask, &green_mask, &blue_mask, &alpha_mask); 226 | int component_size = detexGetComponentSize(info->texture_format) * 8; 227 | int nu_components = detexGetNumberOfComponents(info->texture_format); 228 | // Note: Some readers don't like the absence of other fields (such as the component masks and pixel 229 | // formats) for uncompressed data with a DX10 header. 230 | *(uint32_t *)(header + 84) = nu_components * component_size; // bit count 231 | *(uint32_t *)(header + 88) = (uint32_t)red_mask; 232 | *(uint32_t *)(header + 92) = (uint32_t)green_mask; 233 | *(uint32_t *)(header + 96) = (uint32_t)blue_mask; 234 | *(uint32_t *)(header + 100) = (uint32_t)alpha_mask; 235 | // Format does not have a FOURCC code (legacy uncompressed format). 236 | uint32_t pixel_format_flags = 0x40; // Uncompressed RGB data present. 237 | if (strlen(info->dx_four_cc) > 0) 238 | pixel_format_flags |= 0x04; // FourCC present. 239 | if (detexFormatHasAlpha(info->texture_format)) 240 | pixel_format_flags |= 0x01; 241 | *(uint32_t *)(header + 76) = pixel_format_flags; 242 | } 243 | if (strlen(info->dx_four_cc) > 0) { 244 | // In case of DXTn or DX10 fourCC, set it. 245 | strncpy((char *)(header + 80), info->dx_four_cc, 4); 246 | // Pixel format field was already set to 0x4 (FourCC present) by default. 247 | } 248 | uint32_t caps = 0x1000; 249 | if (nu_levels > 1) 250 | caps |= 0x400008; 251 | *(uint32_t *)(header + 104) = caps; // Caps. 252 | int pitch = textures[0]->width * detexGetPixelSize(textures[0]->format); 253 | if (!detexFormatIsCompressed(textures[0]->format)) 254 | *(uint32_t *)(header + 16) = pitch; 255 | r = fwrite(header, 1, 124, f); 256 | if (r != 124) { 257 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Error writing to file %s", filename); 258 | return false; 259 | } 260 | if (write_dx10_header) { 261 | r = fwrite(dx10_header, 1, 20, f); 262 | if (r != 20) { 263 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Error writing to file %s", filename); 264 | return false; 265 | } 266 | } 267 | // Write data. 268 | for (int i = 0; i < nu_levels; i++) { 269 | uint32_t pixel_size = detexGetPixelSize(textures[i]->format); 270 | // Block size is block size for compressed textures and the pixel size for 271 | // uncompressed textures. 272 | int n; 273 | int block_size; 274 | if (detexFormatIsCompressed(textures[i]->format)) { 275 | n = textures[i]->width_in_blocks * textures[i]->height_in_blocks; 276 | block_size = detexGetCompressedBlockSize(textures[i]->format); 277 | } 278 | else { 279 | n = textures[i]->width * textures[i]->height; 280 | block_size = pixel_size; 281 | } 282 | // Write level data. 283 | r = fwrite(textures[i]->data, 1, n * block_size, f); 284 | if (r != n * block_size) { 285 | detexSetErrorMessage("detexSaveDDSFileWithMipmaps: Error writing to file %s", filename); 286 | return false; 287 | } 288 | } 289 | fclose(f); 290 | return true; 291 | } 292 | 293 | // Save texture to DDS file (single mip-map level). Returns true if succesful. 294 | bool detexSaveDDSFile(detexTexture *texture, const char *filename) { 295 | detexTexture *textures[1]; 296 | textures[0] = texture; 297 | return detexSaveDDSFileWithMipmaps(textures, 1, filename); 298 | } 299 | 300 | -------------------------------------------------------------------------------- /External/Detex/decompress-bc.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | 21 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the BC1 */ 22 | /* format. */ 23 | bool detexDecompressBlockBC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 24 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 25 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) 26 | uint32_t colors = *(uint32_t *)&bitstring[0]; 27 | #else 28 | uint32_t colors = ((uint32_t)bitstring[0] << 24) | 29 | ((uint32_t)bitstring[1] << 16) | 30 | ((uint32_t)bitstring[2] << 8) | bitstring[3]; 31 | #endif 32 | // Decode the two 5-6-5 RGB colors. 33 | int color_r[4], color_g[4], color_b[4]; 34 | color_b[0] = (colors & 0x0000001F) << 3; 35 | color_g[0] = (colors & 0x000007E0) >> (5 - 2); 36 | color_r[0] = (colors & 0x0000F800) >> (11 - 3); 37 | color_b[1] = (colors & 0x001F0000) >> (16 - 3); 38 | color_g[1] = (colors & 0x07E00000) >> (21 - 2); 39 | color_r[1] = (colors & 0xF8000000) >> (27 - 3); 40 | if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16)) { 41 | color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); 42 | color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); 43 | color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); 44 | color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); 45 | color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); 46 | color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); 47 | } 48 | else { 49 | color_r[2] = (color_r[0] + color_r[1]) / 2; 50 | color_g[2] = (color_g[0] + color_g[1]) / 2; 51 | color_b[2] = (color_b[0] + color_b[1]) / 2; 52 | color_r[3] = color_g[3] = color_b[3] = 0; 53 | } 54 | uint32_t pixels = *(uint32_t *)&bitstring[4]; 55 | for (int i = 0; i < 16; i++) { 56 | int pixel = (pixels >> (i * 2)) & 0x3; 57 | *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGB8Alpha0xFF( 58 | color_r[pixel], color_g[pixel], color_b[pixel]); 59 | } 60 | return true; 61 | } 62 | 63 | uint32_t detexGetModeBC1(const uint8_t *bitstring) { 64 | uint32_t colors = *(uint32_t *)bitstring; 65 | if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16)) 66 | return 0; 67 | else 68 | return 1; 69 | } 70 | 71 | void detexSetModeBC1(uint8_t *bitstring, uint32_t mode, uint32_t flags, 72 | uint32_t *colors) { 73 | uint32_t colorbits = *(uint32_t *)bitstring; 74 | uint32_t current_mode; 75 | if ((colorbits & 0xFFFF) > ((colorbits & 0xFFFF0000) >> 16)) 76 | current_mode = 0; 77 | else 78 | current_mode = 1; 79 | if (current_mode != mode) { 80 | colorbits = ((colorbits & 0xFFFF) << 16) | (colorbits >> 16); 81 | *(uint32_t *)bitstring = colorbits; 82 | } 83 | } 84 | 85 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the BC1A */ 86 | /* format. */ 87 | bool detexDecompressBlockBC1A(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 88 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 89 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) 90 | uint32_t colors = *(uint32_t *)&bitstring[0]; 91 | #else 92 | uint32_t colors = ((uint32_t)bitstring[0] << 24) | 93 | ((uint32_t)bitstring[1] << 16) | 94 | ((uint32_t)bitstring[2] << 8) | bitstring[3]; 95 | #endif 96 | bool opaque = ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16)); 97 | if (opaque && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY)) 98 | return false; 99 | if (!opaque && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY)) 100 | return false; 101 | // Decode the two 5-6-5 RGB colors. 102 | int color_r[4], color_g[4], color_b[4], color_a[4]; 103 | color_b[0] = (colors & 0x0000001F) << 3; 104 | color_g[0] = (colors & 0x000007E0) >> (5 - 2); 105 | color_r[0] = (colors & 0x0000F800) >> (11 - 3); 106 | color_b[1] = (colors & 0x001F0000) >> (16 - 3); 107 | color_g[1] = (colors & 0x07E00000) >> (21 - 2); 108 | color_r[1] = (colors & 0xF8000000) >> (27 - 3); 109 | color_a[0] = color_a[1] = color_a[2] = color_a[3] = 0xFF; 110 | if (opaque) { 111 | color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); 112 | color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); 113 | color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); 114 | color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); 115 | color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); 116 | color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); 117 | } 118 | else { 119 | color_r[2] = (color_r[0] + color_r[1]) / 2; 120 | color_g[2] = (color_g[0] + color_g[1]) / 2; 121 | color_b[2] = (color_b[0] + color_b[1]) / 2; 122 | color_r[3] = color_g[3] = color_b[3] = color_a[3] = 0; 123 | } 124 | uint32_t pixels = *(uint32_t *)&bitstring[4]; 125 | for (int i = 0; i < 16; i++) { 126 | int pixel = (pixels >> (i * 2)) & 0x3; 127 | *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8( 128 | color_r[pixel], color_g[pixel], color_b[pixel], 129 | color_a[pixel]); 130 | } 131 | return true; 132 | } 133 | 134 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the BC2 */ 135 | /* format. */ 136 | bool detexDecompressBlockBC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 137 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 138 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) 139 | uint32_t colors = *(uint32_t *)&bitstring[8]; 140 | #else 141 | uint32_t colors = ((uint32_t)bitstring[8] << 24) | 142 | ((uint32_t)bitstring[9] << 16) | 143 | ((uint32_t)bitstring[10] << 8) | bitstring[11]; 144 | #endif 145 | if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) && 146 | (flags & DETEX_DECOMPRESS_FLAG_ENCODE)) 147 | // GeForce 6 and 7 series produce wrong result in this case. 148 | return false; 149 | int color_r[4], color_g[4], color_b[4]; 150 | color_b[0] = (colors & 0x0000001F) << 3; 151 | color_g[0] = (colors & 0x000007E0) >> (5 - 2); 152 | color_r[0] = (colors & 0x0000F800) >> (11 - 3); 153 | color_b[1] = (colors & 0x001F0000) >> (16 - 3); 154 | color_g[1] = (colors & 0x07E00000) >> (21 - 2); 155 | color_r[1] = (colors & 0xF8000000) >> (27 - 3); 156 | color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); 157 | color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); 158 | color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); 159 | color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); 160 | color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); 161 | color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); 162 | uint32_t pixels = *(uint32_t *)&bitstring[12]; 163 | uint64_t alpha_pixels = *(uint64_t *)&bitstring[0]; 164 | for (int i = 0; i < 16; i++) { 165 | int pixel = (pixels >> (i * 2)) & 0x3; 166 | int alpha = ((alpha_pixels >> (i * 4)) & 0xF) * 255 / 15; 167 | *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8( 168 | color_r[pixel], color_g[pixel], color_b[pixel], alpha); 169 | } 170 | return true; 171 | } 172 | 173 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the BC3 */ 174 | /* format. */ 175 | bool detexDecompressBlockBC3(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 176 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 177 | int alpha0 = bitstring[0]; 178 | int alpha1 = bitstring[1]; 179 | if (alpha0 > alpha1 && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY)) 180 | return false; 181 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) 182 | uint32_t colors = *(uint32_t *)&bitstring[8]; 183 | #else 184 | uint32_t colors = ((uint32_t)bitstring[8] << 24) | 185 | ((uint32_t)bitstring[9] << 16) | 186 | ((uint32_t)bitstring[10] << 8) | bitstring[11]; 187 | #endif 188 | if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) && 189 | (flags & DETEX_DECOMPRESS_FLAG_ENCODE)) 190 | // GeForce 6 and 7 series produce wrong result in this case. 191 | return false; 192 | int color_r[4], color_g[4], color_b[4]; 193 | // color_x[] has a value between 0 and 248 with the lower three bits zero. 194 | color_b[0] = (colors & 0x0000001F) << 3; 195 | color_g[0] = (colors & 0x000007E0) >> (5 - 2); 196 | color_r[0] = (colors & 0x0000F800) >> (11 - 3); 197 | color_b[1] = (colors & 0x001F0000) >> (16 - 3); 198 | color_g[1] = (colors & 0x07E00000) >> (21 - 2); 199 | color_r[1] = (colors & 0xF8000000) >> (27 - 3); 200 | color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); 201 | color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); 202 | color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); 203 | color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); 204 | color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); 205 | color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); 206 | uint32_t pixels = *(uint32_t *)&bitstring[12]; 207 | uint64_t alpha_bits = (uint32_t)bitstring[2] | 208 | ((uint32_t)bitstring[3] << 8) | 209 | ((uint64_t)*(uint32_t *)&bitstring[4] << 16); 210 | for (int i = 0; i < 16; i++) { 211 | int pixel = (pixels >> (i * 2)) & 0x3; 212 | int code = (alpha_bits >> (i * 3)) & 0x7; 213 | int alpha; 214 | if (alpha0 > alpha1) 215 | switch (code) { 216 | case 0 : alpha = alpha0; break; 217 | case 1 : alpha = alpha1; break; 218 | case 2 : alpha = detexDivide0To1791By7(6 * alpha0 + 1 * alpha1); break; 219 | case 3 : alpha = detexDivide0To1791By7(5 * alpha0 + 2 * alpha1); break; 220 | case 4 : alpha = detexDivide0To1791By7(4 * alpha0 + 3 * alpha1); break; 221 | case 5 : alpha = detexDivide0To1791By7(3 * alpha0 + 4 * alpha1); break; 222 | case 6 : alpha = detexDivide0To1791By7(2 * alpha0 + 5 * alpha1); break; 223 | case 7 : alpha = detexDivide0To1791By7(1 * alpha0 + 6 * alpha1); break; 224 | } 225 | else 226 | switch (code) { 227 | case 0 : alpha = alpha0; break; 228 | case 1 : alpha = alpha1; break; 229 | case 2 : alpha = detexDivide0To1279By5(4 * alpha0 + 1 * alpha1); break; 230 | case 3 : alpha = detexDivide0To1279By5(3 * alpha0 + 2 * alpha1); break; 231 | case 4 : alpha = detexDivide0To1279By5(2 * alpha0 + 3 * alpha1); break; 232 | case 5 : alpha = detexDivide0To1279By5(1 * alpha0 + 4 * alpha1); break; 233 | case 6 : alpha = 0; break; 234 | case 7 : alpha = 0xFF; break; 235 | } 236 | *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8( 237 | color_r[pixel], color_g[pixel], color_b[pixel], alpha); 238 | } 239 | return true; 240 | } 241 | 242 | -------------------------------------------------------------------------------- /External/Detex/decompress-eac.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | 21 | static const int8_t eac_modifier_table[16][8] = { 22 | { -3, -6, -9, -15, 2, 5, 8, 14 }, 23 | { -3, -7, -10, -13, 2, 6, 9, 12 }, 24 | { -2, -5, -8, -13, 1, 4, 7, 12 }, 25 | { -2, -4, -6, -13, 1, 3, 5, 12 }, 26 | { -3, -6, -8, -12, 2, 5, 7, 11 }, 27 | { -3, -7, -9, -11, 2, 6, 8, 10 }, 28 | { -4, -7, -8, -11, 3, 6, 7, 10 }, 29 | { -3, -5, -8, -11, 2, 4, 7, 10 }, 30 | { -2, -6, -8, -10, 1, 5, 7, 9 }, 31 | { -2, -5, -8, -10, 1, 4, 7, 9 }, 32 | { -2, -4, -8, -10, 1, 3, 7, 9 }, 33 | { -2, -5, -7, -10, 1, 4, 6, 9 }, 34 | { -3, -4, -7, -10, 2, 3, 6, 9 }, 35 | { -1, -2, -3, -10, 0, 1, 2, 9 }, 36 | { -4, -6, -8, -9, 3, 5, 7, 8 }, 37 | { -3, -5, -7, -9, 2, 4, 6, 8 } 38 | }; 39 | 40 | static DETEX_INLINE_ONLY int modifier_times_multiplier(int modifier, int multiplier) { 41 | return modifier * multiplier; 42 | } 43 | 44 | static DETEX_INLINE_ONLY void ProcessPixelEAC(uint8_t i, uint64_t pixels, 45 | const int8_t * DETEX_RESTRICT modifier_table, int base_codeword, int multiplier, 46 | uint8_t * DETEX_RESTRICT pixel_buffer) { 47 | int modifier = modifier_table[(pixels >> (45 - i * 3)) & 7]; 48 | pixel_buffer[((i & 3) * 4 + ((i & 12) >> 2)) * 4 + DETEX_PIXEL32_ALPHA_BYTE_OFFSET] = 49 | detexClamp0To255(base_codeword + modifier_times_multiplier(modifier, multiplier)); 50 | } 51 | 52 | /* Decompress a 128-bit 4x4 pixel texture block compressed using the ETC2_EAC */ 53 | /* format. */ 54 | bool detexDecompressBlockETC2_EAC(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 55 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 56 | bool r = detexDecompressBlockETC2(&bitstring[8], mode_mask, flags, pixel_buffer); 57 | if (!r) 58 | return false; 59 | // Decode the alpha part. 60 | int base_codeword = bitstring[0]; 61 | const int8_t *modifier_table = eac_modifier_table[(bitstring[1] & 0x0F)]; 62 | int multiplier = (bitstring[1] & 0xF0) >> 4; 63 | if (multiplier == 0 && (flags & DETEX_DECOMPRESS_FLAG_ENCODE)) 64 | // Not allowed in encoding. Decoder should handle it. 65 | return false; 66 | uint64_t pixels = ((uint64_t)bitstring[2] << 40) | ((uint64_t)bitstring[3] << 32) | 67 | ((uint64_t)bitstring[4] << 24) 68 | | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7]; 69 | ProcessPixelEAC(0, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 70 | ProcessPixelEAC(1, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 71 | ProcessPixelEAC(2, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 72 | ProcessPixelEAC(3, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 73 | ProcessPixelEAC(4, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 74 | ProcessPixelEAC(5, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 75 | ProcessPixelEAC(6, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 76 | ProcessPixelEAC(7, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 77 | ProcessPixelEAC(8, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 78 | ProcessPixelEAC(9, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 79 | ProcessPixelEAC(10, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 80 | ProcessPixelEAC(11, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 81 | ProcessPixelEAC(12, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 82 | ProcessPixelEAC(13, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 83 | ProcessPixelEAC(14, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 84 | ProcessPixelEAC(15, pixels, modifier_table, base_codeword, multiplier, pixel_buffer); 85 | return true; 86 | } 87 | 88 | /* Return the internal mode of a ETC2_EAC block. */ 89 | uint32_t detexGetModeETC2_EAC(const uint8_t *bitstring) { 90 | return detexGetModeETC2(&bitstring[8]); 91 | } 92 | 93 | void detexSetModeETC2_EAC(uint8_t *bitstring, uint32_t mode, uint32_t flags, 94 | uint32_t *colors) { 95 | detexSetModeETC2(&bitstring[8], mode, flags, colors); 96 | } 97 | 98 | static DETEX_INLINE_ONLY int Clamp0To2047(int x) { 99 | if (x < 0) 100 | return 0; 101 | if (x > 2047) 102 | return 2047; 103 | return x; 104 | } 105 | 106 | // For each pixel, decode an 11-bit integer and store as follows: 107 | // If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer. 108 | // If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset 109 | // is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each 110 | // 32-bit word. 111 | static DETEX_INLINE_ONLY void DecodeBlockEAC11Bit(uint64_t qword, int shift, int offset, 112 | uint8_t * DETEX_RESTRICT pixel_buffer) { 113 | int base_codeword_times_8_plus_4 = ((qword & 0xFF00000000000000) >> (56 - 3)) | 0x4; 114 | int modifier_index = (qword & 0x000F000000000000) >> 48; 115 | const int8_t *modifier_table = eac_modifier_table[modifier_index]; 116 | int multiplier_times_8 = (qword & 0x00F0000000000000) >> (52 - 3); 117 | if (multiplier_times_8 == 0) 118 | multiplier_times_8 = 1; 119 | uint16_t *buffer = (uint16_t *)pixel_buffer; 120 | for (int i = 0; i < 16; i++) { 121 | int pixel_index = (int)((qword & (0x0000E00000000000 >> (i * 3))) >> (45 - i * 3)); 122 | int modifier = modifier_table[pixel_index]; 123 | uint32_t value = Clamp0To2047(base_codeword_times_8_plus_4 + 124 | modifier * multiplier_times_8); 125 | buffer[(((i & 3) * 4 + ((i & 12) >> 2)) << shift) + offset] = 126 | (value << 5) | (value >> 6); // Replicate bits to 16-bit. 127 | } 128 | } 129 | 130 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the */ 131 | /* EAC_R11 format. */ 132 | bool detexDecompressBlockEAC_R11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 133 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 134 | uint64_t qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | 135 | ((uint64_t)bitstring[2] << 40) | 136 | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | 137 | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7]; 138 | DecodeBlockEAC11Bit(qword, 0, 0, pixel_buffer); 139 | return true; 140 | } 141 | 142 | /* Decompress a 128-bit 4x4 pixel texture block compressed using the */ 143 | /* EAC_RG11 format. */ 144 | bool detexDecompressBlockEAC_RG11(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 145 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 146 | uint64_t red_qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | 147 | ((uint64_t)bitstring[2] << 40) | 148 | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | 149 | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7]; 150 | DecodeBlockEAC11Bit(red_qword, 1, 0, pixel_buffer); 151 | uint64_t green_qword = ((uint64_t)bitstring[8] << 56) | ((uint64_t)bitstring[9] << 48) | 152 | ((uint64_t)bitstring[10] << 40) | 153 | ((uint64_t)bitstring[11] << 32) | ((uint64_t)bitstring[12] << 24) | 154 | ((uint64_t)bitstring[13] << 16) | ((uint64_t)bitstring[14] << 8) | bitstring[15]; 155 | DecodeBlockEAC11Bit(green_qword, 1, 1, pixel_buffer); 156 | return true; 157 | } 158 | 159 | static DETEX_INLINE_ONLY int ClampMinus1023To1023(int x) { 160 | if (x < - 1023) 161 | return - 1023; 162 | if (x > 1023) 163 | return 1023; 164 | return x; 165 | } 166 | 167 | static DETEX_INLINE_ONLY uint32_t ReplicateSigned11BitsTo16Bits(int value) { 168 | if (value >= 0) 169 | return (value << 5) | (value >> 5); 170 | value = - value; 171 | value = (value << 5) | (value >> 5); 172 | return - value; 173 | } 174 | 175 | // For each pixel, decode an 11-bit signed integer and store as follows: 176 | // If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer. 177 | // If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset 178 | // is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each 179 | // 32-bit word. 180 | static DETEX_INLINE_ONLY bool DecodeBlockEACSigned11Bit(uint64_t qword, int shift, int offset, 181 | uint8_t *pixel_buffer) { 182 | int base_codeword = (int8_t)((qword & 0xFF00000000000000) >> 56); // Signed 8 bits. 183 | if (base_codeword == - 128) 184 | // Not allowed in encoding. Decoder should handle it but we don't do that yet. 185 | return false; 186 | int base_codeword_times_8 = base_codeword << 3; // Arithmetic shift. 187 | int modifier_index = (qword & 0x000F000000000000) >> 48; 188 | const int8_t *modifier_table = eac_modifier_table[modifier_index]; 189 | int multiplier_times_8 = (qword & 0x00F0000000000000) >> (52 - 3); 190 | if (multiplier_times_8 == 0) 191 | multiplier_times_8 = 1; 192 | uint16_t *buffer = (uint16_t *)pixel_buffer; 193 | for (int i = 0; i < 16; i++) { 194 | int pixel_index = (int)((qword & (0x0000E00000000000 >> (i * 3))) >> (45 - i * 3)); 195 | int modifier = modifier_table[pixel_index]; 196 | int value = ClampMinus1023To1023(base_codeword_times_8 + 197 | modifier * multiplier_times_8); 198 | uint32_t bits = ReplicateSigned11BitsTo16Bits(value); 199 | buffer[(((i & 3) * 4 + ((i & 12) >> 2)) << shift) + offset] = bits; 200 | } 201 | return true; 202 | } 203 | 204 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the */ 205 | /* EAC_SIGNED_R11 format. */ 206 | bool detexDecompressBlockEAC_SIGNED_R11(const uint8_t * DETEX_RESTRICT bitstring, 207 | uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 208 | uint64_t qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | 209 | ((uint64_t)bitstring[2] << 40) | 210 | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | 211 | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7]; 212 | return DecodeBlockEACSigned11Bit(qword, 0, 0, pixel_buffer); 213 | } 214 | 215 | /* Decompress a 128-bit 4x4 pixel texture block compressed using the */ 216 | /* EAC_SIGNED_RG11 format. */ 217 | bool detexDecompressBlockEAC_SIGNED_RG11(const uint8_t * DETEX_RESTRICT bitstring, 218 | uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 219 | uint64_t red_qword = ((uint64_t)bitstring[0] << 56) | ((uint64_t)bitstring[1] << 48) | 220 | ((uint64_t)bitstring[2] << 40) | 221 | ((uint64_t)bitstring[3] << 32) | ((uint64_t)bitstring[4] << 24) | 222 | ((uint64_t)bitstring[5] << 16) | ((uint64_t)bitstring[6] << 8) | bitstring[7]; 223 | int r = DecodeBlockEACSigned11Bit(red_qword, 1, 0, pixel_buffer); 224 | if (!r) 225 | return false; 226 | uint64_t green_qword = ((uint64_t)bitstring[8] << 56) | ((uint64_t)bitstring[9] << 48) | 227 | ((uint64_t)bitstring[10] << 40) | 228 | ((uint64_t)bitstring[11] << 32) | ((uint64_t)bitstring[12] << 24) | 229 | ((uint64_t)bitstring[13] << 16) | ((uint64_t)bitstring[14] << 8) | bitstring[15]; 230 | return DecodeBlockEACSigned11Bit(green_qword, 1, 1, pixel_buffer); 231 | } 232 | 233 | -------------------------------------------------------------------------------- /External/Detex/decompress-rgtc.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | 21 | // For each pixel, decode an 8-bit integer and store as follows: 22 | // If shift and offset are zero, store each value in consecutive 8 bit values in pixel_buffer. 23 | // If shift is one, store each value in consecutive 16-bit words in pixel_buffer; if offset 24 | // is zero, store it in the first 8 bits, if offset is one store it in the last 8 bits of each 25 | // 16-bit word. 26 | static DETEX_INLINE_ONLY void DecodeBlockRGTC(const uint8_t * DETEX_RESTRICT bitstring, int shift, 27 | int offset, uint8_t * DETEX_RESTRICT pixel_buffer) { 28 | // LSBFirst byte order only. 29 | uint64_t bits = (*(uint64_t *)&bitstring[0]) >> 16; 30 | int lum0 = bitstring[0]; 31 | int lum1 = bitstring[1]; 32 | for (int i = 0; i < 16; i++) { 33 | int control_code = bits & 0x7; 34 | uint8_t output; 35 | if (lum0 > lum1) 36 | switch (control_code) { 37 | case 0 : output = lum0; break; 38 | case 1 : output = lum1; break; 39 | case 2 : output = detexDivide0To1791By7(6 * lum0 + lum1); break; 40 | case 3 : output = detexDivide0To1791By7(5 * lum0 + 2 * lum1); break; 41 | case 4 : output = detexDivide0To1791By7(4 * lum0 + 3 * lum1); break; 42 | case 5 : output = detexDivide0To1791By7(3 * lum0 + 4 * lum1); break; 43 | case 6 : output = detexDivide0To1791By7(2 * lum0 + 5 * lum1); break; 44 | case 7 : output = detexDivide0To1791By7(lum0 + 6 * lum1); break; 45 | } 46 | else 47 | switch (control_code) { 48 | case 0 : output = lum0; break; 49 | case 1 : output = lum1; break; 50 | case 2 : output = detexDivide0To1279By5(4 * lum0 + lum1); break; 51 | case 3 : output = detexDivide0To1279By5(3 * lum0 + 2 * lum1); break; 52 | case 4 : output = detexDivide0To1279By5(2 * lum0 + 3 * lum1); break; 53 | case 5 : output = detexDivide0To1279By5(lum0 + 4 * lum1); break; 54 | case 6 : output = 0; break; 55 | case 7 : output = 0xFF; break; 56 | } 57 | pixel_buffer[(i << shift) + offset] = output; 58 | bits >>= 3; 59 | } 60 | } 61 | 62 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the */ 63 | /* unsigned RGTC1 (BC4) format. */ 64 | bool detexDecompressBlockRGTC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 65 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 66 | DecodeBlockRGTC(bitstring, 0, 0, pixel_buffer); 67 | return true; 68 | } 69 | 70 | /* Decompress a 128-bit 4x4 pixel texture block compressed using the */ 71 | /* unsigned RGTC2 (BC5) format. */ 72 | bool detexDecompressBlockRGTC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 73 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 74 | DecodeBlockRGTC(bitstring, 1, 0, pixel_buffer); 75 | DecodeBlockRGTC(&bitstring[8], 1, 1, pixel_buffer); 76 | return true; 77 | } 78 | 79 | // For each pixel, decode an 16-bit integer and store as follows: 80 | // If shift and offset are zero, store each value in consecutive 16 bit values in pixel_buffer. 81 | // If shift is one, store each value in consecutive 32-bit words in pixel_buffer; if offset 82 | // is zero, store it in the first 16 bits, if offset is one store it in the last 16 bits of each 83 | // 32-bit word. Returns true if the compressed block is valid. 84 | static DETEX_INLINE_ONLY bool DecodeBlockSignedRGTC(const uint8_t * DETEX_RESTRICT bitstring, int shift, 85 | int offset, uint8_t * DETEX_RESTRICT pixel_buffer) { 86 | // LSBFirst byte order only. 87 | uint64_t bits = (*(uint64_t *)&bitstring[0]) >> 16; 88 | int lum0 = (int8_t)bitstring[0]; 89 | int lum1 = (int8_t)bitstring[1]; 90 | if (lum0 == - 127 && lum1 == - 128) 91 | // Not allowed. 92 | return false; 93 | if (lum0 == - 128) 94 | lum0 = - 127; 95 | if (lum1 == - 128) 96 | lum1 = - 127; 97 | // Note: values are mapped to a red value of -127 to 127. 98 | uint16_t *pixel16_buffer = (uint16_t *)pixel_buffer; 99 | for (int i = 0; i < 16; i++) { 100 | int control_code = bits & 0x7; 101 | int32_t result; 102 | if (lum0 > lum1) 103 | switch (control_code) { 104 | case 0 : result = lum0; break; 105 | case 1 : result = lum1; break; 106 | case 2 : result = detexDivideMinus895To895By7(6 * lum0 + lum1); break; 107 | case 3 : result = detexDivideMinus895To895By7(5 * lum0 + 2 * lum1); break; 108 | case 4 : result = detexDivideMinus895To895By7(4 * lum0 + 3 * lum1); break; 109 | case 5 : result = detexDivideMinus895To895By7(3 * lum0 + 4 * lum1); break; 110 | case 6 : result = detexDivideMinus895To895By7(2 * lum0 + 5 * lum1); break; 111 | case 7 : result = detexDivideMinus895To895By7(lum0 + 6 * lum1); break; 112 | } 113 | else 114 | switch (control_code) { 115 | case 0 : result = lum0; break; 116 | case 1 : result = lum1; break; 117 | case 2 : result = detexDivideMinus639To639By5(4 * lum0 + lum1); break; 118 | case 3 : result = detexDivideMinus639To639By5(3 * lum0 + 2 * lum1); break; 119 | case 4 : result = detexDivideMinus639To639By5(2 * lum0 + 3 * lum1); break; 120 | case 5 : result = detexDivideMinus639To639By5(lum0 + 4 * lum1); break; 121 | case 6 : result = - 127; break; 122 | case 7 : result = 127; break; 123 | } 124 | // Map from [-127, 127] to [-32768, 32767]. 125 | pixel16_buffer[(i << shift) + offset] = (uint16_t)(int16_t) 126 | ((result + 127) * 65535 / 254 - 32768); 127 | bits >>= 3; 128 | } 129 | return true; 130 | } 131 | 132 | /* Decompress a 64-bit 4x4 pixel texture block compressed using the */ 133 | /* signed RGTC1 (signed BC4) format. */ 134 | bool detexDecompressBlockSIGNED_RGTC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 135 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 136 | return DecodeBlockSignedRGTC(bitstring, 0, 0, pixel_buffer); 137 | } 138 | 139 | /* Decompress a 128-bit 4x4 pixel texture block compressed using the */ 140 | /* signed RGTC2 (signed BC5) format. */ 141 | bool detexDecompressBlockSIGNED_RGTC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, 142 | uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { 143 | bool r = DecodeBlockSignedRGTC(bitstring, 1, 0, pixel_buffer); 144 | if (!r) 145 | return false; 146 | return DecodeBlockSignedRGTC(&bitstring[8], 1, 1, pixel_buffer); 147 | } 148 | 149 | -------------------------------------------------------------------------------- /External/Detex/division-tables.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include "detex.h" 20 | 21 | // Integer division using look-up tables, used by BC1/2/3 and RGTC (BC4/5) 22 | // decompression. 23 | 24 | const uint8_t detex_division_by_3_table[768] = { 25 | 0, 0, 0, 1, 1, 1, 2, 2, 26 | 2, 3, 3, 3, 4, 4, 4, 5, 27 | 5, 5, 6, 6, 6, 7, 7, 7, 28 | 8, 8, 8, 9, 9, 9, 10, 10, 29 | 10, 11, 11, 11, 12, 12, 12, 13, 30 | 13, 13, 14, 14, 14, 15, 15, 15, 31 | 16, 16, 16, 17, 17, 17, 18, 18, 32 | 18, 19, 19, 19, 20, 20, 20, 21, 33 | 21, 21, 22, 22, 22, 23, 23, 23, 34 | 24, 24, 24, 25, 25, 25, 26, 26, 35 | 26, 27, 27, 27, 28, 28, 28, 29, 36 | 29, 29, 30, 30, 30, 31, 31, 31, 37 | 32, 32, 32, 33, 33, 33, 34, 34, 38 | 34, 35, 35, 35, 36, 36, 36, 37, 39 | 37, 37, 38, 38, 38, 39, 39, 39, 40 | 40, 40, 40, 41, 41, 41, 42, 42, 41 | 42, 43, 43, 43, 44, 44, 44, 45, 42 | 45, 45, 46, 46, 46, 47, 47, 47, 43 | 48, 48, 48, 49, 49, 49, 50, 50, 44 | 50, 51, 51, 51, 52, 52, 52, 53, 45 | 53, 53, 54, 54, 54, 55, 55, 55, 46 | 56, 56, 56, 57, 57, 57, 58, 58, 47 | 58, 59, 59, 59, 60, 60, 60, 61, 48 | 61, 61, 62, 62, 62, 63, 63, 63, 49 | 64, 64, 64, 65, 65, 65, 66, 66, 50 | 66, 67, 67, 67, 68, 68, 68, 69, 51 | 69, 69, 70, 70, 70, 71, 71, 71, 52 | 72, 72, 72, 73, 73, 73, 74, 74, 53 | 74, 75, 75, 75, 76, 76, 76, 77, 54 | 77, 77, 78, 78, 78, 79, 79, 79, 55 | 80, 80, 80, 81, 81, 81, 82, 82, 56 | 82, 83, 83, 83, 84, 84, 84, 85, 57 | 85, 85, 86, 86, 86, 87, 87, 87, 58 | 88, 88, 88, 89, 89, 89, 90, 90, 59 | 90, 91, 91, 91, 92, 92, 92, 93, 60 | 93, 93, 94, 94, 94, 95, 95, 95, 61 | 96, 96, 96, 97, 97, 97, 98, 98, 62 | 98, 99, 99, 99, 100, 100, 100, 101, 63 | 101, 101, 102, 102, 102, 103, 103, 103, 64 | 104, 104, 104, 105, 105, 105, 106, 106, 65 | 106, 107, 107, 107, 108, 108, 108, 109, 66 | 109, 109, 110, 110, 110, 111, 111, 111, 67 | 112, 112, 112, 113, 113, 113, 114, 114, 68 | 114, 115, 115, 115, 116, 116, 116, 117, 69 | 117, 117, 118, 118, 118, 119, 119, 119, 70 | 120, 120, 120, 121, 121, 121, 122, 122, 71 | 122, 123, 123, 123, 124, 124, 124, 125, 72 | 125, 125, 126, 126, 126, 127, 127, 127, 73 | 128, 128, 128, 129, 129, 129, 130, 130, 74 | 130, 131, 131, 131, 132, 132, 132, 133, 75 | 133, 133, 134, 134, 134, 135, 135, 135, 76 | 136, 136, 136, 137, 137, 137, 138, 138, 77 | 138, 139, 139, 139, 140, 140, 140, 141, 78 | 141, 141, 142, 142, 142, 143, 143, 143, 79 | 144, 144, 144, 145, 145, 145, 146, 146, 80 | 146, 147, 147, 147, 148, 148, 148, 149, 81 | 149, 149, 150, 150, 150, 151, 151, 151, 82 | 152, 152, 152, 153, 153, 153, 154, 154, 83 | 154, 155, 155, 155, 156, 156, 156, 157, 84 | 157, 157, 158, 158, 158, 159, 159, 159, 85 | 160, 160, 160, 161, 161, 161, 162, 162, 86 | 162, 163, 163, 163, 164, 164, 164, 165, 87 | 165, 165, 166, 166, 166, 167, 167, 167, 88 | 168, 168, 168, 169, 169, 169, 170, 170, 89 | 170, 171, 171, 171, 172, 172, 172, 173, 90 | 173, 173, 174, 174, 174, 175, 175, 175, 91 | 176, 176, 176, 177, 177, 177, 178, 178, 92 | 178, 179, 179, 179, 180, 180, 180, 181, 93 | 181, 181, 182, 182, 182, 183, 183, 183, 94 | 184, 184, 184, 185, 185, 185, 186, 186, 95 | 186, 187, 187, 187, 188, 188, 188, 189, 96 | 189, 189, 190, 190, 190, 191, 191, 191, 97 | 192, 192, 192, 193, 193, 193, 194, 194, 98 | 194, 195, 195, 195, 196, 196, 196, 197, 99 | 197, 197, 198, 198, 198, 199, 199, 199, 100 | 200, 200, 200, 201, 201, 201, 202, 202, 101 | 202, 203, 203, 203, 204, 204, 204, 205, 102 | 205, 205, 206, 206, 206, 207, 207, 207, 103 | 208, 208, 208, 209, 209, 209, 210, 210, 104 | 210, 211, 211, 211, 212, 212, 212, 213, 105 | 213, 213, 214, 214, 214, 215, 215, 215, 106 | 216, 216, 216, 217, 217, 217, 218, 218, 107 | 218, 219, 219, 219, 220, 220, 220, 221, 108 | 221, 221, 222, 222, 222, 223, 223, 223, 109 | 224, 224, 224, 225, 225, 225, 226, 226, 110 | 226, 227, 227, 227, 228, 228, 228, 229, 111 | 229, 229, 230, 230, 230, 231, 231, 231, 112 | 232, 232, 232, 233, 233, 233, 234, 234, 113 | 234, 235, 235, 235, 236, 236, 236, 237, 114 | 237, 237, 238, 238, 238, 239, 239, 239, 115 | 240, 240, 240, 241, 241, 241, 242, 242, 116 | 242, 243, 243, 243, 244, 244, 244, 245, 117 | 245, 245, 246, 246, 246, 247, 247, 247, 118 | 248, 248, 248, 249, 249, 249, 250, 250, 119 | 250, 251, 251, 251, 252, 252, 252, 253, 120 | 253, 253, 254, 254, 254, 255, 255, 255, 121 | }; 122 | 123 | const uint8_t detex_division_by_7_table[1792] = { 124 | 0, 0, 0, 0, 0, 0, 0, 1, 125 | 1, 1, 1, 1, 1, 1, 2, 2, 126 | 2, 2, 2, 2, 2, 3, 3, 3, 127 | 3, 3, 3, 3, 4, 4, 4, 4, 128 | 4, 4, 4, 5, 5, 5, 5, 5, 129 | 5, 5, 6, 6, 6, 6, 6, 6, 130 | 6, 7, 7, 7, 7, 7, 7, 7, 131 | 8, 8, 8, 8, 8, 8, 8, 9, 132 | 9, 9, 9, 9, 9, 9, 10, 10, 133 | 10, 10, 10, 10, 10, 11, 11, 11, 134 | 11, 11, 11, 11, 12, 12, 12, 12, 135 | 12, 12, 12, 13, 13, 13, 13, 13, 136 | 13, 13, 14, 14, 14, 14, 14, 14, 137 | 14, 15, 15, 15, 15, 15, 15, 15, 138 | 16, 16, 16, 16, 16, 16, 16, 17, 139 | 17, 17, 17, 17, 17, 17, 18, 18, 140 | 18, 18, 18, 18, 18, 19, 19, 19, 141 | 19, 19, 19, 19, 20, 20, 20, 20, 142 | 20, 20, 20, 21, 21, 21, 21, 21, 143 | 21, 21, 22, 22, 22, 22, 22, 22, 144 | 22, 23, 23, 23, 23, 23, 23, 23, 145 | 24, 24, 24, 24, 24, 24, 24, 25, 146 | 25, 25, 25, 25, 25, 25, 26, 26, 147 | 26, 26, 26, 26, 26, 27, 27, 27, 148 | 27, 27, 27, 27, 28, 28, 28, 28, 149 | 28, 28, 28, 29, 29, 29, 29, 29, 150 | 29, 29, 30, 30, 30, 30, 30, 30, 151 | 30, 31, 31, 31, 31, 31, 31, 31, 152 | 32, 32, 32, 32, 32, 32, 32, 33, 153 | 33, 33, 33, 33, 33, 33, 34, 34, 154 | 34, 34, 34, 34, 34, 35, 35, 35, 155 | 35, 35, 35, 35, 36, 36, 36, 36, 156 | 36, 36, 36, 37, 37, 37, 37, 37, 157 | 37, 37, 38, 38, 38, 38, 38, 38, 158 | 38, 39, 39, 39, 39, 39, 39, 39, 159 | 40, 40, 40, 40, 40, 40, 40, 41, 160 | 41, 41, 41, 41, 41, 41, 42, 42, 161 | 42, 42, 42, 42, 42, 43, 43, 43, 162 | 43, 43, 43, 43, 44, 44, 44, 44, 163 | 44, 44, 44, 45, 45, 45, 45, 45, 164 | 45, 45, 46, 46, 46, 46, 46, 46, 165 | 46, 47, 47, 47, 47, 47, 47, 47, 166 | 48, 48, 48, 48, 48, 48, 48, 49, 167 | 49, 49, 49, 49, 49, 49, 50, 50, 168 | 50, 50, 50, 50, 50, 51, 51, 51, 169 | 51, 51, 51, 51, 52, 52, 52, 52, 170 | 52, 52, 52, 53, 53, 53, 53, 53, 171 | 53, 53, 54, 54, 54, 54, 54, 54, 172 | 54, 55, 55, 55, 55, 55, 55, 55, 173 | 56, 56, 56, 56, 56, 56, 56, 57, 174 | 57, 57, 57, 57, 57, 57, 58, 58, 175 | 58, 58, 58, 58, 58, 59, 59, 59, 176 | 59, 59, 59, 59, 60, 60, 60, 60, 177 | 60, 60, 60, 61, 61, 61, 61, 61, 178 | 61, 61, 62, 62, 62, 62, 62, 62, 179 | 62, 63, 63, 63, 63, 63, 63, 63, 180 | 64, 64, 64, 64, 64, 64, 64, 65, 181 | 65, 65, 65, 65, 65, 65, 66, 66, 182 | 66, 66, 66, 66, 66, 67, 67, 67, 183 | 67, 67, 67, 67, 68, 68, 68, 68, 184 | 68, 68, 68, 69, 69, 69, 69, 69, 185 | 69, 69, 70, 70, 70, 70, 70, 70, 186 | 70, 71, 71, 71, 71, 71, 71, 71, 187 | 72, 72, 72, 72, 72, 72, 72, 73, 188 | 73, 73, 73, 73, 73, 73, 74, 74, 189 | 74, 74, 74, 74, 74, 75, 75, 75, 190 | 75, 75, 75, 75, 76, 76, 76, 76, 191 | 76, 76, 76, 77, 77, 77, 77, 77, 192 | 77, 77, 78, 78, 78, 78, 78, 78, 193 | 78, 79, 79, 79, 79, 79, 79, 79, 194 | 80, 80, 80, 80, 80, 80, 80, 81, 195 | 81, 81, 81, 81, 81, 81, 82, 82, 196 | 82, 82, 82, 82, 82, 83, 83, 83, 197 | 83, 83, 83, 83, 84, 84, 84, 84, 198 | 84, 84, 84, 85, 85, 85, 85, 85, 199 | 85, 85, 86, 86, 86, 86, 86, 86, 200 | 86, 87, 87, 87, 87, 87, 87, 87, 201 | 88, 88, 88, 88, 88, 88, 88, 89, 202 | 89, 89, 89, 89, 89, 89, 90, 90, 203 | 90, 90, 90, 90, 90, 91, 91, 91, 204 | 91, 91, 91, 91, 92, 92, 92, 92, 205 | 92, 92, 92, 93, 93, 93, 93, 93, 206 | 93, 93, 94, 94, 94, 94, 94, 94, 207 | 94, 95, 95, 95, 95, 95, 95, 95, 208 | 96, 96, 96, 96, 96, 96, 96, 97, 209 | 97, 97, 97, 97, 97, 97, 98, 98, 210 | 98, 98, 98, 98, 98, 99, 99, 99, 211 | 99, 99, 99, 99, 100, 100, 100, 100, 212 | 100, 100, 100, 101, 101, 101, 101, 101, 213 | 101, 101, 102, 102, 102, 102, 102, 102, 214 | 102, 103, 103, 103, 103, 103, 103, 103, 215 | 104, 104, 104, 104, 104, 104, 104, 105, 216 | 105, 105, 105, 105, 105, 105, 106, 106, 217 | 106, 106, 106, 106, 106, 107, 107, 107, 218 | 107, 107, 107, 107, 108, 108, 108, 108, 219 | 108, 108, 108, 109, 109, 109, 109, 109, 220 | 109, 109, 110, 110, 110, 110, 110, 110, 221 | 110, 111, 111, 111, 111, 111, 111, 111, 222 | 112, 112, 112, 112, 112, 112, 112, 113, 223 | 113, 113, 113, 113, 113, 113, 114, 114, 224 | 114, 114, 114, 114, 114, 115, 115, 115, 225 | 115, 115, 115, 115, 116, 116, 116, 116, 226 | 116, 116, 116, 117, 117, 117, 117, 117, 227 | 117, 117, 118, 118, 118, 118, 118, 118, 228 | 118, 119, 119, 119, 119, 119, 119, 119, 229 | 120, 120, 120, 120, 120, 120, 120, 121, 230 | 121, 121, 121, 121, 121, 121, 122, 122, 231 | 122, 122, 122, 122, 122, 123, 123, 123, 232 | 123, 123, 123, 123, 124, 124, 124, 124, 233 | 124, 124, 124, 125, 125, 125, 125, 125, 234 | 125, 125, 126, 126, 126, 126, 126, 126, 235 | 126, 127, 127, 127, 127, 127, 127, 127, 236 | 128, 128, 128, 128, 128, 128, 128, 129, 237 | 129, 129, 129, 129, 129, 129, 130, 130, 238 | 130, 130, 130, 130, 130, 131, 131, 131, 239 | 131, 131, 131, 131, 132, 132, 132, 132, 240 | 132, 132, 132, 133, 133, 133, 133, 133, 241 | 133, 133, 134, 134, 134, 134, 134, 134, 242 | 134, 135, 135, 135, 135, 135, 135, 135, 243 | 136, 136, 136, 136, 136, 136, 136, 137, 244 | 137, 137, 137, 137, 137, 137, 138, 138, 245 | 138, 138, 138, 138, 138, 139, 139, 139, 246 | 139, 139, 139, 139, 140, 140, 140, 140, 247 | 140, 140, 140, 141, 141, 141, 141, 141, 248 | 141, 141, 142, 142, 142, 142, 142, 142, 249 | 142, 143, 143, 143, 143, 143, 143, 143, 250 | 144, 144, 144, 144, 144, 144, 144, 145, 251 | 145, 145, 145, 145, 145, 145, 146, 146, 252 | 146, 146, 146, 146, 146, 147, 147, 147, 253 | 147, 147, 147, 147, 148, 148, 148, 148, 254 | 148, 148, 148, 149, 149, 149, 149, 149, 255 | 149, 149, 150, 150, 150, 150, 150, 150, 256 | 150, 151, 151, 151, 151, 151, 151, 151, 257 | 152, 152, 152, 152, 152, 152, 152, 153, 258 | 153, 153, 153, 153, 153, 153, 154, 154, 259 | 154, 154, 154, 154, 154, 155, 155, 155, 260 | 155, 155, 155, 155, 156, 156, 156, 156, 261 | 156, 156, 156, 157, 157, 157, 157, 157, 262 | 157, 157, 158, 158, 158, 158, 158, 158, 263 | 158, 159, 159, 159, 159, 159, 159, 159, 264 | 160, 160, 160, 160, 160, 160, 160, 161, 265 | 161, 161, 161, 161, 161, 161, 162, 162, 266 | 162, 162, 162, 162, 162, 163, 163, 163, 267 | 163, 163, 163, 163, 164, 164, 164, 164, 268 | 164, 164, 164, 165, 165, 165, 165, 165, 269 | 165, 165, 166, 166, 166, 166, 166, 166, 270 | 166, 167, 167, 167, 167, 167, 167, 167, 271 | 168, 168, 168, 168, 168, 168, 168, 169, 272 | 169, 169, 169, 169, 169, 169, 170, 170, 273 | 170, 170, 170, 170, 170, 171, 171, 171, 274 | 171, 171, 171, 171, 172, 172, 172, 172, 275 | 172, 172, 172, 173, 173, 173, 173, 173, 276 | 173, 173, 174, 174, 174, 174, 174, 174, 277 | 174, 175, 175, 175, 175, 175, 175, 175, 278 | 176, 176, 176, 176, 176, 176, 176, 177, 279 | 177, 177, 177, 177, 177, 177, 178, 178, 280 | 178, 178, 178, 178, 178, 179, 179, 179, 281 | 179, 179, 179, 179, 180, 180, 180, 180, 282 | 180, 180, 180, 181, 181, 181, 181, 181, 283 | 181, 181, 182, 182, 182, 182, 182, 182, 284 | 182, 183, 183, 183, 183, 183, 183, 183, 285 | 184, 184, 184, 184, 184, 184, 184, 185, 286 | 185, 185, 185, 185, 185, 185, 186, 186, 287 | 186, 186, 186, 186, 186, 187, 187, 187, 288 | 187, 187, 187, 187, 188, 188, 188, 188, 289 | 188, 188, 188, 189, 189, 189, 189, 189, 290 | 189, 189, 190, 190, 190, 190, 190, 190, 291 | 190, 191, 191, 191, 191, 191, 191, 191, 292 | 192, 192, 192, 192, 192, 192, 192, 193, 293 | 193, 193, 193, 193, 193, 193, 194, 194, 294 | 194, 194, 194, 194, 194, 195, 195, 195, 295 | 195, 195, 195, 195, 196, 196, 196, 196, 296 | 196, 196, 196, 197, 197, 197, 197, 197, 297 | 197, 197, 198, 198, 198, 198, 198, 198, 298 | 198, 199, 199, 199, 199, 199, 199, 199, 299 | 200, 200, 200, 200, 200, 200, 200, 201, 300 | 201, 201, 201, 201, 201, 201, 202, 202, 301 | 202, 202, 202, 202, 202, 203, 203, 203, 302 | 203, 203, 203, 203, 204, 204, 204, 204, 303 | 204, 204, 204, 205, 205, 205, 205, 205, 304 | 205, 205, 206, 206, 206, 206, 206, 206, 305 | 206, 207, 207, 207, 207, 207, 207, 207, 306 | 208, 208, 208, 208, 208, 208, 208, 209, 307 | 209, 209, 209, 209, 209, 209, 210, 210, 308 | 210, 210, 210, 210, 210, 211, 211, 211, 309 | 211, 211, 211, 211, 212, 212, 212, 212, 310 | 212, 212, 212, 213, 213, 213, 213, 213, 311 | 213, 213, 214, 214, 214, 214, 214, 214, 312 | 214, 215, 215, 215, 215, 215, 215, 215, 313 | 216, 216, 216, 216, 216, 216, 216, 217, 314 | 217, 217, 217, 217, 217, 217, 218, 218, 315 | 218, 218, 218, 218, 218, 219, 219, 219, 316 | 219, 219, 219, 219, 220, 220, 220, 220, 317 | 220, 220, 220, 221, 221, 221, 221, 221, 318 | 221, 221, 222, 222, 222, 222, 222, 222, 319 | 222, 223, 223, 223, 223, 223, 223, 223, 320 | 224, 224, 224, 224, 224, 224, 224, 225, 321 | 225, 225, 225, 225, 225, 225, 226, 226, 322 | 226, 226, 226, 226, 226, 227, 227, 227, 323 | 227, 227, 227, 227, 228, 228, 228, 228, 324 | 228, 228, 228, 229, 229, 229, 229, 229, 325 | 229, 229, 230, 230, 230, 230, 230, 230, 326 | 230, 231, 231, 231, 231, 231, 231, 231, 327 | 232, 232, 232, 232, 232, 232, 232, 233, 328 | 233, 233, 233, 233, 233, 233, 234, 234, 329 | 234, 234, 234, 234, 234, 235, 235, 235, 330 | 235, 235, 235, 235, 236, 236, 236, 236, 331 | 236, 236, 236, 237, 237, 237, 237, 237, 332 | 237, 237, 238, 238, 238, 238, 238, 238, 333 | 238, 239, 239, 239, 239, 239, 239, 239, 334 | 240, 240, 240, 240, 240, 240, 240, 241, 335 | 241, 241, 241, 241, 241, 241, 242, 242, 336 | 242, 242, 242, 242, 242, 243, 243, 243, 337 | 243, 243, 243, 243, 244, 244, 244, 244, 338 | 244, 244, 244, 245, 245, 245, 245, 245, 339 | 245, 245, 246, 246, 246, 246, 246, 246, 340 | 246, 247, 247, 247, 247, 247, 247, 247, 341 | 248, 248, 248, 248, 248, 248, 248, 249, 342 | 249, 249, 249, 249, 249, 249, 250, 250, 343 | 250, 250, 250, 250, 250, 251, 251, 251, 344 | 251, 251, 251, 251, 252, 252, 252, 252, 345 | 252, 252, 252, 253, 253, 253, 253, 253, 346 | 253, 253, 254, 254, 254, 254, 254, 254, 347 | 254, 255, 255, 255, 255, 255, 255, 255, 348 | }; 349 | 350 | const uint8_t detex_division_by_5_table[1280] = { 351 | 0, 0, 0, 0, 0, 1, 1, 1, 352 | 1, 1, 2, 2, 2, 2, 2, 3, 353 | 3, 3, 3, 3, 4, 4, 4, 4, 354 | 4, 5, 5, 5, 5, 5, 6, 6, 355 | 6, 6, 6, 7, 7, 7, 7, 7, 356 | 8, 8, 8, 8, 8, 9, 9, 9, 357 | 9, 9, 10, 10, 10, 10, 10, 11, 358 | 11, 11, 11, 11, 12, 12, 12, 12, 359 | 12, 13, 13, 13, 13, 13, 14, 14, 360 | 14, 14, 14, 15, 15, 15, 15, 15, 361 | 16, 16, 16, 16, 16, 17, 17, 17, 362 | 17, 17, 18, 18, 18, 18, 18, 19, 363 | 19, 19, 19, 19, 20, 20, 20, 20, 364 | 20, 21, 21, 21, 21, 21, 22, 22, 365 | 22, 22, 22, 23, 23, 23, 23, 23, 366 | 24, 24, 24, 24, 24, 25, 25, 25, 367 | 25, 25, 26, 26, 26, 26, 26, 27, 368 | 27, 27, 27, 27, 28, 28, 28, 28, 369 | 28, 29, 29, 29, 29, 29, 30, 30, 370 | 30, 30, 30, 31, 31, 31, 31, 31, 371 | 32, 32, 32, 32, 32, 33, 33, 33, 372 | 33, 33, 34, 34, 34, 34, 34, 35, 373 | 35, 35, 35, 35, 36, 36, 36, 36, 374 | 36, 37, 37, 37, 37, 37, 38, 38, 375 | 38, 38, 38, 39, 39, 39, 39, 39, 376 | 40, 40, 40, 40, 40, 41, 41, 41, 377 | 41, 41, 42, 42, 42, 42, 42, 43, 378 | 43, 43, 43, 43, 44, 44, 44, 44, 379 | 44, 45, 45, 45, 45, 45, 46, 46, 380 | 46, 46, 46, 47, 47, 47, 47, 47, 381 | 48, 48, 48, 48, 48, 49, 49, 49, 382 | 49, 49, 50, 50, 50, 50, 50, 51, 383 | 51, 51, 51, 51, 52, 52, 52, 52, 384 | 52, 53, 53, 53, 53, 53, 54, 54, 385 | 54, 54, 54, 55, 55, 55, 55, 55, 386 | 56, 56, 56, 56, 56, 57, 57, 57, 387 | 57, 57, 58, 58, 58, 58, 58, 59, 388 | 59, 59, 59, 59, 60, 60, 60, 60, 389 | 60, 61, 61, 61, 61, 61, 62, 62, 390 | 62, 62, 62, 63, 63, 63, 63, 63, 391 | 64, 64, 64, 64, 64, 65, 65, 65, 392 | 65, 65, 66, 66, 66, 66, 66, 67, 393 | 67, 67, 67, 67, 68, 68, 68, 68, 394 | 68, 69, 69, 69, 69, 69, 70, 70, 395 | 70, 70, 70, 71, 71, 71, 71, 71, 396 | 72, 72, 72, 72, 72, 73, 73, 73, 397 | 73, 73, 74, 74, 74, 74, 74, 75, 398 | 75, 75, 75, 75, 76, 76, 76, 76, 399 | 76, 77, 77, 77, 77, 77, 78, 78, 400 | 78, 78, 78, 79, 79, 79, 79, 79, 401 | 80, 80, 80, 80, 80, 81, 81, 81, 402 | 81, 81, 82, 82, 82, 82, 82, 83, 403 | 83, 83, 83, 83, 84, 84, 84, 84, 404 | 84, 85, 85, 85, 85, 85, 86, 86, 405 | 86, 86, 86, 87, 87, 87, 87, 87, 406 | 88, 88, 88, 88, 88, 89, 89, 89, 407 | 89, 89, 90, 90, 90, 90, 90, 91, 408 | 91, 91, 91, 91, 92, 92, 92, 92, 409 | 92, 93, 93, 93, 93, 93, 94, 94, 410 | 94, 94, 94, 95, 95, 95, 95, 95, 411 | 96, 96, 96, 96, 96, 97, 97, 97, 412 | 97, 97, 98, 98, 98, 98, 98, 99, 413 | 99, 99, 99, 99, 100, 100, 100, 100, 414 | 100, 101, 101, 101, 101, 101, 102, 102, 415 | 102, 102, 102, 103, 103, 103, 103, 103, 416 | 104, 104, 104, 104, 104, 105, 105, 105, 417 | 105, 105, 106, 106, 106, 106, 106, 107, 418 | 107, 107, 107, 107, 108, 108, 108, 108, 419 | 108, 109, 109, 109, 109, 109, 110, 110, 420 | 110, 110, 110, 111, 111, 111, 111, 111, 421 | 112, 112, 112, 112, 112, 113, 113, 113, 422 | 113, 113, 114, 114, 114, 114, 114, 115, 423 | 115, 115, 115, 115, 116, 116, 116, 116, 424 | 116, 117, 117, 117, 117, 117, 118, 118, 425 | 118, 118, 118, 119, 119, 119, 119, 119, 426 | 120, 120, 120, 120, 120, 121, 121, 121, 427 | 121, 121, 122, 122, 122, 122, 122, 123, 428 | 123, 123, 123, 123, 124, 124, 124, 124, 429 | 124, 125, 125, 125, 125, 125, 126, 126, 430 | 126, 126, 126, 127, 127, 127, 127, 127, 431 | 128, 128, 128, 128, 128, 129, 129, 129, 432 | 129, 129, 130, 130, 130, 130, 130, 131, 433 | 131, 131, 131, 131, 132, 132, 132, 132, 434 | 132, 133, 133, 133, 133, 133, 134, 134, 435 | 134, 134, 134, 135, 135, 135, 135, 135, 436 | 136, 136, 136, 136, 136, 137, 137, 137, 437 | 137, 137, 138, 138, 138, 138, 138, 139, 438 | 139, 139, 139, 139, 140, 140, 140, 140, 439 | 140, 141, 141, 141, 141, 141, 142, 142, 440 | 142, 142, 142, 143, 143, 143, 143, 143, 441 | 144, 144, 144, 144, 144, 145, 145, 145, 442 | 145, 145, 146, 146, 146, 146, 146, 147, 443 | 147, 147, 147, 147, 148, 148, 148, 148, 444 | 148, 149, 149, 149, 149, 149, 150, 150, 445 | 150, 150, 150, 151, 151, 151, 151, 151, 446 | 152, 152, 152, 152, 152, 153, 153, 153, 447 | 153, 153, 154, 154, 154, 154, 154, 155, 448 | 155, 155, 155, 155, 156, 156, 156, 156, 449 | 156, 157, 157, 157, 157, 157, 158, 158, 450 | 158, 158, 158, 159, 159, 159, 159, 159, 451 | 160, 160, 160, 160, 160, 161, 161, 161, 452 | 161, 161, 162, 162, 162, 162, 162, 163, 453 | 163, 163, 163, 163, 164, 164, 164, 164, 454 | 164, 165, 165, 165, 165, 165, 166, 166, 455 | 166, 166, 166, 167, 167, 167, 167, 167, 456 | 168, 168, 168, 168, 168, 169, 169, 169, 457 | 169, 169, 170, 170, 170, 170, 170, 171, 458 | 171, 171, 171, 171, 172, 172, 172, 172, 459 | 172, 173, 173, 173, 173, 173, 174, 174, 460 | 174, 174, 174, 175, 175, 175, 175, 175, 461 | 176, 176, 176, 176, 176, 177, 177, 177, 462 | 177, 177, 178, 178, 178, 178, 178, 179, 463 | 179, 179, 179, 179, 180, 180, 180, 180, 464 | 180, 181, 181, 181, 181, 181, 182, 182, 465 | 182, 182, 182, 183, 183, 183, 183, 183, 466 | 184, 184, 184, 184, 184, 185, 185, 185, 467 | 185, 185, 186, 186, 186, 186, 186, 187, 468 | 187, 187, 187, 187, 188, 188, 188, 188, 469 | 188, 189, 189, 189, 189, 189, 190, 190, 470 | 190, 190, 190, 191, 191, 191, 191, 191, 471 | 192, 192, 192, 192, 192, 193, 193, 193, 472 | 193, 193, 194, 194, 194, 194, 194, 195, 473 | 195, 195, 195, 195, 196, 196, 196, 196, 474 | 196, 197, 197, 197, 197, 197, 198, 198, 475 | 198, 198, 198, 199, 199, 199, 199, 199, 476 | 200, 200, 200, 200, 200, 201, 201, 201, 477 | 201, 201, 202, 202, 202, 202, 202, 203, 478 | 203, 203, 203, 203, 204, 204, 204, 204, 479 | 204, 205, 205, 205, 205, 205, 206, 206, 480 | 206, 206, 206, 207, 207, 207, 207, 207, 481 | 208, 208, 208, 208, 208, 209, 209, 209, 482 | 209, 209, 210, 210, 210, 210, 210, 211, 483 | 211, 211, 211, 211, 212, 212, 212, 212, 484 | 212, 213, 213, 213, 213, 213, 214, 214, 485 | 214, 214, 214, 215, 215, 215, 215, 215, 486 | 216, 216, 216, 216, 216, 217, 217, 217, 487 | 217, 217, 218, 218, 218, 218, 218, 219, 488 | 219, 219, 219, 219, 220, 220, 220, 220, 489 | 220, 221, 221, 221, 221, 221, 222, 222, 490 | 222, 222, 222, 223, 223, 223, 223, 223, 491 | 224, 224, 224, 224, 224, 225, 225, 225, 492 | 225, 225, 226, 226, 226, 226, 226, 227, 493 | 227, 227, 227, 227, 228, 228, 228, 228, 494 | 228, 229, 229, 229, 229, 229, 230, 230, 495 | 230, 230, 230, 231, 231, 231, 231, 231, 496 | 232, 232, 232, 232, 232, 233, 233, 233, 497 | 233, 233, 234, 234, 234, 234, 234, 235, 498 | 235, 235, 235, 235, 236, 236, 236, 236, 499 | 236, 237, 237, 237, 237, 237, 238, 238, 500 | 238, 238, 238, 239, 239, 239, 239, 239, 501 | 240, 240, 240, 240, 240, 241, 241, 241, 502 | 241, 241, 242, 242, 242, 242, 242, 243, 503 | 243, 243, 243, 243, 244, 244, 244, 244, 504 | 244, 245, 245, 245, 245, 245, 246, 246, 505 | 246, 246, 246, 247, 247, 247, 247, 247, 506 | 248, 248, 248, 248, 248, 249, 249, 249, 507 | 249, 249, 250, 250, 250, 250, 250, 251, 508 | 251, 251, 251, 251, 252, 252, 252, 252, 509 | 252, 253, 253, 253, 253, 253, 254, 254, 510 | 254, 254, 254, 255, 255, 255, 255, 255, 511 | }; 512 | 513 | -------------------------------------------------------------------------------- /External/Detex/file-info.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #ifndef _MSC_VER 23 | #include 24 | #endif 25 | 26 | #include "detex.h" 27 | #include "file-info.h" 28 | #include "misc.h" 29 | 30 | /* 31 | The TextureInfo structure has the following fields: 32 | 33 | int type; // The texture type. Various properties of the texture type can be derived from bits in the texture type. 34 | int ktx_support; // Whether the program supports loading/saving this format in ktx files. 35 | int dds_support; // Whether the program supports loading/saving this format in dds files. 36 | const char *text1; // A short text identifier, also used with the --format option. 37 | const char *text2; // An alternative identifier. 38 | int block_width; // The block width (1 for uncompressed textures). 39 | int block_height; // The block height (1 for uncompressed textures). 40 | int gl_internal_format; // The OpenGL glInternalFormat identifier for this texture type. 41 | int gl_format; // The matching glFormat. 42 | int gl_type; // The matching glType. 43 | const char *dx_four_cc; // The DDS file four character code matching this texture type. If "DX10", dx10_format is valid. 44 | int dx10_format; // The DX10 format identifier matching this texture type. 45 | 46 | There is also a synonym table for KTX and DDS file formats with alternative IDs. When loading a texture file 47 | the synonyms will be recognized and treated as the corresponding texture type in the primary table. When 48 | saving a file the format used will be that of the primary table. 49 | */ 50 | 51 | static const detexTextureFileInfo texture_info[] = { 52 | // Texture format KTX/DDS Textual representations Block 53 | // support size OpenGL ID in KTX files DDS file IDs 54 | // internalFormat, format, type FourCC, DX10 format 55 | // Uncompressed formats (texture format = pixel format). 56 | { DETEX_PIXEL_FORMAT_RGB8, 1, 1, "RGB8", "", 1, 1, 0x1907, 0x1907, 0x1401, "", 0 }, 57 | { DETEX_PIXEL_FORMAT_RGBA8, 1, 1, "RGBA8", "", 1, 1, 0x1908, 0x1908, 0x1401, "DX10", 28 }, 58 | { DETEX_PIXEL_FORMAT_R8, 1, 1, "R8", "", 1, 1, 0x8229, 0x1903, 0x1401, "DX10", 61 }, 59 | { DETEX_PIXEL_FORMAT_SIGNED_R8, 1, 1, "SIGNED_R8", "", 1, 1, 0x8F49, 0x1903, 0x1400, "DX10", 63 }, 60 | { DETEX_PIXEL_FORMAT_RG8, 1, 1, "RG8", "", 1, 1, 0x822B, 0x8227, 0x1401, "DX10", 49 }, 61 | { DETEX_PIXEL_FORMAT_SIGNED_RG8, 1, 1, "SIGNED_RG8", "", 1, 1, 0x8F95, 0x8227, 0x1400, "DX10", 51 }, 62 | { DETEX_PIXEL_FORMAT_R16, 1, 1, "R16", "", 1, 1, 0x822A, 0x1903, 0x1403, "DX10", 56 }, 63 | { DETEX_PIXEL_FORMAT_SIGNED_R16, 1, 1, "SIGNED_R16", "", 1, 1, 0x8F98, 0x1903, 0x1402, "DX10", 58 }, 64 | { DETEX_PIXEL_FORMAT_RG16, 1, 1, "RG16", "", 1, 1, 0x8226, 0x8227, 0x1403, "DX10", 35 }, 65 | { DETEX_PIXEL_FORMAT_SIGNED_RG16, 1, 1, "SIGNED_RG16", "", 1, 1, 0x8F99, 0x8227, 0x1402, "DX10", 37 }, 66 | { DETEX_PIXEL_FORMAT_RGB16, 1, 0, "RGB16", "", 1, 1, 0x8054, 0x1907, 0x1403, "", 0 }, 67 | { DETEX_PIXEL_FORMAT_RGBA16, 1, 1, "RGBA16", "", 1, 1, 0x805B, 0x8227, 0x1403, "DX10", 11 }, 68 | { DETEX_PIXEL_FORMAT_FLOAT_R16, 1, 1, "FLOAT_R16", "", 1, 1, 0x822D, 0x1903, 0x140B, "DX10", 54 }, 69 | { DETEX_PIXEL_FORMAT_FLOAT_RG16, 1, 1, "FLOAT_RG16", "", 1, 1, 0x822F, 0x8227, 0x140B, "DX10", 34 }, 70 | { DETEX_PIXEL_FORMAT_FLOAT_RGB16, 1, 0, "FLOAT_RGB16", "", 1, 1, 0x1907, 0x1907, 0x140B, "", 0 }, 71 | { DETEX_PIXEL_FORMAT_FLOAT_RGBA16, 1, 1, "FLOAT_RGBA16", "", 1, 1, 0x1908, 0x1908, 0x140B, "DX10", 10 }, 72 | { DETEX_PIXEL_FORMAT_FLOAT_R32, 1, 1, "FLOAT_R32", "", 1, 1, 0x822E, 0x1903, 0x1406, "DX10", 41 }, 73 | { DETEX_PIXEL_FORMAT_FLOAT_RG32, 1, 1, "FLOAT_RG32", "", 1, 1, 0x8230, 0x8227, 0x1406, "DX10", 16 }, 74 | { DETEX_PIXEL_FORMAT_FLOAT_RGB32, 1, 1, "FLOAT_RGB32", "", 1, 1, 0x8815, 0x1907, 0x1406, "DX10", 6 }, 75 | { DETEX_PIXEL_FORMAT_FLOAT_RGBA32, 1, 1, "FLOAT_RGBA32", "", 1, 1, 0x8814, 0x1908, 0x1406, "DX10", 2 }, 76 | { DETEX_PIXEL_FORMAT_A8, 1, 1, "A8", "", 1, 1, 0x1906, 0x1906, 0x1401, "DX10", 65 }, 77 | // Compressed formats. 78 | { DETEX_TEXTURE_FORMAT_BC1, 1, 1, "BC1", "DXT1", 4, 4, 0x83F0, 0, 0, "DXT1", 0 }, 79 | { DETEX_TEXTURE_FORMAT_BC1A, 1, 1, "BC1A", "DXT1A", 4, 4, 0x83F1, 0, 0, "", 0 }, 80 | { DETEX_TEXTURE_FORMAT_BC2, 1, 1, "BC2", "DXT3", 4, 4, 0x83F2, 0, 0, "DXT3", 0 }, 81 | { DETEX_TEXTURE_FORMAT_BC3, 1, 1, "BC3", "DXT5", 4, 4, 0x83F3, 0, 0, "DXT5", 0 }, 82 | { DETEX_TEXTURE_FORMAT_RGTC1, 1, 1, "RGTC1", "BC4_UNORM", 4, 4, 0x8DBB, 0, 0, "DX10", 80 }, 83 | { DETEX_TEXTURE_FORMAT_SIGNED_RGTC1, 1, 1, "SIGNED_RGTC1", "BC4_SNORM", 4, 4, 0x8DBC, 0, 0, "DX10", 81 }, 84 | { DETEX_TEXTURE_FORMAT_RGTC2, 1, 1, "RGTC2", "BC5_UNORM", 4, 4, 0x8DBD, 0, 0, "DX10", 83 }, 85 | { DETEX_TEXTURE_FORMAT_SIGNED_RGTC2, 1, 1, "SIGNED_RGTC2", "BC5_SNORM", 4, 4, 0x8DBE, 0, 0, "DX10", 84 }, 86 | { DETEX_TEXTURE_FORMAT_BPTC_FLOAT, 1, 1, "BPTC_FLOAT", "BC6H_UF16", 4, 4, 0x8E8F, 0, 0, "DX10", 95 }, 87 | { DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT, 1, 1, "BPTC_SIGNED_FLOAT", "BC6H_SF16", 4, 4, 0x8E8E, 0, 0, "DX10", 96 }, 88 | { DETEX_TEXTURE_FORMAT_BPTC, 1, 1, "BPTC", "BC7", 4, 4, 0x8E8C, 0, 0, "DX10", 98 }, 89 | { DETEX_TEXTURE_FORMAT_BPTC, 1, 1, "BPTC", "BC7", 4, 4, 0x8E8C, 0, 0, "DX10", 99 }, 90 | { DETEX_TEXTURE_FORMAT_ETC1, 1, 0, "ETC1", "", 4, 4, 0x8D64, 0, 0, "", 0 }, 91 | { DETEX_TEXTURE_FORMAT_ETC2, 1, 0, "ETC2", "ETC2_RGB8", 4, 4, 0x9274, 0, 0, "", 0 }, 92 | { DETEX_TEXTURE_FORMAT_ETC2_PUNCHTHROUGH, 1, 0, "ETC2_PUNCHTHROUGH", "", 4, 4, 0x9275, 0, 0, "", 0 }, 93 | { DETEX_TEXTURE_FORMAT_ETC2_EAC, 1, 0, "ETC2_EAC", "EAC", 4, 4, 0x9278, 0, 0, "", 0 }, 94 | { DETEX_TEXTURE_FORMAT_EAC_R11, 1, 0, "EAC_R11", "", 4, 4, 0x9270, 0, 0, "", 0 }, 95 | { DETEX_TEXTURE_FORMAT_EAC_SIGNED_R11, 1, 0, "EAC_SIGNED_R11", "", 4, 4, 0x9271, 0, 0, "", 0 }, 96 | { DETEX_TEXTURE_FORMAT_EAC_RG11, 1, 0, "EAC_RG11", "", 4, 4, 0x9272, 0, 0, "", 0 }, 97 | { DETEX_TEXTURE_FORMAT_EAC_SIGNED_RG11, 1, 0, "EAC_SIGNED_RG11", "", 4, 4, 0x9273, 0, 0, "", 0 }, 98 | // { DETEX_TEXTURE_FORMAT_ETC2_SRGB8, 1, 0, "SRGB_ETC2", "", 4, 4, 0x9275, 0, 0, "", 0 }, 99 | // { DETEX_TEXTURE_FORMAT_ETC2_SRGB_EAC, 1, 0, "SRGB_ETC2_EAC", "", 4, 4, 0x9279, 0, 0, "", 0 }, 100 | // { DETEX_TEXTURE_FORMAT_ETC2_SRGB_PUNCHTHROUGH, 1, 0, "SRGB_ETC2_PUNCHTHROUGH, "", 4, 4, 0x9277, 0, 0, "", 0 }, 101 | { DETEX_TEXTURE_FORMAT_ASTC_4X4, 1, 0, "ASTC_4x4", "", 4, 4, 0x93B0, 0, 0, "DX10", 134 }, 102 | #if 0 103 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_5X4, 1, 0, "astc_5x4", "", 5, 4, 0x93B1, 0, 0, "", 0 }, 104 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_5X5, 1, 0, "astc_5x5", "", 5, 5, 0x93B2, 0, 0, "", 0 }, 105 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_6X5, 1, 0, "astc_6x4", "", 6, 5, 0x93B3, 0, 0, "", 0 }, 106 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_6X6, 1, 0, "astc_6x6", "", 6, 6, 0x93B4, 0, 0, "", 0 }, 107 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_8X5, 1, 0, "astc_8x5", "", 8, 5, 0x93B5, 0, 0, "", 0 }, 108 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_8X6, 1, 0, "astc_8x6", "", 8, 6, 0x93B6, 0, 0, "", 0 }, 109 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_8X8, 1, 0, "astc_8x8", "", 8, 8, 0x93B7, 0, 0, "", 0 }, 110 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_10X5, 1, 0, "astc_10x5", "", 10, 5, 0x93B8, 0, 0, "", 0 }, 111 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_10X6, 1, 0, "astc_10x6", "", 10, 6, 0x93B9, 0, 0, "", 0 }, 112 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_10X8, 1, 0, "astc_10x8", "", 10, 8, 0x93BA, 0, 0, "", 0 }, 113 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_10X10, 1, 0, "astc_10x10", "", 10, 10, 0x93BB, 0, 0, "", 0 }, 114 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_12X10, 1, 0, "astc_12x10", "", 12, 10, 0x93BC, 0, 0, "", 0 }, 115 | { DETEX_TEXTURE_FORMAT_RGBA_ASTC_12X12, 1, 0, "astc_12x12", "", 12, 12, 0x93BD, 0, 0, "", 0 }, 116 | #endif 117 | // Pseudo-formats (not present in files, but used for name look-up). 118 | { DETEX_PIXEL_FORMAT_RGBX8, 0, 0, "RGBX8", "", 1, 1, 0, 0, 0, "", 0 }, 119 | { DETEX_PIXEL_FORMAT_BGRX8, 0, 0, "BGRX8", "", 1, 1, 0, 0, 0, "", 0 }, 120 | { DETEX_PIXEL_FORMAT_FLOAT_RGBX16, 0, 0, "FLOAT_RGBX16", "", 1, 1, 0, 0, 0, "", 0 }, 121 | { DETEX_PIXEL_FORMAT_FLOAT_BGRX16, 0, 0, "FLOAT_BGRX16", "", 1, 1, 0, 0, 0, "", 0 }, 122 | { DETEX_PIXEL_FORMAT_FLOAT_R16_HDR, 0, 0, "FLOAT_R16_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 123 | { DETEX_PIXEL_FORMAT_FLOAT_RG16_HDR, 0, 0, "FLOAT_RG16_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 124 | { DETEX_PIXEL_FORMAT_FLOAT_RGB16_HDR, 0, 0, "FLOAT_RGB16_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 125 | { DETEX_PIXEL_FORMAT_FLOAT_RGBA16_HDR, 0, 0, "FLOAT_RGBA16_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 126 | { DETEX_PIXEL_FORMAT_FLOAT_R32_HDR, 0, 0, "FLOAT_R32_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 127 | { DETEX_PIXEL_FORMAT_FLOAT_RG32_HDR, 0, 0, "FLOAT_RG32_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 128 | { DETEX_PIXEL_FORMAT_FLOAT_RGB32_HDR, 0, 0, "FLOAT_RGB32_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 129 | { DETEX_PIXEL_FORMAT_FLOAT_RGBA32_HDR, 0, 0, "FLOAT_RGBA32_HDR", "", 1, 1, 0, 0, 0, "", 0 }, 130 | }; 131 | 132 | #define DETEX_NU_TEXTURE_INFO_ENTRIES (sizeof(texture_info) / sizeof(texture_info[0])) 133 | 134 | typedef struct { 135 | int texture_format; 136 | int gl_internal_format; 137 | int gl_format; 138 | int gl_type; 139 | } OpenGLTextureFormatSynonym; 140 | 141 | 142 | static OpenGLTextureFormatSynonym open_gl_synonym[] = { 143 | { DETEX_PIXEL_FORMAT_RGB8, 0x8051, 0x1907, 0x1401 }, // GL_RGB8 144 | { DETEX_PIXEL_FORMAT_RGBA8, 0x8058, 0x1908, 0x1401 }, // GL_RGBA8 145 | { DETEX_PIXEL_FORMAT_FLOAT_RGB16, 0x881B, 0x1907, 0x140B }, // GL_RGB16F 146 | { DETEX_PIXEL_FORMAT_FLOAT_RGBA16, 0x881A, 0x1908, 0x140B }, // GL_RGAB16F 147 | { DETEX_PIXEL_FORMAT_A8, 0x803C, 0x1906, 0x1401 }, // GL_ALPHA8 148 | { DETEX_TEXTURE_FORMAT_RGTC1, 0x8C70, 0, 0 }, // LATC1 149 | { DETEX_TEXTURE_FORMAT_SIGNED_RGTC1, 0x8C71, 0, 0 }, // SIGNED_LATC1 150 | { DETEX_TEXTURE_FORMAT_RGTC2, 0x8C72, 0, 0 }, // LATC1 151 | { DETEX_TEXTURE_FORMAT_SIGNED_RGTC2, 0x8C73, 0, 0 }, // SIGNED_LATC1 152 | }; 153 | 154 | #define DETEX_NU_OPEN_GL_SYNONYMS (sizeof(open_gl_synonym) / sizeof(open_gl_synonym[0])) 155 | 156 | typedef struct { 157 | int texture_format; 158 | const char *dx10_four_cc; 159 | int dx10_format; 160 | } DDSTextureFormatSynonym; 161 | 162 | #define NU_DDS_SYNONYMS 22 163 | 164 | static const DDSTextureFormatSynonym dds_synonym[] = { 165 | { DETEX_PIXEL_FORMAT_RGBA8, "DX10", 27 }, 166 | { DETEX_PIXEL_FORMAT_RGBA8, "DX10", 30 }, 167 | { DETEX_PIXEL_FORMAT_RG16, "DX10", 36 }, 168 | { DETEX_PIXEL_FORMAT_R16, "DX10", 57 }, 169 | { DETEX_PIXEL_FORMAT_SIGNED_RG16, "DX10", 38 }, 170 | { DETEX_PIXEL_FORMAT_SIGNED_R16, "DX10", 59 }, 171 | { DETEX_PIXEL_FORMAT_RG8, "DX10", 50 }, 172 | { DETEX_PIXEL_FORMAT_R8, "DX10", 62 }, 173 | { DETEX_PIXEL_FORMAT_SIGNED_RG8, "DX10", 52 }, 174 | { DETEX_PIXEL_FORMAT_SIGNED_R8, "DX10", 64 }, 175 | { DETEX_PIXEL_FORMAT_RGBA16, "DX10", 12 }, 176 | { DETEX_TEXTURE_FORMAT_BC1, "DX10", 70 }, 177 | { DETEX_TEXTURE_FORMAT_BC1, "DX10", 71 }, 178 | { DETEX_TEXTURE_FORMAT_BC2, "DX10", 73 }, 179 | { DETEX_TEXTURE_FORMAT_BC2, "DX10", 74 }, 180 | { DETEX_TEXTURE_FORMAT_BC3, "DX10", 76 }, 181 | { DETEX_TEXTURE_FORMAT_BC3, "DX10", 77 }, 182 | { DETEX_TEXTURE_FORMAT_RGTC1, "DX10", 79 }, 183 | { DETEX_TEXTURE_FORMAT_RGTC1, "BC4U", 0 }, 184 | { DETEX_TEXTURE_FORMAT_SIGNED_RGTC1, "BC4S", 0 }, 185 | { DETEX_TEXTURE_FORMAT_RGTC2, "DX10", 82 }, 186 | { DETEX_TEXTURE_FORMAT_SIGNED_RGTC2, "BC5S", 0 }, 187 | { DETEX_TEXTURE_FORMAT_BPTC, "DX10", 97 }, 188 | { DETEX_TEXTURE_FORMAT_BPTC_FLOAT, "DX10", 94 }, 189 | { DETEX_TEXTURE_FORMAT_RGTC1, "ATI1", 0 }, 190 | { DETEX_TEXTURE_FORMAT_RGTC2, "ATI2", 0 } 191 | }; 192 | 193 | #define DETEX_NU_DDS_SYNONYMS (sizeof(dds_synonym) / sizeof(dds_synonym[0])) 194 | 195 | // Look-up texture file info for texture format. 196 | const detexTextureFileInfo *detexLookupTextureFormatFileInfo(uint32_t texture_format) { 197 | for (int i = 0; i < DETEX_NU_TEXTURE_INFO_ENTRIES; i++) 198 | if (texture_info[i].texture_format == texture_format) 199 | return &texture_info[i]; 200 | return NULL; 201 | } 202 | 203 | // Look-up texture file info for texture description. 204 | const detexTextureFileInfo *detexLookupTextureDescription(const char *s) { 205 | for (int i = 0; i < DETEX_NU_TEXTURE_INFO_ENTRIES; i++) 206 | if (strcasecmp(texture_info[i].text1, s) == 0 || strcasecmp(texture_info[i].text2, s) == 0) 207 | return &texture_info[i]; 208 | return NULL; 209 | } 210 | 211 | // Look-up texture file info for KTX file format based on GL format parameters. 212 | const detexTextureFileInfo *detexLookupKTXFileInfo(int gl_internal_format, int gl_format, int gl_type) { 213 | for (int i = 0; i < DETEX_NU_TEXTURE_INFO_ENTRIES; i++) 214 | if (texture_info[i].gl_internal_format != 0 && texture_info[i].gl_internal_format == gl_internal_format) { 215 | if (texture_info[i].gl_format == 0) 216 | return &texture_info[i]; 217 | if (texture_info[i].gl_format == gl_format && texture_info[i].gl_type == gl_type) 218 | return &texture_info[i]; 219 | } 220 | for (int i = 0; i < DETEX_NU_OPEN_GL_SYNONYMS; i++) 221 | if (open_gl_synonym[i].gl_internal_format == gl_internal_format) { 222 | if (open_gl_synonym[i].gl_format == 0) 223 | return detexLookupTextureFormatFileInfo(open_gl_synonym[i].texture_format); 224 | if (open_gl_synonym[i].gl_format == gl_format && open_gl_synonym[i].gl_type == gl_type) 225 | return detexLookupTextureFormatFileInfo(open_gl_synonym[i].texture_format); 226 | } 227 | return NULL; 228 | } 229 | 230 | enum { 231 | DDPF_ALPHAPIXELS = 0x1, 232 | DDPF_ALPHA = 0x2, 233 | DDPF_RGB = 0x40, 234 | }; 235 | 236 | // Look-up texture file info for DDS file format based on DX format parameters. 237 | const detexTextureFileInfo *detexLookupDDSFileInfo(const char *four_cc, int dx10_format, 238 | uint32_t pixel_format_flags, int bitcount, uint32_t red_mask, uint32_t green_mask, 239 | uint32_t blue_mask, uint32_t alpha_mask) { 240 | for (int i = 0; i < DETEX_NU_TEXTURE_INFO_ENTRIES; i++) 241 | if (strncmp(four_cc, "DX10", 4) == 0) { 242 | if (texture_info[i].dx10_format == dx10_format) 243 | return &texture_info[i]; 244 | } 245 | else 246 | if (texture_info[i].dx_four_cc[0] != '\0' && 247 | strncmp(texture_info[i].dx_four_cc, four_cc, 4) == 0) 248 | return &texture_info[i]; 249 | else { 250 | uint32_t format = texture_info[i].texture_format; 251 | if ((pixel_format_flags & DDPF_RGB) && 252 | !detexFormatIsCompressed(format)) { 253 | // Uncompressed format. Match component masks. 254 | if (bitcount <= 32) { 255 | int format_bitcount = detexGetPixelSize(format) * 8; 256 | uint64_t format_red_mask, format_green_mask, format_blue_mask, 257 | format_alpha_mask; 258 | detexGetComponentMasks(format, &format_red_mask, &format_green_mask, 259 | &format_blue_mask, &format_alpha_mask); 260 | if (format_bitcount == bitcount && 261 | format_red_mask == red_mask && 262 | format_green_mask == green_mask && 263 | format_blue_mask == blue_mask && 264 | ((pixel_format_flags & DDPF_ALPHAPIXELS) == 0 || 265 | format_alpha_mask == alpha_mask)) 266 | return &texture_info[i]; 267 | } 268 | } 269 | // Detect old alpha format. 270 | if ((pixel_format_flags & DDPF_ALPHA) && bitcount == 8 && 271 | format == DETEX_PIXEL_FORMAT_A8) 272 | return &texture_info[i]; 273 | } 274 | for (int i = 0; i < DETEX_NU_DDS_SYNONYMS; i++) 275 | if (strncmp(four_cc, "DX10", 4) == 0) { 276 | if (dds_synonym[i].dx10_format == dx10_format) 277 | return detexLookupTextureFormatFileInfo(dds_synonym[i].texture_format); 278 | } 279 | else if (dds_synonym[i].dx10_four_cc[0] != '\0' && 280 | strncmp(dds_synonym[i].dx10_four_cc, four_cc, 4) == 0) 281 | return detexLookupTextureFormatFileInfo(dds_synonym[i].texture_format); 282 | return NULL; 283 | } 284 | 285 | // Return a description of the texture format. 286 | const char *detexGetTextureFormatText(uint32_t texture_format) { 287 | const detexTextureFileInfo *info; 288 | info = detexLookupTextureFormatFileInfo(texture_format); 289 | if (info == NULL) { 290 | // printf("Error -- invalid texture format.\n"); 291 | return "Invalid"; 292 | } 293 | return info->text1; 294 | } 295 | 296 | // Return alternative description of the texture format. 297 | const char *detexGetAlternativeTextureFormatText(uint32_t texture_format) { 298 | const detexTextureFileInfo *info; 299 | info = detexLookupTextureFormatFileInfo(texture_format); 300 | if (info == NULL) { 301 | return "Invalid"; 302 | } 303 | return info->text2; 304 | } 305 | 306 | /* Return OpenGL Texture2D/KTX file parameters for a texture format. */ 307 | bool detexGetOpenGLParameters(uint32_t texture_format, int *gl_internal_format, 308 | uint32_t *gl_format, uint32_t *gl_type) { 309 | const detexTextureFileInfo *info = detexLookupTextureFormatFileInfo(texture_format); 310 | if (info == NULL) { 311 | detexSetErrorMessage("detexGetOpenGLParameters: Invalid texture format"); 312 | return false; 313 | } 314 | *gl_internal_format = info->gl_internal_format; 315 | *gl_format = info->gl_format; 316 | *gl_type = info->gl_type; 317 | return true; 318 | } 319 | 320 | /* Return DirectX 10 format for a texture format. */ 321 | bool detexGetDX10Parameters(uint32_t texture_format, uint32_t *dx10_format) { 322 | const detexTextureFileInfo *info = detexLookupTextureFormatFileInfo(texture_format); 323 | if (info == NULL) { 324 | detexSetErrorMessage("detexGetDX10Parameters: Invalid texture format"); 325 | return false; 326 | } 327 | if (strncmp(info->dx_four_cc, "DX10", 4) != 0) { 328 | detexSetErrorMessage("detexGetDX10Parameters: No DX10 format for texture format"); 329 | return false; 330 | } 331 | *dx10_format = info->dx10_format; 332 | return true; 333 | } 334 | 335 | -------------------------------------------------------------------------------- /External/Detex/file-info.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | typedef struct { 20 | uint32_t texture_format; 21 | int ktx_support; 22 | int dds_support; 23 | const char *text1; 24 | const char *text2; 25 | int block_width; // The block width (1 for uncompressed textures). 26 | int block_height; // The block height (1 for uncompressed textures). 27 | int gl_internal_format; 28 | uint32_t gl_format; 29 | uint32_t gl_type; 30 | const char *dx_four_cc; 31 | int dx10_format; 32 | } detexTextureFileInfo; 33 | 34 | // Look-up texture file info for texture format. 35 | const detexTextureFileInfo *detexLookupTextureFormatFileInfo(uint32_t texture_format); 36 | 37 | // Look-up texture file info for texture description. 38 | const detexTextureFileInfo *detexLookupTextureDescription(const char *s); 39 | 40 | // Look-up texture file info for KTX file format based on GL format parameters. 41 | const detexTextureFileInfo *detexLookupKTXFileInfo(int gl_internal_format, int gl_format, int gl_type); 42 | 43 | // Look-up texture file info for DDS file format based on DX format parameters. 44 | const detexTextureFileInfo *detexLookupDDSFileInfo(const char *four_cc, int dx10_format, uint32_t pixel_format_flags, int bitcount, uint32_t red_mask, uint32_t green_mask, uint32_t blue_mask, uint32_t alpha_mask); 45 | 46 | -------------------------------------------------------------------------------- /External/Detex/half-float.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "detex.h" 25 | #include "half-float.h" 26 | 27 | /****************************************************************************** 28 | * 29 | * Filename: ieeehalfprecision.c 30 | * Programmer: James Tursa 31 | * Version: 1.0 32 | * Date: March 3, 2009 33 | * Copyright: (c) 2009 by James Tursa, All Rights Reserved 34 | * 35 | * This code uses the BSD License: 36 | * 37 | * Redistribution and use in source and binary forms, with or without 38 | * modification, are permitted provided that the following conditions are 39 | * met: 40 | * 41 | * * Redistributions of source code must retain the above copyright 42 | * notice, this list of conditions and the following disclaimer. 43 | * * Redistributions in binary form must reproduce the above copyright 44 | * notice, this list of conditions and the following disclaimer in 45 | * the documentation and/or other materials provided with the distribution 46 | * 47 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 48 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 51 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57 | * POSSIBILITY OF SUCH DAMAGE. 58 | * 59 | * This file contains C code to convert between IEEE double, single, and half 60 | * precision floating point formats. The intended use is for standalone C code 61 | * that does not rely on MATLAB mex.h. The bit pattern for the half precision 62 | * floating point format is stored in a 16-bit unsigned int variable. The half 63 | * precision bit pattern definition is: 64 | * 65 | * 1 bit sign bit 66 | * 5 bits exponent, biased by 15 67 | * 10 bits mantissa, hidden leading bit, normalized to 1.0 68 | * 69 | * Special floating point bit patterns recognized and supported: 70 | * 71 | * All exponent bits zero: 72 | * - If all mantissa bits are zero, then number is zero (possibly signed) 73 | * - Otherwise, number is a denormalized bit pattern 74 | * 75 | * All exponent bits set to 1: 76 | * - If all mantissa bits are zero, then number is +Infinity or -Infinity 77 | * - Otherwise, number is NaN (Not a Number) 78 | * 79 | * For the denormalized cases, note that 2^(-24) is the smallest number that can 80 | * be represented in half precision exactly. 2^(-25) will convert to 2^(-24) 81 | * because of the rounding algorithm used, and 2^(-26) is too small and underflows 82 | * to zero. 83 | * 84 | ********************************************************************************/ 85 | 86 | //----------------------------------------------------------------------------- 87 | // 88 | // Routine: singles2halfp 89 | // 90 | // Input: source = Address of 32-bit floating point data to convert 91 | // numel = Number of values at that address to convert 92 | // 93 | // Output: target = Address of 16-bit data to hold output (numel values) 94 | // return value = 0 if native floating point format is IEEE 95 | // = 1 if native floating point format is not IEEE 96 | // 97 | // Programmer: James Tursa 98 | // 99 | //----------------------------------------------------------------------------- 100 | 101 | static DETEX_INLINE_ONLY void singles2halfp(void * DETEX_RESTRICT target, 102 | void * DETEX_RESTRICT source, int numel) 103 | { 104 | uint16_t *hp = (uint16_t *) target; // Type pun output as an unsigned 16-bit int 105 | uint32_t *xp = (uint32_t *) source; // Type pun input as an unsigned 32-bit int 106 | uint16_t hs, he, hm; 107 | uint32_t x, xs, xe, xm; 108 | int hes; 109 | #if 0 110 | static int next; // Little Endian adjustment 111 | static int checkieee = 1; // Flag to check for IEEE754, Endian, and word size 112 | double one = 1.0; // Used for checking IEEE754 floating point format 113 | uint32_t *ip; // Used for checking IEEE754 floating point format 114 | 115 | if( checkieee ) { // 1st call, so check for IEEE754, Endian, and word size 116 | ip = (uint32_t *) &one; 117 | if( *ip ) { // If Big Endian, then no adjustment 118 | next = 0; 119 | } else { // If Little Endian, then adjustment will be necessary 120 | next = 1; 121 | ip++; 122 | } 123 | if( *ip != 0x3FF00000u ) { // Check for exact IEEE 754 bit pattern of 1.0 124 | return 1; // Floating point bit pattern is not IEEE 754 125 | } 126 | if( sizeof(int16_t) != 2 || sizeof(int32_t) != 4 ) { 127 | return 1; // short is not 16-bits, or long is not 32-bits. 128 | } 129 | checkieee = 0; // Everything checks out OK 130 | } 131 | 132 | if( source == NULL || target == NULL ) { // Nothing to convert (e.g., imag part of pure real) 133 | return 0; 134 | } 135 | #endif 136 | 137 | while( numel-- ) { 138 | x = *xp++; 139 | if( (x & 0x7FFFFFFFu) == 0 ) { // Signed zero 140 | *hp++ = (uint16_t) (x >> 16); // Return the signed zero 141 | } else { // Not zero 142 | xs = x & 0x80000000u; // Pick off sign bit 143 | xe = x & 0x7F800000u; // Pick off exponent bits 144 | xm = x & 0x007FFFFFu; // Pick off mantissa bits 145 | if( xe == 0 ) { // Denormal will underflow, return a signed zero 146 | *hp++ = (uint16_t) (xs >> 16); 147 | } else if( xe == 0x7F800000u ) { // Inf or NaN (all the exponent bits are set) 148 | if( xm == 0 ) { // If mantissa is zero ... 149 | *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf 150 | } else { 151 | *hp++ = (uint16_t) 0xFE00u; // NaN, only 1st mantissa bit set 152 | } 153 | } else { // Normalized number 154 | hs = (uint16_t) (xs >> 16); // Sign bit 155 | hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp 156 | if( hes >= 0x1F ) { // Overflow 157 | *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf 158 | } else if( hes <= 0 ) { // Underflow 159 | if( (14 - hes) > 24 ) { // Mantissa shifted all the way off & no rounding possibility 160 | hm = (uint16_t) 0u; // Set mantissa to zero 161 | } else { 162 | xm |= 0x00800000u; // Add the hidden leading bit 163 | hm = (uint16_t) (xm >> (14 - hes)); // Mantissa 164 | if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding 165 | hm += (uint16_t) 1u; // Round, might overflow into exp bit, but this is OK 166 | } 167 | *hp++ = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero 168 | } else { 169 | he = (uint16_t) (hes << 10); // Exponent 170 | hm = (uint16_t) (xm >> 13); // Mantissa 171 | if( xm & 0x00001000u ) // Check for rounding 172 | *hp++ = (hs | he | hm) + (uint16_t) 1u; // Round, might overflow to inf, this is OK 173 | else 174 | *hp++ = (hs | he | hm); // No rounding 175 | } 176 | } 177 | } 178 | } 179 | } 180 | 181 | //----------------------------------------------------------------------------- 182 | // 183 | // Routine: halfp2singles 184 | // 185 | // Input: source = address of 16-bit data to convert 186 | // numel = Number of values at that address to convert 187 | // 188 | // Output: target = Address of 32-bit floating point data to hold output (numel values) 189 | // return value = 0 if native floating point format is IEEE 190 | // = 1 if native floating point format is not IEEE 191 | // 192 | // Programmer: James Tursa 193 | // 194 | //----------------------------------------------------------------------------- 195 | 196 | static DETEX_INLINE_ONLY void halfp2singles(void * DETEX_RESTRICT target, 197 | void * DETEX_RESTRICT source, int numel) 198 | { 199 | uint16_t *hp = (uint16_t *) source; // Type pun input as an unsigned 16-bit int 200 | uint32_t *xp = (uint32_t *) target; // Type pun output as an unsigned 32-bit int 201 | uint16_t h, hs, he, hm; 202 | uint32_t xs, xe, xm; 203 | int32_t xes; 204 | int e; 205 | #if 0 206 | static int next; // Little Endian adjustment 207 | static int checkieee = 1; // Flag to check for IEEE754, Endian, and word size 208 | double one = 1.0; // Used for checking IEEE754 floating point format 209 | uint32_t *ip; // Used for checking IEEE754 floating point format 210 | 211 | if( checkieee ) { // 1st call, so check for IEEE754, Endian, and word size 212 | ip = (uint32_t *) &one; 213 | if( *ip ) { // If Big Endian, then no adjustment 214 | next = 0; 215 | } else { // If Little Endian, then adjustment will be necessary 216 | next = 1; 217 | ip++; 218 | } 219 | if( *ip != 0x3FF00000u ) { // Check for exact IEEE 754 bit pattern of 1.0 220 | return 1; // Floating point bit pattern is not IEEE 754 221 | } 222 | if( sizeof(int16_t) != 2 || sizeof(int32_t) != 4 ) { 223 | return 1; // short is not 16-bits, or long is not 32-bits. 224 | } 225 | checkieee = 0; // Everything checks out OK 226 | } 227 | 228 | if( source == NULL || target == NULL ) // Nothing to convert (e.g., imag part of pure real) 229 | return 0; 230 | #endif 231 | 232 | while( numel-- ) { 233 | h = *hp++; 234 | if( (h & 0x7FFFu) == 0 ) { // Signed zero 235 | *xp++ = ((uint32_t) h) << 16; // Return the signed zero 236 | } else { // Not zero 237 | hs = h & 0x8000u; // Pick off sign bit 238 | he = h & 0x7C00u; // Pick off exponent bits 239 | hm = h & 0x03FFu; // Pick off mantissa bits 240 | if( he == 0 ) { // Denormal will convert to normalized 241 | e = -1; // The following loop figures out how much extra to adjust the exponent 242 | do { 243 | e++; 244 | hm <<= 1; 245 | } while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit 246 | xs = ((uint32_t) hs) << 16; // Sign bit 247 | xes = ((int32_t) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single 248 | xe = (uint32_t) (xes << 23); // Exponent 249 | xm = ((uint32_t) (hm & 0x03FFu)) << 13; // Mantissa 250 | *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits 251 | } else if( he == 0x7C00u ) { // Inf or NaN (all the exponent bits are set) 252 | if( hm == 0 ) { // If mantissa is zero ... 253 | *xp++ = (((uint32_t) hs) << 16) | ((uint32_t) 0x7F800000u); // Signed Inf 254 | } else { 255 | *xp++ = (uint32_t) 0xFFC00000u; // NaN, only 1st mantissa bit set 256 | } 257 | } else { // Normalized number 258 | xs = ((uint32_t) hs) << 16; // Sign bit 259 | xes = ((int32_t) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single 260 | xe = (uint32_t) (xes << 23); // Exponent 261 | xm = ((uint32_t) hm) << 13; // Mantissa 262 | *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits 263 | } 264 | } 265 | } 266 | } 267 | 268 | // Precalculated half-float table management. 269 | 270 | float *detex_half_float_table = NULL; 271 | 272 | static void detexCalculateHalfFloatTable() { 273 | detex_half_float_table = (float *)malloc(65536 * sizeof(float)); 274 | uint16_t *hf_buffer = (uint16_t *)malloc(65536 * sizeof(uint16_t)); 275 | for (int i = 0; i <= 0xFFFF; i++) 276 | hf_buffer[i] = i; 277 | halfp2singles(detex_half_float_table, hf_buffer, 65536); 278 | free(hf_buffer); 279 | } 280 | 281 | void detexValidateHalfFloatTable() { 282 | if (detex_half_float_table == NULL) 283 | detexCalculateHalfFloatTable(); 284 | } 285 | 286 | // Conversion functions. 287 | 288 | void detexConvertHalfFloatToFloat(uint16_t *source_buffer, int n, float *target_buffer) { 289 | detexValidateHalfFloatTable(); 290 | for (int i = 0; i < n; i++) 291 | target_buffer[i] = detexGetFloatFromHalfFloat(source_buffer[i]); 292 | } 293 | 294 | void detexConvertFloatToHalfFloat(float *source_buffer, int n, uint16_t *target_buffer) { 295 | singles2halfp(target_buffer, source_buffer, n); 296 | } 297 | 298 | // Convert normalized half floats to unsigned 16-bit integers in place. 299 | void detexConvertNormalizedHalfFloatToUInt16(uint16_t *buffer, int n) { 300 | detexValidateHalfFloatTable(); 301 | fesetround(FE_DOWNWARD); 302 | for (int i = 0; i < n; i++) { 303 | float f = detexGetFloatFromHalfFloat(buffer[i]); 304 | int u = lrintf(detexClamp0To1(f) * 65535.0f + 0.5f); 305 | buffer[i] = (uint16_t)u; 306 | } 307 | } 308 | 309 | // Convert normalized floats to unsigned 16-bit integers. 310 | void detexConvertNormalizedFloatToUInt16(float * DETEX_RESTRICT source_buffer, int n, 311 | uint16_t * DETEX_RESTRICT target_buffer) { 312 | fesetround(FE_DOWNWARD); 313 | for (int i = 0; i < n; i++) { 314 | int u = lrintf(detexClamp0To1(source_buffer[i]) * 65535.0f + 0.5f); 315 | target_buffer[i] = (uint16_t)u; 316 | } 317 | } 318 | 319 | -------------------------------------------------------------------------------- /External/Detex/half-float.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | void detexConvertHalfFloatToFloat(uint16_t *source_buffer, int n, float *target_buffer); 20 | 21 | void detexConvertFloatToHalfFloat(float *source_buffer, int n, uint16_t *target_buffer); 22 | 23 | void detexConvertNormalizedHalfFloatToUInt16(uint16_t *buffer, int n); 24 | 25 | void detexConvertNormalizedFloatToUInt16(float *source_buffer, int n, uint16_t *target_buffer); 26 | 27 | extern float *detex_half_float_table; 28 | 29 | void detexValidateHalfFloatTable(); 30 | 31 | static DETEX_INLINE_ONLY float detexGetFloatFromHalfFloat(uint16_t hf) { 32 | return detex_half_float_table[hf]; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /External/Detex/hdr.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "detex.h" 26 | #include "half-float.h" 27 | #include "hdr.h" 28 | #include "misc.h" 29 | 30 | // Gamma/HDR parameters. 31 | 32 | __thread float detex_gamma = 1.0f; 33 | __thread float detex_gamma_range_min = 0.0f; 34 | __thread float detex_gamma_range_max = 1.0f; 35 | __thread float *detex_gamma_corrected_half_float_table = NULL; 36 | __thread float detex_corrected_half_float_table_gamma; 37 | 38 | void detexSetHDRParameters(float gamma, float range_min, float range_max) { 39 | detex_gamma = gamma; 40 | detex_gamma_range_min = range_min; 41 | detex_gamma_range_max = range_max; 42 | detex_gamma_corrected_half_float_table = NULL; 43 | } 44 | 45 | // Update gamma-corrected half-float table when required. 46 | static void ValidateGammaCorrectedHalfFloatTable(float gamma) { 47 | if (detex_gamma_corrected_half_float_table != NULL && 48 | detex_corrected_half_float_table_gamma == gamma) 49 | return; 50 | if (detex_gamma_corrected_half_float_table == NULL) 51 | detex_gamma_corrected_half_float_table = (float *)malloc(65536 * sizeof(float)); 52 | float *float_table = detex_gamma_corrected_half_float_table; 53 | detexValidateHalfFloatTable(); 54 | memcpy(float_table, detex_half_float_table, 65536 * sizeof(float)); 55 | for (int i = 0; i <= 0xFFFF; i++) 56 | if (float_table[i] >= 0.0f) 57 | float_table[i] = powf(float_table[i], 1.0f / gamma); 58 | else 59 | float_table[i] = - powf(- float_table[i], 1.0f / gamma); 60 | } 61 | 62 | static DETEX_INLINE_ONLY void CalculateRangeFloat(float *buffer, int n, 63 | float *range_min_out, float *range_max_out) { 64 | float range_min = FLT_MAX; 65 | float range_max = - FLT_MAX; 66 | for (int i = 0; i < n; i++) { 67 | float f = buffer[i]; 68 | if (f < range_min) 69 | range_min = f; 70 | if (f > range_max) 71 | range_max = f; 72 | } 73 | *range_min_out = range_min; 74 | *range_max_out = range_max; 75 | } 76 | 77 | static DETEX_INLINE_ONLY void CalculateRangeHalfFloat(uint16_t *buffer, int n, 78 | float *range_min_out, float *range_max_out) { 79 | detexValidateHalfFloatTable(); 80 | float range_min = FLT_MAX; 81 | float range_max = - FLT_MAX; 82 | for (int i = 0; i < n; i ++) { 83 | float f = detexGetFloatFromHalfFloat(buffer[i]); 84 | if (f < range_min) 85 | range_min = f; 86 | if (f > range_max) 87 | range_max = f; 88 | } 89 | *range_min_out = range_min; 90 | *range_max_out = range_max; 91 | } 92 | 93 | 94 | bool detexCalculateDynamicRange(uint8_t *pixel_buffer, int nu_pixels, uint32_t pixel_format, 95 | float *range_min_out, float *range_max_out) { 96 | if (~(pixel_format & DETEX_PIXEL_FORMAT_FLOAT_BIT)) { 97 | detexSetErrorMessage("detexCalculateDynamicRange: Pixel buffer not in float format"); 98 | return false; 99 | } 100 | if (pixel_format & DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT) { 101 | CalculateRangeHalfFloat((uint16_t *)pixel_buffer, 102 | nu_pixels * detexGetPixelSize(pixel_format) / 2, 103 | range_min_out, range_max_out); 104 | return true; 105 | } 106 | else if (pixel_format & DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT) { 107 | CalculateRangeFloat((float *)pixel_buffer, 108 | nu_pixels * detexGetPixelSize(pixel_format) / 4, 109 | range_min_out, range_max_out); 110 | return true; 111 | } 112 | else { 113 | detexSetErrorMessage("detexCalculateDynamicRange: Unable to handle pixel buffer format"); 114 | return false; 115 | } 116 | } 117 | 118 | // Convert half floats to unsigned 16-bit integers in place with gamma value of 1. 119 | static DETEX_INLINE_ONLY void detexConvertHDRHalfFloatToUInt16Gamma1(uint16_t *buffer, int n) { 120 | detexValidateHalfFloatTable(); 121 | float range_min = detex_gamma_range_min; 122 | float range_max = detex_gamma_range_max; 123 | fesetround(FE_DOWNWARD); 124 | if (range_min == 0.0f && range_max == 1.0f) { 125 | for (int i = 0; i < n; i++) { 126 | float f = detexGetFloatFromHalfFloat(buffer[i]); 127 | int u = lrintf(detexClamp0To1(f) * 65535.0f + 0.5f); 128 | buffer[i] = (uint16_t)u; 129 | } 130 | return; 131 | } 132 | float factor = 1.0f / (range_max - range_min); 133 | for (int i = 0; i < n; i++) { 134 | float f = detexGetFloatFromHalfFloat(buffer[i]); 135 | int u = lrintf(detexClamp0To1((f - range_min) * factor) * 65535.0f + 0.5f); 136 | buffer[i] = (uint16_t)u; 137 | } 138 | } 139 | 140 | static DETEX_INLINE_ONLY void detexConvertHDRHalfFloatToUInt16SpecialGamma(uint16_t *buffer, int n) { 141 | float gamma = detex_gamma; 142 | float range_min = detex_gamma_range_min; 143 | float range_max = detex_gamma_range_max; 144 | ValidateGammaCorrectedHalfFloatTable(gamma); 145 | float *corrected_half_float_table = detex_gamma_corrected_half_float_table; 146 | float corrected_range_min, corrected_range_max; 147 | if (range_min >= 0.0f) 148 | corrected_range_min = powf(range_min, 1.0f / gamma); 149 | else 150 | corrected_range_min = - powf(- range_min, 1.0f / gamma); 151 | if (range_max >= 0.0f) 152 | corrected_range_max = powf(range_max, 1.0f / gamma); 153 | else 154 | corrected_range_max = - powf(- range_max, 1.0f / gamma); 155 | float factor = 1.0f / (corrected_range_max - corrected_range_min); 156 | for (int i = 0; i < n; i++) { 157 | float f = corrected_half_float_table[buffer[i]]; 158 | int u = lrintf(detexClamp0To1((f - corrected_range_min) * factor) * 65535.0f + 0.5f); 159 | buffer[i] = (uint16_t)u; 160 | } 161 | } 162 | 163 | void detexConvertHDRHalfFloatToUInt16(uint16_t *buffer, int n) { 164 | if (detex_gamma == 1.0f) 165 | detexConvertHDRHalfFloatToUInt16Gamma1(buffer, n); 166 | else 167 | detexConvertHDRHalfFloatToUInt16SpecialGamma(buffer, n); 168 | } 169 | 170 | static DETEX_INLINE_ONLY void detexConvertHDRFloatToFloatGamma1(float *buffer, int n) { 171 | float range_min = detex_gamma_range_min; 172 | float range_max = detex_gamma_range_max; 173 | fesetround(FE_DOWNWARD); 174 | if (range_min == 0.0f && range_max == 1.0f) { 175 | for (int i = 0; i < n; i++) { 176 | float f = buffer[i]; 177 | buffer[i] = detexClamp0To1(f); 178 | } 179 | return; 180 | } 181 | float factor = 1.0f / (range_max - range_min); 182 | for (int i = 0; i < n; i++) { 183 | float f = buffer[i]; 184 | buffer[i] = detexClamp0To1((f - range_min) * factor); 185 | } 186 | } 187 | 188 | static DETEX_INLINE_ONLY void detexConvertHDRFloatToFloatSpecialGamma(float *buffer, int n) { 189 | float gamma = detex_gamma; 190 | float range_min = detex_gamma_range_min; 191 | float range_max = detex_gamma_range_max; 192 | float corrected_range_min, corrected_range_max; 193 | if (range_min >= 0.0f) 194 | corrected_range_min = powf(range_min, 1.0f / gamma); 195 | else 196 | corrected_range_min = - powf(- range_min, 1.0f / gamma); 197 | if (range_max >= 0.0f) 198 | corrected_range_max = powf(range_max, 1.0f / gamma); 199 | else 200 | corrected_range_max = - powf(- range_max, 1.0f / gamma); 201 | float factor = 1.0f / (corrected_range_max - corrected_range_min); 202 | for (int i = 0; i < n; i++) { 203 | float f = buffer[i]; 204 | buffer[i] = detexClamp0To1((f - corrected_range_min) * factor); 205 | } 206 | } 207 | 208 | void detexConvertHDRFloatToFloat(float *buffer, int n) { 209 | if (detex_gamma == 1.0f) 210 | detexConvertHDRFloatToFloatGamma1(buffer, n); 211 | else 212 | detexConvertHDRFloatToFloatSpecialGamma(buffer, n); 213 | } 214 | 215 | -------------------------------------------------------------------------------- /External/Detex/hdr.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | void detexConvertHDRHalfFloatToUInt16(uint16_t *buffer, int n); 20 | 21 | void detexConvertHDRFloatToFloat(float *buffer, int n); 22 | 23 | -------------------------------------------------------------------------------- /External/Detex/ktx.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "detex.h" 24 | #include "file-info.h" 25 | #include "misc.h" 26 | 27 | static const uint8_t ktx_id[12] = { 28 | 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A 29 | }; 30 | 31 | // Load texture from KTX file with mip-maps. Returns true if successful. 32 | // nu_mipmaps is a return parameter that returns the number of mipmap levels found. 33 | // textures_out is a return parameter for an array of detexTexture pointers that is allocated, 34 | // free with free(). textures_out[i] are allocated textures corresponding to each level, free 35 | // with free(); 36 | bool detexLoadKTXFileWithMipmaps(const char *filename, int max_mipmaps, detexTexture ***textures_out, 37 | int *nu_levels_out) { 38 | FILE *f = fopen(filename, "rb"); 39 | if (f == NULL) { 40 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Could not open file %s", filename); 41 | return false; 42 | } 43 | int header[16]; 44 | size_t s = fread(header, 1, 64, f); 45 | if (s != 64) { 46 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Error reading file %s", filename); 47 | return false; 48 | } 49 | if (memcmp(header, ktx_id, 12) != 0) { 50 | // KTX signature not found. 51 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Couldn't find KTX signature"); 52 | return false; 53 | } 54 | int wrong_endian = 0; 55 | if (header[3] == 0x01020304) { 56 | // Wrong endian .ktx file. 57 | wrong_endian = 1; 58 | for (int i = 3; i < 16; i++) { 59 | uint8_t *b = (uint8_t *)&header[i]; 60 | uint8_t temp = b[0]; 61 | b[0] = b[3]; 62 | b[3] = temp; 63 | temp = b[1]; 64 | b[1] = b[2]; 65 | b[2] = temp; 66 | } 67 | } 68 | int glType = header[4]; 69 | int glFormat = header[6]; 70 | int glInternalFormat = header[7]; 71 | // int pixel_depth = header[11]; 72 | const detexTextureFileInfo *info = detexLookupKTXFileInfo(glInternalFormat, glFormat, glType); 73 | if (info == NULL) { 74 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Unsupported format in .ktx file " 75 | "(glInternalFormat = 0x%04X)", glInternalFormat); 76 | return false; 77 | } 78 | int bytes_per_block; 79 | if (detexFormatIsCompressed(info->texture_format)) 80 | bytes_per_block = detexGetCompressedBlockSize(info->texture_format); 81 | else 82 | bytes_per_block = detexGetPixelSize(info->texture_format); 83 | int block_width = info->block_width; 84 | int block_height = info->block_height; 85 | // printf("File is %s texture.\n", info->text1); 86 | int width = header[9]; 87 | int height = header[10]; 88 | int extended_width = ((width + block_width - 1) / block_width) * block_width; 89 | int extended_height = ((height + block_height - 1) / block_height) * block_height; 90 | int nu_file_mipmaps = header[14]; 91 | // if (nu_file_mipmaps > 1 && max_mipmaps == 1) { 92 | // detexSetErrorMessage("Disregarding mipmaps beyond the first level.\n"); 93 | // } 94 | int nu_mipmaps; 95 | if (nu_file_mipmaps > max_mipmaps) 96 | nu_mipmaps = max_mipmaps; 97 | else 98 | nu_mipmaps = nu_file_mipmaps; 99 | if (header[15] > 0) { 100 | // Skip metadata. 101 | uint8_t *metadata = (unsigned char *)malloc(header[15]); 102 | if (fread(metadata, 1, header[15], f) < header[15]) { 103 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Error reading file %s", filename); 104 | return false; 105 | } 106 | free(metadata); 107 | } 108 | detexTexture **textures = (detexTexture **)malloc(sizeof(detexTexture *) * nu_mipmaps); 109 | for (int i = 0; i < nu_mipmaps; i++) { 110 | uint32_t image_size_buffer[1]; 111 | size_t r = fread(image_size_buffer, 1, 4, f); 112 | if (r != 4) { 113 | for (int j = 0; j < i; j++) 114 | free(textures[j]); 115 | free(textures); 116 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Error reading file %s", filename); 117 | return false; 118 | } 119 | if (wrong_endian) { 120 | uint8_t *image_size_bytep = (uint8_t *)&image_size_buffer[0]; 121 | unsigned char temp = image_size_buffer[0]; 122 | image_size_bytep[0] = image_size_bytep[3]; 123 | image_size_bytep[3] = temp; 124 | temp = image_size_bytep[1]; 125 | image_size_bytep[1] = image_size_bytep[2]; 126 | image_size_bytep[2] = temp; 127 | } 128 | int image_size = image_size_buffer[0]; 129 | int n = (extended_height / block_height) * (extended_width / block_width); 130 | if (image_size != n * bytes_per_block) { 131 | for (int j = 0; j < i; j++) 132 | free(textures[j]); 133 | free(textures); 134 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Error loading file %s: " 135 | "Image size field of mipmap level %d does not match (%d vs %d)", 136 | filename, i, image_size, n * bytes_per_block); 137 | return false; 138 | } 139 | // Allocate texture. 140 | textures[i] = (detexTexture *)malloc(sizeof(detexTexture)); 141 | textures[i]->format = info->texture_format; 142 | textures[i]->data = (uint8_t *)malloc(n * bytes_per_block); 143 | textures[i]->width = width; 144 | textures[i]->height = height; 145 | textures[i]->width_in_blocks = extended_width / block_width; 146 | textures[i]->height_in_blocks = extended_height / block_height; 147 | if (fread(textures[i]->data, 1, n * bytes_per_block, f) < n * bytes_per_block) { 148 | for (int j = 0; j <= i; j++) 149 | free(textures[j]); 150 | free(textures); 151 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Error reading file %s", filename); 152 | return false; 153 | } 154 | // Divide by two for the next mipmap level, rounding down. 155 | if (width > 1) 156 | width >>= 1; 157 | if (height > 1) 158 | height >>= 1; 159 | extended_width = ((width + block_width - 1) / block_width) * block_width; 160 | extended_height = ((height + block_height - 1) / block_height) * block_height; 161 | // Read mipPadding. But not if we have already read everything specified. 162 | char buffer[4]; 163 | if (i + 1 < nu_mipmaps) { 164 | int nu_bytes = 3 - ((image_size + 3) % 4); 165 | if (fread(buffer, 1, nu_bytes, f) != nu_bytes) { 166 | for (int j = 0; j <= i; j++) 167 | free(textures[j]); 168 | free(textures); 169 | detexSetErrorMessage("detexLoadKTXFileWithMipmaps: Error reading file %s", filename); 170 | return false; 171 | } 172 | } 173 | } 174 | fclose(f); 175 | *nu_levels_out = nu_mipmaps; 176 | *textures_out = textures; 177 | return true; 178 | } 179 | 180 | // Load texture from KTX file (first mip-map only). Returns true if successful. 181 | // The texture is allocated, free with free(). 182 | bool detexLoadKTXFile(const char *filename, detexTexture **texture_out) { 183 | int nu_mipmaps; 184 | detexTexture **textures; 185 | bool r = detexLoadKTXFileWithMipmaps(filename, 1, &textures, &nu_mipmaps); 186 | if (!r) 187 | return false; 188 | *texture_out = textures[0]; 189 | free(textures); 190 | return true; 191 | } 192 | 193 | enum { 194 | DETEX_ORIENTATION_DOWN = 1, 195 | DETEX_ORIENTATION_UP = 2 196 | }; 197 | 198 | static const char ktx_orientation_key_down[24] = { 199 | 'K', 'T', 'X', 'o', 'r', 'i', 'e', 'n', 't', 'a', 't', 'i', 'o', 'n', 0, 200 | 'S', '=', 'r', ',', 'T', '=', 'd', 0, 0 // Includes one byte of padding. 201 | }; 202 | 203 | static const char ktx_orientation_key_up[24] = { 204 | 'K', 'T', 'X', 'o', 'r', 'i', 'e', 'n', 't', 'a', 't', 'i', 'o', 'n', 0, 205 | 'S', '=', 'r', ',', 'T', '=', 'u', 0, 0 // Includes one byte of padding. 206 | }; 207 | 208 | // Save textures to KTX file (multiple mip-maps levels). Return true if succesful. 209 | bool detexSaveKTXFileWithMipmaps(detexTexture **textures, int nu_levels, const char *filename) { 210 | FILE *f = fopen(filename, "wb"); 211 | if (f == NULL) { 212 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Could not open file %s for writing", filename); 213 | return false; 214 | } 215 | uint32_t header[16]; 216 | memset(header, 0, 64); 217 | memcpy(header, ktx_id, 12); // Set id. 218 | header[3] = 0x04030201; 219 | const detexTextureFileInfo *info = detexLookupTextureFormatFileInfo(textures[0]->format); 220 | if (info == NULL) { 221 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Could not match texture format with file format"); 222 | return false; 223 | } 224 | if (!info->ktx_support) { 225 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Could not match texture format with KTX file format"); 226 | return false; 227 | } 228 | int glType = 0; 229 | int glTypeSize = 1; 230 | int glFormat = 0; 231 | glType = info->gl_type; 232 | glFormat = info->gl_format; 233 | int glInternalFormat = info->gl_internal_format; 234 | header[4] = glType; // glType 235 | header[5] = glTypeSize; // glTypeSize 236 | header[6] = glFormat; // glFormat 237 | header[7] = glInternalFormat; 238 | header[9] = textures[0]->width; 239 | header[10] = textures[0]->height; 240 | header[11] = 0; 241 | header[13] = 1; // Number of faces. 242 | header[14] = nu_levels; // Mipmap levels. 243 | int data[1]; 244 | const int option_orientation = 0; 245 | if (option_orientation == 0) { 246 | header[15] = 0; 247 | size_t r = fwrite(header, 1, 64, f); 248 | if (r != 64) { 249 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 250 | return false; 251 | } 252 | } 253 | else { 254 | header[15] = 28; // Key value data bytes. 255 | size_t r = fwrite(header, 1, 64, f); 256 | if (r != 64) { 257 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 258 | return false; 259 | } 260 | data[0] = 27; // Key and value size. 261 | r = fwrite(data, 1, 4, f); 262 | if (r != 4) { 263 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 264 | return false; 265 | } 266 | if (option_orientation == DETEX_ORIENTATION_DOWN) 267 | r = fwrite(ktx_orientation_key_down, 1, 24, f); 268 | else 269 | r = fwrite(ktx_orientation_key_up, 1, 24, f); 270 | if (r != 24) { 271 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 272 | return false; 273 | } 274 | } 275 | for (int i = 0; i < nu_levels; i++) { 276 | uint32_t pixel_size = detexGetPixelSize(textures[i]->format); 277 | // Block size is block size for compressed textures and the pixel size for 278 | // uncompressed textures. 279 | int n; 280 | int block_size; 281 | if (detexFormatIsCompressed(textures[i]->format)) { 282 | n = textures[i]->width_in_blocks * textures[i]->height_in_blocks; 283 | block_size = detexGetCompressedBlockSize(textures[i]->format); 284 | } 285 | else { 286 | n = textures[i]->width * textures[i]->height; 287 | block_size = pixel_size; 288 | } 289 | // if (!option_quiet) 290 | // printf("Writing mipmap level %d of size %d x %d.\n", i, textures[i]->width, textures[i]->height); 291 | // Because of per row 32-bit alignment is mandated by the KTX specification, we have to handle 292 | // special cases of unaligned uncompressed textures. 293 | if (detexFormatIsCompressed(textures[i]->format) || (pixel_size & 3) == 0) { 294 | // Regular 32-bit aligned texture. 295 | data[0] = n * block_size; // Image size. 296 | size_t r1 = fwrite(data, 1, 4, f); 297 | size_t r2 = fwrite(textures[i]->data, 1, n * block_size, f); 298 | if (r1 != 4 || r2 != n * block_size) { 299 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 300 | return false; 301 | } 302 | } 303 | else { 304 | // Uncompressed texture with pixel size that is not a multiple of four. 305 | int row_size = (textures[i]->width * pixel_size + 3) & (~3); 306 | data[0] = textures[i]->height * row_size; // Image size. 307 | size_t r1 = fwrite(data, 1, 4, f); 308 | if (r1 != 4) { 309 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 310 | return false; 311 | } 312 | uint8_t *row = (uint8_t *)malloc(row_size); 313 | for (int y = 0; y < textures[i]->height; y++) { 314 | memcpy(row, &textures[i]->data[y * textures[i]->width * pixel_size], 315 | textures[i]->width * pixel_size); 316 | for (int j = textures[i]->width * pixel_size; j < row_size; j++) 317 | row[j] = 0; 318 | size_t r2 = fwrite(row, 1, row_size, f); 319 | if (r2 != row_size) { 320 | detexSetErrorMessage("detexSaveKTXFileWithMipmaps: Error writing to file %s", filename); 321 | return false; 322 | } 323 | } 324 | free(row); 325 | } 326 | } 327 | fclose(f); 328 | return true; 329 | } 330 | 331 | // Save texture to KTX file (single mip-map level). Returns true if succesful. 332 | bool detexSaveKTXFile(detexTexture *texture, const char *filename) { 333 | detexTexture *textures[1]; 334 | textures[0] = texture; 335 | return detexSaveKTXFileWithMipmaps(textures, 1, filename); 336 | } 337 | 338 | -------------------------------------------------------------------------------- /External/Detex/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #define _GNU_SOURCE 20 | #include 21 | #include 22 | #include 23 | #ifndef _MSC_VER 24 | #include 25 | #endif 26 | #include 27 | 28 | #include "detex.h" 29 | 30 | #ifndef max 31 | #define max(a,b) (((a) > (b)) ? (a) : (b)) 32 | #endif 33 | 34 | // Generate bit mask from bit0 to bit1 (inclusive). 35 | static DETEX_INLINE_ONLY uint64_t GenerateMask(int bit0, int bit1) { 36 | return (((uint64_t)1 << (bit1 + 1)) - 1) ^ 37 | (((uint64_t)1 << bit0) - 1); 38 | } 39 | 40 | /* Return the component bitfield masks for a pixel format (pixel size must be at most 64 bits). */ 41 | DETEX_API bool detexGetComponentMasks(uint32_t pixel_format, uint64_t *red_mask_out, uint64_t *green_mask_out, 42 | uint64_t *blue_mask_out, uint64_t *alpha_mask_out) { 43 | if (detexGetPixelSize(pixel_format) > 64) 44 | return false; 45 | int component_size = detexGetComponentSize(pixel_format) * 8; 46 | int nu_components = detexGetNumberOfComponents(pixel_format); 47 | uint64_t red_mask, green_mask, blue_mask, alpha_mask; 48 | red_mask = 0; 49 | green_mask = 0; 50 | blue_mask = 0; 51 | alpha_mask = 0; 52 | if (nu_components == 1 && (pixel_format & DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT)) { 53 | alpha_mask = GenerateMask(0, component_size - 1); 54 | goto end; 55 | } 56 | red_mask = GenerateMask(0, component_size - 1); 57 | if (nu_components > 1) { 58 | green_mask = GenerateMask(component_size, component_size * 2 - 1); 59 | if (nu_components > 2) { 60 | blue_mask = GenerateMask(component_size * 2, component_size * 3 - 1); 61 | if (nu_components > 3) 62 | alpha_mask = GenerateMask(component_size * 3, component_size * 4 - 1); 63 | } 64 | } 65 | if (pixel_format & DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT) { 66 | // Swap red and blue. 67 | uint64_t temp = red_mask; 68 | red_mask = blue_mask; 69 | blue_mask = temp; 70 | } 71 | end: 72 | *red_mask_out = red_mask; 73 | *green_mask_out = green_mask; 74 | *blue_mask_out = blue_mask; 75 | *alpha_mask_out = alpha_mask; 76 | return true; 77 | } 78 | 79 | // Error handling. 80 | 81 | static __thread char *detex_error_message = NULL; 82 | 83 | void detexSetErrorMessage(const char *format, ...) { 84 | if (detex_error_message != NULL) 85 | free(detex_error_message); 86 | va_list args; 87 | va_start(args, format); 88 | char *message; 89 | // Allocate and set message. 90 | int r = vasprintf(&message, format, args); 91 | if (r < 0) 92 | message = strdup("detexSetErrorMessage: vasprintf returned error"); 93 | va_end(args); 94 | detex_error_message = message; 95 | } 96 | 97 | const char *detexGetErrorMessage() { 98 | return detex_error_message; 99 | } 100 | 101 | // General texture file loading. 102 | 103 | // Load texture file (type autodetected from extension) with mipmaps. 104 | bool detexLoadTextureFileWithMipmaps(const char *filename, int max_mipmaps, detexTexture ***textures_out, 105 | int *nu_levels_out) { 106 | size_t filename_length = strlen(filename); 107 | if (filename_length > 4 && strncasecmp(filename + filename_length - 4, ".ktx", 4) == 0) 108 | return detexLoadKTXFileWithMipmaps(filename, max_mipmaps, textures_out, nu_levels_out); 109 | else if (filename_length > 4 && strncasecmp(filename + filename_length - 4, ".dds", 4) == 0) 110 | return detexLoadDDSFileWithMipmaps(filename, max_mipmaps, textures_out, nu_levels_out); 111 | else { 112 | bool result = detexLoadImageFile(filename, textures_out); 113 | if (result) { 114 | *nu_levels_out = 1; 115 | } 116 | return result; 117 | } 118 | } 119 | 120 | // Load texture file (type autodetected from extension). 121 | bool detexLoadTextureFile(const char *filename, detexTexture **texture_out) { 122 | int nu_mipmaps; 123 | detexTexture **textures; 124 | bool r = detexLoadTextureFileWithMipmaps(filename, 1, &textures, &nu_mipmaps); 125 | if (!r) 126 | return false; 127 | *texture_out = textures[0]; 128 | free(textures); 129 | return true; 130 | } 131 | 132 | // Load texture from memory (first mip-map only). 133 | DETEX_API void detexLoadTextureFromMemory(uint32_t pixel_format, uint32_t width, uint32_t height, const uint8_t *data, detexTexture ***texture_out) { 134 | detexTexture **texture = (detexTexture **)malloc(sizeof(detexTexture *)); 135 | texture[0] = (detexTexture *)malloc(sizeof(detexTexture)); 136 | texture[0]->format = pixel_format; 137 | texture[0]->width = width; 138 | texture[0]->height = height; 139 | size_t size; 140 | if (detexFormatIsCompressed(pixel_format)) { 141 | texture[0]->width_in_blocks = max(1, (width + 3) / 4); 142 | texture[0]->height_in_blocks = max(1, (height + 3) / 4); 143 | size = detexGetCompressedBlockSize(pixel_format) * texture[0]->width_in_blocks * texture[0]->height_in_blocks; 144 | } else { 145 | texture[0]->width_in_blocks = texture[0]->width; 146 | texture[0]->height_in_blocks = texture[0]->height; 147 | size = detexGetPixelSize(pixel_format) * texture[0]->width * texture[0]->height; 148 | } 149 | texture[0]->data = (uint8_t *)malloc(size); 150 | memcpy(texture[0]->data, data, size); 151 | *texture_out = texture; 152 | } 153 | 154 | // Free loaded texture. 155 | DETEX_API void detexFreeTexture(detexTexture **texture, int nu_levels) { 156 | if (texture) { 157 | for (int i = 0; i < nu_levels; i++) 158 | { 159 | free(texture[i]->data); 160 | free(texture[i]); 161 | } 162 | free(texture); 163 | } 164 | } 165 | 166 | // Computes row and slice pitch of a texture. 167 | DETEX_API void detexComputePitch(uint32_t pixel_format, int width, int height, int* row_pitch, int* slice_pitch) { 168 | switch (pixel_format) { 169 | case DETEX_TEXTURE_FORMAT_BC1: 170 | case DETEX_TEXTURE_FORMAT_RGTC1: 171 | case DETEX_TEXTURE_FORMAT_SIGNED_RGTC1: { 172 | int width_in_blocks = max(1, (width + 3) / 4); 173 | int height_in_blocks = max(1, (height + 3) / 4); 174 | *row_pitch = width_in_blocks * 8; 175 | *slice_pitch = *row_pitch * height_in_blocks; 176 | } 177 | break; 178 | 179 | case DETEX_TEXTURE_FORMAT_BC2: 180 | case DETEX_TEXTURE_FORMAT_BC3: 181 | case DETEX_TEXTURE_FORMAT_RGTC2: 182 | case DETEX_TEXTURE_FORMAT_SIGNED_RGTC2: 183 | case DETEX_TEXTURE_FORMAT_BPTC_FLOAT: 184 | case DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT: 185 | case DETEX_TEXTURE_FORMAT_BPTC: { 186 | int width_in_blocks = max(1, (width + 3) / 4); 187 | int height_in_blocks = max(1, (height + 3) / 4); 188 | *row_pitch = width_in_blocks * 16; 189 | *slice_pitch = *row_pitch * height_in_blocks; 190 | } 191 | break; 192 | 193 | default: { 194 | uint32_t bpp = detexGetPixelSize(pixel_format) * 8; 195 | *row_pitch = (width * bpp + 7) / 8; 196 | *slice_pitch = *row_pitch * height; 197 | } 198 | break; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /External/Detex/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | 20 | void detexSetErrorMessage(const char *format, ...); 21 | 22 | -------------------------------------------------------------------------------- /External/Detex/stb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifndef _MSC_VER 5 | #include 6 | #endif 7 | 8 | #include "detex.h" 9 | #include "misc.h" 10 | 11 | #define STB_IMAGE_IMPLEMENTATION 12 | #define STBI_WINDOWS_UTF8 13 | #include "stb_image.h" 14 | 15 | #define STB_IMAGE_WRITE_IMPLEMENTATION 16 | #define STBIW_WINDOWS_UTF8 17 | #include "stb_image_write.h" 18 | 19 | // Load texture from an image file using stb_image (first mip-map only). 20 | // Formats supported: JPEG, PNG, TGA, BMP, PSD, GIF, HDR, PIC, PNM. 21 | // Returns true if successful. The texture is allocated, free with free(). 22 | bool detexLoadImageFile(const char *filename, detexTexture ***texture_out) { 23 | int x, y, comp; 24 | unsigned char *image = stbi_load(filename, &x, &y, &comp, STBI_rgb_alpha); 25 | if (!image) 26 | { 27 | detexSetErrorMessage("detexLoadImageFile: Could not open file %s. Reason: %s", 28 | filename, stbi_failure_reason()); 29 | return false; 30 | } 31 | detexTexture **dTexture = (detexTexture **)malloc(sizeof(detexTexture *)); 32 | dTexture[0] = (detexTexture *)malloc(sizeof(detexTexture)); 33 | dTexture[0]->format = DETEX_PIXEL_FORMAT_RGBA8; 34 | dTexture[0]->width = x; 35 | dTexture[0]->height = y; 36 | dTexture[0]->width_in_blocks = x; 37 | dTexture[0]->height_in_blocks = y; 38 | size_t size = x * y * detexGetPixelSize(DETEX_PIXEL_FORMAT_RGBA8); 39 | dTexture[0]->data = (uint8_t *)malloc(size); 40 | memcpy(dTexture[0]->data, image, size); 41 | *texture_out = dTexture; 42 | stbi_image_free(image); 43 | return true; 44 | } 45 | 46 | // Save texture to an image file (type autodetected from extension). 47 | // Formats supported: JPEG, PNG, TGA, BMP. 48 | DETEX_API bool detexSaveImageFile(detexTexture *texture, const char *filename) 49 | { 50 | if (texture->format != DETEX_PIXEL_FORMAT_RGBA8) 51 | { 52 | detexSetErrorMessage("detexSaveImageFile: Only RGA8 format supported"); 53 | return false; 54 | } 55 | size_t filename_length = strlen(filename); 56 | if ((filename_length > 4 && strncasecmp(filename + filename_length - 4, ".jpg", 4) == 0) || 57 | (filename_length > 5 && strncasecmp(filename + filename_length - 5, ".jpeg", 5) == 0)) 58 | return stbi_write_jpg(filename, texture->width, texture->height, 4, texture->data, 0); 59 | else if (filename_length > 4 && strncasecmp(filename + filename_length - 4, ".png", 4) == 0) 60 | return stbi_write_png(filename, texture->width, texture->height, 4, texture->data, 4 * texture->width); 61 | else if (filename_length > 4 && strncasecmp(filename + filename_length - 4, ".tga", 4) == 0) 62 | return stbi_write_tga(filename, texture->width, texture->height, 4, texture->data); 63 | else if (filename_length > 4 && strncasecmp(filename + filename_length - 4, ".bmp", 4) == 0) 64 | return stbi_write_bmp(filename, texture->width, texture->height, 4, texture->data); 65 | else { 66 | detexSetErrorMessage("detexSaveImageFile: Unsupported filename extension"); 67 | return false; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /External/Detex/texture.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Harm Hanemaaijer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | */ 18 | 19 | #include 20 | 21 | #include "detex.h" 22 | #include "misc.h" 23 | 24 | typedef bool (*detexDecompressBlockFuncType)(const uint8_t *bitstring, 25 | uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer); 26 | 27 | static detexDecompressBlockFuncType decompress_function[] = { 28 | NULL, 29 | detexDecompressBlockBC1, 30 | detexDecompressBlockBC1A, 31 | detexDecompressBlockBC2, 32 | detexDecompressBlockBC3, 33 | detexDecompressBlockRGTC1, 34 | detexDecompressBlockSIGNED_RGTC1, 35 | detexDecompressBlockRGTC2, 36 | detexDecompressBlockSIGNED_RGTC2, 37 | detexDecompressBlockBPTC_FLOAT, 38 | detexDecompressBlockBPTC_SIGNED_FLOAT, 39 | detexDecompressBlockBPTC, 40 | detexDecompressBlockETC1, 41 | detexDecompressBlockETC2, 42 | detexDecompressBlockETC2_PUNCHTHROUGH, 43 | detexDecompressBlockETC2_EAC, 44 | detexDecompressBlockEAC_R11, 45 | detexDecompressBlockEAC_SIGNED_R11, 46 | detexDecompressBlockEAC_RG11, 47 | detexDecompressBlockEAC_SIGNED_RG11, 48 | }; 49 | 50 | /* 51 | * General block decompression function. Block is decompressed using the given 52 | * compressed format, and stored in the given pixel format. Returns true if 53 | * succesful. 54 | */ 55 | bool detexDecompressBlock(const uint8_t * DETEX_RESTRICT bitstring, uint32_t texture_format, 56 | uint32_t mode_mask, uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer, 57 | uint32_t pixel_format) { 58 | uint8_t block_buffer[DETEX_MAX_BLOCK_SIZE]; 59 | uint32_t compressed_format = detexGetCompressedFormat(texture_format); 60 | bool r = decompress_function[compressed_format](bitstring, mode_mask, flags, 61 | block_buffer); 62 | if (!r) { 63 | detexSetErrorMessage("detexDecompressBlock: Decompress function for format " 64 | "0x%08X returned error", texture_format); 65 | return false; 66 | } 67 | /* Convert into desired pixel format. */ 68 | return detexConvertPixels(block_buffer, 16, 69 | detexGetPixelFormat(texture_format), pixel_buffer, pixel_format); 70 | } 71 | 72 | /* 73 | * Decode texture function (tiled). Decode an entire compressed texture into an 74 | * array of image buffer tiles (corresponding to compressed blocks), converting 75 | * into the given pixel format. 76 | */ 77 | bool detexDecompressTextureTiled(const detexTexture *texture, 78 | uint8_t * DETEX_RESTRICT pixel_buffer, uint32_t pixel_format) { 79 | if (!detexFormatIsCompressed(texture->format)) { 80 | detexSetErrorMessage("detexDecompressTextureTiled: Cannot handle uncompressed texture format"); 81 | return false; 82 | } 83 | const uint8_t *data = texture->data; 84 | bool result = true; 85 | for (int y = 0; y < texture->height_in_blocks; y++) 86 | for (int x = 0; x < texture->width_in_blocks; x++) { 87 | bool r = detexDecompressBlock(data, texture->format, 88 | DETEX_MODE_MASK_ALL, 0, pixel_buffer, pixel_format); 89 | uint32_t block_size = detexGetPixelSize(pixel_format) * 16; 90 | if (!r) { 91 | result = false; 92 | memset(pixel_buffer, 0, block_size); 93 | } 94 | data += detexGetCompressedBlockSize(texture->format); 95 | pixel_buffer += block_size; 96 | } 97 | return result; 98 | } 99 | 100 | /* 101 | * Decode texture function (linear). Decode an entire texture into a single 102 | * image buffer, with pixels stored row-by-row, converting into the given pixel 103 | * format. 104 | */ 105 | bool detexDecompressTextureLinear(const detexTexture *texture, 106 | uint8_t * DETEX_RESTRICT pixel_buffer, uint32_t pixel_format) { 107 | uint8_t block_buffer[DETEX_MAX_BLOCK_SIZE]; 108 | if (!detexFormatIsCompressed(texture->format)) { 109 | return detexConvertPixels(texture->data, texture->width * texture->height, 110 | detexGetPixelFormat(texture->format), pixel_buffer, pixel_format); 111 | } 112 | const uint8_t *data = texture->data; 113 | int pixel_size = detexGetPixelSize(pixel_format); 114 | bool result = true; 115 | for (int y = 0; y < texture->height_in_blocks; y++) { 116 | int nu_rows; 117 | if (y * 4 + 3 >= texture->height) 118 | nu_rows = texture->height - y * 4; 119 | else 120 | nu_rows = 4; 121 | for (int x = 0; x < texture->width_in_blocks; x++) { 122 | bool r = detexDecompressBlock(data, texture->format, 123 | DETEX_MODE_MASK_ALL, 0, block_buffer, pixel_format); 124 | uint32_t block_size = detexGetPixelSize(pixel_format) * 16; 125 | if (!r) { 126 | result = false; 127 | memset(block_buffer, 0, block_size); 128 | } 129 | uint8_t *pixelp = pixel_buffer + 130 | y * 4 * texture->width * pixel_size + 131 | + x * 4 * pixel_size; 132 | int nu_columns; 133 | if (x * 4 + 3 >= texture->width) 134 | nu_columns = texture->width - x * 4; 135 | else 136 | nu_columns = 4; 137 | for (int row = 0; row < nu_rows; row++) 138 | memcpy(pixelp + row * texture->width * pixel_size, 139 | block_buffer + row * 4 * pixel_size, 140 | nu_columns * pixel_size); 141 | data += detexGetCompressedBlockSize(texture->format); 142 | } 143 | } 144 | return result; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /External/MetalUtility/MetalUtility.h: -------------------------------------------------------------------------------- 1 | typedef struct GLFWwindow GLFWwindow; 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | void* GetMetalLayer(GLFWwindow* window); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif -------------------------------------------------------------------------------- /External/MetalUtility/MetalUtility.m: -------------------------------------------------------------------------------- 1 | #include "MetalUtility.h" 2 | 3 | #define GLFW_EXPOSE_NATIVE_COCOA 4 | #include 5 | #include 6 | 7 | #import 8 | 9 | // Vulkan swap-chain creation requires the metal layer that was created 10 | void* GetMetalLayer(GLFWwindow* window) 11 | { 12 | if (!window) 13 | return NULL; 14 | 15 | NSWindow* nsWindow = glfwGetCocoaWindow(window); 16 | if (!nsWindow) 17 | return NULL; 18 | 19 | NSView* contentView = [nsWindow contentView]; 20 | if (![contentView.layer isKindOfClass:[CAMetalLayer class]]) 21 | { 22 | [contentView setLayer:[CAMetalLayer layer]]; 23 | [contentView setWantsLayer:YES]; 24 | } 25 | 26 | return (__bridge void*)[contentView layer]; 27 | } 28 | -------------------------------------------------------------------------------- /Include/Camera.h: -------------------------------------------------------------------------------- 1 | // © 2021 NVIDIA Corporation 2 | 3 | #pragma once 4 | 5 | struct CameraDesc { 6 | cBoxf limits = {}; 7 | float3 dLocal = float3(0.0f); 8 | float3 dUser = float3(0.0f); 9 | float dYaw = 0.0f; // deg 10 | float dPitch = 0.0f; // deg 11 | float aspectRatio = 1.0f; 12 | float horizontalFov = 90.0f; // deg 13 | float nearZ = 0.1f; 14 | float farZ = 10000.0f; 15 | float orthoRange = 0.0f; 16 | float timeScale = 0.5f; 17 | float backwardOffset = 0.0f; 18 | bool isReversedZ = false; 19 | bool isPositiveZ = true; 20 | bool isCustomMatrixSet = false; 21 | float4x4 customMatrix = float4x4::Identity(); 22 | }; 23 | 24 | struct CameraState { 25 | double3 globalPosition = {}; 26 | float4x4 mViewToClip = float4x4::Identity(); 27 | float4x4 mClipToView = float4x4::Identity(); 28 | float4x4 mWorldToView = float4x4::Identity(); 29 | float4x4 mViewToWorld = float4x4::Identity(); 30 | float4x4 mWorldToClip = float4x4::Identity(); 31 | float4x4 mClipToWorld = float4x4::Identity(); 32 | float3 position = {}; 33 | float3 rotation = {}; 34 | float2 viewportJitter = {}; 35 | float motionScale = 0.015f; 36 | }; 37 | 38 | class Camera { 39 | public: 40 | void Update(const CameraDesc& desc, uint32_t frameIndex); 41 | void Initialize(const float3& position, const float3& lookAt, bool isRelative = false); 42 | void InitializeWithRotation(const float3& position, const float3& rotationDegrees, bool isRelative); 43 | 44 | inline void SavePreviousState() { 45 | statePrev = state; 46 | } 47 | 48 | inline const float3 GetRelative(const double3& origin) const { 49 | double3 position = m_IsRelative ? state.globalPosition : double3(0.0); 50 | 51 | return float3(origin - position); 52 | } 53 | 54 | inline void* GetState() { 55 | return &state; 56 | } 57 | 58 | static inline uint32_t GetStateSize() { 59 | return sizeof(CameraState); 60 | } 61 | 62 | public: 63 | CameraState state = {}; 64 | CameraState statePrev = {}; 65 | 66 | private: 67 | bool m_IsRelative = false; 68 | }; 69 | -------------------------------------------------------------------------------- /Include/Controls.h: -------------------------------------------------------------------------------- 1 | // © 2021 NVIDIA Corporation 2 | 3 | #pragma once 4 | 5 | #undef Button4 6 | #undef Button5 7 | 8 | enum class Button : uint8_t { 9 | Left = GLFW_MOUSE_BUTTON_LEFT, 10 | Right = GLFW_MOUSE_BUTTON_RIGHT, 11 | Middle = GLFW_MOUSE_BUTTON_MIDDLE, 12 | Button4 = GLFW_MOUSE_BUTTON_4, 13 | Button5 = GLFW_MOUSE_BUTTON_5, 14 | Button6 = GLFW_MOUSE_BUTTON_6, 15 | Button7 = GLFW_MOUSE_BUTTON_7, 16 | Button8 = GLFW_MOUSE_BUTTON_8, 17 | 18 | NUM = GLFW_MOUSE_BUTTON_LAST 19 | }; 20 | 21 | enum class Key : uint32_t { 22 | Tilda = GLFW_KEY_GRAVE_ACCENT, 23 | _1 = GLFW_KEY_1, 24 | _2 = GLFW_KEY_2, 25 | _3 = GLFW_KEY_3, 26 | _4 = GLFW_KEY_4, 27 | _5 = GLFW_KEY_5, 28 | _6 = GLFW_KEY_6, 29 | _7 = GLFW_KEY_7, 30 | _8 = GLFW_KEY_8, 31 | _9 = GLFW_KEY_9, 32 | _0 = GLFW_KEY_0, 33 | Minus = GLFW_KEY_MINUS, 34 | Equals = GLFW_KEY_EQUAL, 35 | Back = GLFW_KEY_BACKSPACE, 36 | 37 | Q = GLFW_KEY_Q, 38 | W = GLFW_KEY_W, 39 | E = GLFW_KEY_E, 40 | R = GLFW_KEY_R, 41 | T = GLFW_KEY_T, 42 | Y = GLFW_KEY_Y, 43 | U = GLFW_KEY_U, 44 | I = GLFW_KEY_I, 45 | O = GLFW_KEY_O, 46 | P = GLFW_KEY_P, 47 | A = GLFW_KEY_A, 48 | S = GLFW_KEY_S, 49 | D = GLFW_KEY_D, 50 | F = GLFW_KEY_F, 51 | G = GLFW_KEY_G, 52 | H = GLFW_KEY_H, 53 | J = GLFW_KEY_J, 54 | K = GLFW_KEY_K, 55 | L = GLFW_KEY_L, 56 | Z = GLFW_KEY_Z, 57 | X = GLFW_KEY_X, 58 | C = GLFW_KEY_C, 59 | V = GLFW_KEY_V, 60 | B = GLFW_KEY_B, 61 | N = GLFW_KEY_N, 62 | M = GLFW_KEY_M, 63 | 64 | Escape = GLFW_KEY_ESCAPE, 65 | F1 = GLFW_KEY_F1, 66 | F2 = GLFW_KEY_F2, 67 | F3 = GLFW_KEY_F3, 68 | F4 = GLFW_KEY_F4, 69 | F5 = GLFW_KEY_F5, 70 | F6 = GLFW_KEY_F6, 71 | F7 = GLFW_KEY_F7, 72 | F8 = GLFW_KEY_F8, 73 | F9 = GLFW_KEY_F9, 74 | F10 = GLFW_KEY_F10, 75 | F11 = GLFW_KEY_F11, 76 | F12 = GLFW_KEY_F12, 77 | Pause = GLFW_KEY_PAUSE, 78 | 79 | Num0 = GLFW_KEY_KP_0, 80 | Num1 = GLFW_KEY_KP_1, 81 | Num2 = GLFW_KEY_KP_2, 82 | Num3 = GLFW_KEY_KP_3, 83 | Num4 = GLFW_KEY_KP_4, 84 | Num5 = GLFW_KEY_KP_5, 85 | Num6 = GLFW_KEY_KP_6, 86 | Num7 = GLFW_KEY_KP_7, 87 | Num8 = GLFW_KEY_KP_8, 88 | Num9 = GLFW_KEY_KP_9, 89 | NumLock = GLFW_KEY_NUM_LOCK, 90 | NumSub = GLFW_KEY_KP_SUBTRACT, 91 | NumAdd = GLFW_KEY_KP_ADD, 92 | NumDel = GLFW_KEY_KP_DECIMAL, 93 | NumMul = GLFW_KEY_KP_MULTIPLY, 94 | NumDiv = GLFW_KEY_KP_DIVIDE, 95 | NumEnter = GLFW_KEY_KP_ENTER, 96 | 97 | LControl = GLFW_KEY_LEFT_CONTROL, 98 | RControl = GLFW_KEY_RIGHT_CONTROL, 99 | LAlt = GLFW_KEY_LEFT_ALT, 100 | RAlt = GLFW_KEY_RIGHT_ALT, 101 | LShift = GLFW_KEY_LEFT_SHIFT, 102 | RShift = GLFW_KEY_RIGHT_SHIFT, 103 | LBracket = GLFW_KEY_LEFT_BRACKET, 104 | RBracket = GLFW_KEY_RIGHT_BRACKET, 105 | 106 | Scroll = GLFW_KEY_SCROLL_LOCK, 107 | Tab = GLFW_KEY_TAB, 108 | Return = GLFW_KEY_ENTER, 109 | Semicolon = GLFW_KEY_SEMICOLON, 110 | Apostrophe = GLFW_KEY_APOSTROPHE, 111 | BackSlash = GLFW_KEY_BACKSLASH, 112 | Comma = GLFW_KEY_COMMA, 113 | Period = GLFW_KEY_PERIOD, 114 | Slash = GLFW_KEY_SLASH, 115 | Space = GLFW_KEY_SPACE, 116 | Capital = GLFW_KEY_CAPS_LOCK, 117 | 118 | Insert = GLFW_KEY_INSERT, 119 | Del = GLFW_KEY_DELETE, 120 | Home = GLFW_KEY_HOME, 121 | End = GLFW_KEY_END, 122 | PageUp = GLFW_KEY_PAGE_UP, 123 | PageDown = GLFW_KEY_PAGE_DOWN, 124 | 125 | Left = GLFW_KEY_LEFT, 126 | Right = GLFW_KEY_RIGHT, 127 | Up = GLFW_KEY_UP, 128 | Down = GLFW_KEY_DOWN, 129 | 130 | NUM = GLFW_KEY_LAST 131 | }; 132 | -------------------------------------------------------------------------------- /Include/Helper.h: -------------------------------------------------------------------------------- 1 | // © 2021 NVIDIA Corporation 2 | 3 | #pragma once 4 | 5 | namespace helper { 6 | template 7 | constexpr T Align(T x, A alignment) { 8 | return (T)((size_t(x) + (size_t)alignment - 1) & ~((size_t)alignment - 1)); 9 | } 10 | 11 | template 12 | constexpr uint32_t GetCountOf(T const (&)[N]) { 13 | return N; 14 | } 15 | 16 | template 17 | constexpr uint32_t GetCountOf(const std::vector& v) { 18 | return (uint32_t)v.size(); 19 | } 20 | 21 | template 22 | constexpr uint32_t GetCountOf(const std::array& v) { 23 | return (uint32_t)v.size(); 24 | } 25 | 26 | template 27 | constexpr uint32_t GetOffsetOf(U T::* member) { 28 | return (uint32_t)((char*)&((T*)nullptr->*member) - (char*)nullptr); 29 | } 30 | 31 | template 32 | constexpr size_t GetByteSizeOf(const std::vector& v) { 33 | return v.size() * sizeof(decltype(v.back())); 34 | } 35 | 36 | struct Annotation { 37 | const nri::CoreInterface& m_NRI; 38 | nri::CommandBuffer& m_CommandBuffer; 39 | 40 | inline Annotation(const nri::CoreInterface& NRI, nri::CommandBuffer& commandBuffer, const char* name) 41 | : m_NRI(NRI), m_CommandBuffer(commandBuffer) { 42 | m_NRI.CmdBeginAnnotation(m_CommandBuffer, name, nri::BGRA_UNUSED); 43 | } 44 | 45 | inline ~Annotation() { 46 | m_NRI.CmdEndAnnotation(m_CommandBuffer); 47 | } 48 | }; 49 | } // namespace helper 50 | -------------------------------------------------------------------------------- /Include/NRIFramework.h: -------------------------------------------------------------------------------- 1 | // © 2021 NVIDIA Corporation 2 | 3 | #pragma once 4 | 5 | #define NRI_FRAMEWORK_VERSION_MAJOR 0 6 | #define NRI_FRAMEWORK_VERSION_MINOR 20 7 | #define NRI_FRAMEWORK_VERSION_DATE "28 April 2025" 8 | #define NRI_FRAMEWORK 1 9 | 10 | // Platform detection 11 | #define NRIF_WINDOWS 0 12 | #define NRIF_X11 1 13 | #define NRIF_WAYLAND 2 14 | #define NRIF_COCOA 3 15 | 16 | #if defined(_WIN32) 17 | # define NRIF_PLATFORM NRIF_WINDOWS 18 | # define GLFW_EXPOSE_NATIVE_WIN32 19 | # define VK_USE_PLATFORM_WIN32_KHR 20 | #elif defined(__APPLE__) 21 | # define NRIF_PLATFORM NRIF_COCOA 22 | # define GLFW_EXPOSE_NATIVE_COCOA 23 | # define VK_USE_PLATFORM_METAL_EXT 24 | #elif (defined(__linux__) && NRIF_USE_WAYLAND) 25 | # define NRIF_PLATFORM NRIF_WAYLAND 26 | # define GLFW_EXPOSE_NATIVE_WAYLAND 27 | # define VK_USE_PLATFORM_WAYLAND_KHR 28 | #elif (defined(__linux__)) 29 | # define NRIF_PLATFORM NRIF_X11 30 | # define GLFW_EXPOSE_NATIVE_X11 31 | # define VK_USE_PLATFORM_XLIB_KHR 32 | #else 33 | # error "Unknown platform" 34 | #endif 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // 3rd party 43 | #define GLFW_INCLUDE_NONE 44 | #include "GLFW/glfw3.h" 45 | #include "imgui.h" 46 | 47 | // NRI: core & common extensions 48 | #include "NRI.h" 49 | 50 | #include "Extensions/NRIDeviceCreation.h" 51 | #include "Extensions/NRIHelper.h" 52 | #include "Extensions/NRIImgui.h" 53 | #include "Extensions/NRILowLatency.h" 54 | #include "Extensions/NRIMeshShader.h" 55 | #include "Extensions/NRIRayTracing.h" 56 | #include "Extensions/NRIResourceAllocator.h" 57 | #include "Extensions/NRIStreamer.h" 58 | #include "Extensions/NRISwapChain.h" 59 | #include "Extensions/NRIUpscaler.h" 60 | 61 | // 3rd party 62 | #include "CmdLine.h" // https://github.com/tanakh/cmdline 63 | 64 | #include "ml.h" 65 | #include "ml.hlsli" 66 | 67 | // NRI framework 68 | #include "Camera.h" 69 | #include "Controls.h" 70 | #include "Helper.h" 71 | #include "Timer.h" 72 | #include "Utils.h" 73 | 74 | // Settings 75 | constexpr nri::VKBindingOffsets VK_BINDING_OFFSETS = {0, 128, 32, 64}; // see CMake 76 | constexpr bool D3D11_COMMANDBUFFER_EMULATION = false; 77 | 78 | struct SwapChainTexture { 79 | nri::Fence* acquireSemaphore; 80 | nri::Fence* releaseSemaphore; 81 | nri::Texture* texture; 82 | nri::Descriptor* colorAttachment; 83 | nri::Format attachmentFormat; 84 | }; 85 | 86 | class SampleBase { 87 | public: 88 | // Pre initialize 89 | SampleBase(); 90 | 91 | virtual void InitCmdLine([[maybe_unused]] cmdline::parser& cmdLine) { 92 | } 93 | 94 | virtual void ReadCmdLine([[maybe_unused]] cmdline::parser& cmdLine) { 95 | } 96 | 97 | // Initialize 98 | virtual bool Initialize(nri::GraphicsAPI graphicsAPI) = 0; 99 | bool InitImgui(nri::Device& device); 100 | 101 | // Wait before input (wait for latency and/or queued frames) 102 | virtual void LatencySleep([[maybe_unused]] uint32_t frameIndex) { 103 | } 104 | 105 | // Prepare 106 | virtual void PrepareFrame([[maybe_unused]] uint32_t frameIndex) { 107 | } 108 | 109 | void GetCameraDescFromInputDevices(CameraDesc& cameraDesc); 110 | 111 | // Render 112 | virtual void RenderFrame(uint32_t frameIndex) = 0; 113 | void RenderImgui(nri::CommandBuffer& commandBuffer, nri::Streamer& streamer, nri::Format attachmentFormat, float sdrScale, bool isSrgb); 114 | 115 | // Destroy 116 | virtual ~SampleBase(); 117 | void DestroyImgui(); 118 | 119 | // Misc 120 | virtual bool AppShouldClose() { 121 | return false; 122 | } 123 | 124 | inline bool IsKeyToggled(Key key) { 125 | bool state = m_KeyToggled[(uint32_t)key]; 126 | m_KeyToggled[(uint32_t)key] = false; 127 | 128 | return state; 129 | } 130 | 131 | inline bool IsKeyPressed(Key key) const { 132 | return m_KeyState[(uint32_t)key]; 133 | } 134 | 135 | inline bool IsButtonPressed(Button button) const { 136 | return m_ButtonState[(uint8_t)button]; 137 | } 138 | 139 | inline const float2& GetMouseDelta() const { 140 | return m_MouseDelta; 141 | } 142 | 143 | inline float GetMouseWheel() const { 144 | return m_MouseWheel; 145 | } 146 | 147 | inline uint2 GetWindowResolution() const { 148 | return m_WindowResolution; 149 | } 150 | 151 | inline uint2 GetOutputResolution() const { 152 | return m_OutputResolution; 153 | } 154 | 155 | inline const nri::Window& GetWindow() const { 156 | return m_NRIWindow; 157 | } 158 | 159 | inline uint8_t GetQueuedFrameNum() const { 160 | return m_VsyncInterval ? 2 : 3; 161 | } 162 | 163 | inline uint8_t GetOptimalSwapChainTextureNum() const { 164 | return GetQueuedFrameNum() + 1; 165 | } 166 | 167 | static void EnableMemoryLeakDetection(uint32_t breakOnAllocationIndex); 168 | 169 | protected: 170 | nri::AllocationCallbacks m_AllocationCallbacks = {}; 171 | std::string m_SceneFile = "ShaderBalls/ShaderBalls.gltf"; 172 | GLFWwindow* m_Window = nullptr; 173 | Camera m_Camera; 174 | Timer m_Timer; 175 | uint2 m_OutputResolution = {1920, 1080}; 176 | uint2 m_WindowResolution = {}; 177 | uint8_t m_VsyncInterval = 0; 178 | uint32_t m_DpiMode = 0; 179 | uint32_t m_RngState = 0; 180 | uint32_t m_AdapterIndex = 0; 181 | float m_MouseSensitivity = 1.0f; 182 | bool m_DebugAPI = false; 183 | bool m_DebugNRI = false; 184 | bool m_AlwaysActive = false; 185 | 186 | // Private 187 | private: 188 | void CursorMode(int32_t mode); 189 | 190 | public: 191 | inline bool HasUserInterface() const { 192 | return m_ImguiRenderer != nullptr; 193 | } 194 | 195 | void InitCmdLineDefault(cmdline::parser& cmdLine); 196 | void ReadCmdLineDefault(cmdline::parser& cmdLine); 197 | bool Create(int32_t argc, char** argv, const char* windowTitle); 198 | void RenderLoop(); 199 | 200 | // Input (not public) 201 | public: 202 | std::array m_KeyState = {}; 203 | std::array m_KeyToggled = {}; 204 | std::array m_ButtonState = {}; 205 | float2 m_MouseDelta = {}; 206 | float2 m_MousePosPrev = {}; 207 | float m_MouseWheel = 0.0f; 208 | 209 | private: 210 | // UI 211 | nri::ImguiInterface m_iImgui = {}; 212 | nri::Imgui* m_ImguiRenderer = nullptr; 213 | GLFWcursor* m_MouseCursors[ImGuiMouseCursor_COUNT] = {}; 214 | 215 | // Rendering 216 | nri::Window m_NRIWindow = {}; 217 | double m_TimeLimit = 1e38; 218 | uint32_t m_FrameNum = uint32_t(-1); 219 | }; 220 | 221 | #define _STRINGIFY(s) #s 222 | #define STRINGIFY(s) _STRINGIFY(s) 223 | 224 | #define NRI_ABORT_ON_FAILURE(result) \ 225 | if ((result) != nri::Result::SUCCESS) { \ 226 | exit(1); \ 227 | } 228 | 229 | #define NRI_ABORT_ON_FALSE(result) \ 230 | if (!(result)) { \ 231 | exit(1); \ 232 | } 233 | 234 | #define SAMPLE_MAIN(className, memoryAllocationIndexForBreak) \ 235 | SampleBase* g_sample = nullptr; \ 236 | void Destroy() { \ 237 | if (g_sample) \ 238 | delete g_sample; \ 239 | } \ 240 | int main(int argc, char** argv) { \ 241 | SampleBase::EnableMemoryLeakDetection(memoryAllocationIndexForBreak); \ 242 | g_sample = new className; \ 243 | atexit(Destroy); \ 244 | bool result = g_sample->Create(argc, argv, STRINGIFY(PROJECT_NAME)); \ 245 | if (result) \ 246 | g_sample->RenderLoop(); \ 247 | return result ? 0 : 1; \ 248 | } 249 | -------------------------------------------------------------------------------- /Include/Timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Timer { 6 | public: 7 | Timer(); 8 | 9 | void UpdateFrameTime(); 10 | 11 | // In milliseconds 12 | double GetTimeStamp() const; 13 | 14 | inline double GetLastFrameTimeStamp() const { 15 | return m_Time * m_InvTicksPerMs; 16 | } 17 | 18 | inline float GetFrameTime() const { 19 | return m_Delta; 20 | } 21 | 22 | inline float GetSmoothedFrameTime() const { 23 | return m_SmoothedDelta; 24 | } 25 | 26 | inline float GetVerySmoothedFrameTime() const { 27 | return m_VerySmoothedDelta; 28 | } 29 | 30 | private: 31 | uint64_t m_Time = 0; 32 | double m_InvTicksPerMs = 0.0; 33 | float m_Delta = 1.0f; 34 | float m_SmoothedDelta = 1.0f; 35 | float m_VerySmoothedDelta = 1.0f; 36 | }; -------------------------------------------------------------------------------- /Include/Utils.h: -------------------------------------------------------------------------------- 1 | // © 2021 NVIDIA Corporation 2 | 3 | #pragma once 4 | 5 | #undef OPAQUE 6 | #undef TRANSPARENT 7 | 8 | namespace utils { 9 | struct Texture; 10 | struct Scene; 11 | 12 | typedef std::vector> ShaderCodeStorage; 13 | typedef void* Mip; 14 | typedef uint32_t Index; 15 | 16 | constexpr uint32_t InvalidIndex = uint32_t(-1); 17 | 18 | enum StaticTexture : uint32_t { 19 | Black, 20 | White, 21 | Invalid, 22 | FlatNormal, 23 | ScramblingRanking, 24 | SobolSequence 25 | }; 26 | 27 | enum class AlphaMode : uint32_t { 28 | OPAQUE, 29 | PREMULTIPLIED, 30 | TRANSPARENT, 31 | OFF // alpha is 0 everywhere 32 | }; 33 | 34 | enum class DataFolder : uint8_t { 35 | ROOT, 36 | SHADERS, 37 | TEXTURES, 38 | SCENES, 39 | TESTS 40 | }; 41 | 42 | enum class AnimationTrackType : uint8_t { 43 | Step, 44 | Linear, 45 | CubicSpline 46 | }; 47 | 48 | const char* GetFileName(const std::string& path); 49 | std::string GetFullPath(const std::string& localPath, DataFolder dataFolder); 50 | bool LoadFile(const std::string& path, std::vector& data); 51 | nri::ShaderDesc LoadShader(nri::GraphicsAPI graphicsAPI, const std::string& path, ShaderCodeStorage& storage, const char* entryPointName = nullptr); 52 | bool LoadTexture(const std::string& path, Texture& texture, bool computeAvgColorAndAlphaMode = false); 53 | void LoadTextureFromMemory(nri::Format format, uint32_t width, uint32_t height, const uint8_t* pixels, Texture& texture); 54 | bool LoadTextureFromMemory(const std::string& name, const uint8_t* data, int dataSize, Texture& texture, bool computeAvgColorAndAlphaMode); 55 | bool LoadScene(const std::string& path, Scene& scene, bool allowUpdate); 56 | 57 | struct Texture { 58 | std::string name; 59 | Mip* mips = nullptr; 60 | AlphaMode alphaMode = AlphaMode::OPAQUE; 61 | nri::Format format = nri::Format::UNKNOWN; 62 | uint16_t width = 0; 63 | uint16_t height = 0; 64 | uint16_t depth = 0; 65 | uint8_t mipNum = 0; 66 | uint16_t layerNum = 0; 67 | 68 | ~Texture(); 69 | 70 | bool IsBlockCompressed() const; 71 | void GetSubresource(nri::TextureSubresourceUploadDesc& subresource, uint32_t mipIndex, uint32_t arrayIndex = 0) const; 72 | 73 | inline void OverrideFormat(nri::Format fmt) { 74 | this->format = fmt; 75 | } 76 | 77 | inline uint16_t GetArraySize() const { 78 | return layerNum; 79 | } 80 | 81 | inline uint8_t GetMipNum() const { 82 | return mipNum; 83 | } 84 | 85 | inline uint16_t GetWidth() const { 86 | return width; 87 | } 88 | 89 | inline uint16_t GetHeight() const { 90 | return height; 91 | } 92 | 93 | inline uint16_t GetDepth() const { 94 | return depth; 95 | } 96 | 97 | inline nri::Format GetFormat() const { 98 | return format; 99 | } 100 | }; 101 | 102 | struct Material { 103 | float4 baseColorAndMetalnessScale = float4(1.0f); 104 | float4 emissiveAndRoughnessScale = float4(1.0f); 105 | 106 | uint32_t baseColorTexIndex = StaticTexture::Black; // TODO: use StaticTexture::Invalid for debug purposes 107 | uint32_t roughnessMetalnessTexIndex = StaticTexture::Black; 108 | uint32_t normalTexIndex = StaticTexture::FlatNormal; 109 | uint32_t emissiveTexIndex = StaticTexture::Black; 110 | AlphaMode alphaMode = AlphaMode::OPAQUE; 111 | bool isHair; 112 | bool isLeaf; 113 | 114 | inline bool IsOpaque() const { 115 | return alphaMode == AlphaMode::OPAQUE; 116 | } 117 | 118 | inline bool IsAlphaOpaque() const { 119 | return alphaMode == AlphaMode::PREMULTIPLIED; 120 | } 121 | 122 | inline bool IsTransparent() const { 123 | return alphaMode == AlphaMode::TRANSPARENT; 124 | } 125 | 126 | inline bool IsOff() const { 127 | return alphaMode == AlphaMode::OFF; 128 | } 129 | 130 | inline bool IsEmissive() const { 131 | return emissiveTexIndex != StaticTexture::Black && (emissiveAndRoughnessScale.x != 0.0f || emissiveAndRoughnessScale.y != 0.0f || emissiveAndRoughnessScale.z != 0.0f); 132 | } 133 | }; 134 | 135 | struct Instance { 136 | float4x4 rotation = float4x4::Identity(); 137 | float4x4 rotationPrev = float4x4::Identity(); 138 | double3 position = double3::Zero(); 139 | double3 positionPrev = double3::Zero(); 140 | float3 scale = float3(1.0f); // TODO: needed to generate hulls representing inner glass surfaces 141 | uint32_t meshInstanceIndex = InvalidIndex; 142 | uint32_t materialIndex = InvalidIndex; 143 | bool allowUpdate = false; // if "false" will be merged into the monolithic BLAS together with other static geometry 144 | }; 145 | 146 | // static mesh data shared across mesh instances 147 | struct Mesh { 148 | cBoxf aabb; // must be manually adjusted by instance.rotation.GetScale() 149 | uint32_t vertexOffset = 0; 150 | uint32_t indexOffset = 0; 151 | uint32_t indexNum = 0; 152 | uint32_t vertexNum = 0; 153 | 154 | uint32_t morphMeshIndexOffset = InvalidIndex; 155 | uint32_t morphTargetVertexOffset = InvalidIndex; 156 | uint32_t morphTargetNum = 0; 157 | 158 | inline bool HasMorphTargets() const { 159 | return morphTargetNum != 0; 160 | } 161 | }; 162 | 163 | // per mesh instance data 164 | struct MeshInstance { 165 | uint32_t meshIndex = 0; 166 | uint32_t primitiveOffset = 0; 167 | uint32_t morphedVertexOffset = InvalidIndex; 168 | uint32_t morphedPrimitiveOffset = InvalidIndex; 169 | uint32_t blasIndex = InvalidIndex; // BLAS index for dynamic geometry in a user controlled array 170 | }; 171 | 172 | struct Vertex { 173 | float pos[3]; 174 | float16_t2 uv; 175 | uint32_t N; // 10 10 10 2 unorm 176 | uint32_t T; // 10 10 10 2 unorm (.w - handedness) 177 | }; 178 | 179 | struct MorphVertex { 180 | float16_t4 pos; 181 | float16_t2 N; 182 | float16_t2 T; 183 | }; 184 | 185 | struct UnpackedVertex { 186 | float pos[3]; 187 | float uv[2]; 188 | float N[3]; 189 | float T[4]; 190 | }; 191 | 192 | struct Primitive { 193 | float worldArea; 194 | float uvArea; 195 | }; 196 | 197 | struct SceneNode { 198 | std::vector children; 199 | std::vector instances; 200 | std::string name; 201 | SceneNode* parent = nullptr; 202 | float4x4 localTransform; 203 | float4x4 worldTransform; 204 | float4 rotation; 205 | float3 translation; 206 | float3 scale; 207 | }; 208 | 209 | struct VectorAnimationTrack { 210 | std::vector keys; 211 | std::vector values; 212 | SceneNode* node = nullptr; 213 | uint32_t frameCount = 0; 214 | AnimationTrackType type = AnimationTrackType::Linear; 215 | }; 216 | 217 | struct QuatAnimationTrack { 218 | std::vector keys; 219 | std::vector values; 220 | SceneNode* node = nullptr; 221 | uint32_t frameCount = 0; 222 | AnimationTrackType type = AnimationTrackType::Linear; 223 | }; 224 | 225 | typedef std::pair MorphTargetIndexWeight; 226 | 227 | struct WeightsAnimationTrack { 228 | std::vector keys; 229 | std::vector> values; 230 | std::vector activeValues; 231 | 232 | uint32_t frameCount = 0; 233 | AnimationTrackType type = AnimationTrackType::Linear; 234 | }; 235 | 236 | struct WeightTrackMorphMeshIndex { 237 | uint32_t weightTrackIndex = InvalidIndex; 238 | uint32_t meshInstanceIndex = InvalidIndex; 239 | }; 240 | 241 | struct Animation { 242 | std::vector sceneNodes; 243 | std::vector dynamicNodes; 244 | std::vector positionTracks; 245 | std::vector rotationTracks; 246 | std::vector scaleTracks; 247 | std::vector weightTracks; 248 | std::vector morphMeshInstances; 249 | std::string name; 250 | float durationMs = 0.0f; 251 | float animationProgress = 0.0f; 252 | float sign = 1.0f; 253 | float animationTimeSec = 0.0f; 254 | }; 255 | 256 | struct Scene { 257 | ~Scene() { 258 | UnloadTextureData(); 259 | } 260 | 261 | // Transient resources - texture & geometry data (can be unloaded after uploading on GPU) 262 | std::vector textures; 263 | std::vector vertices; 264 | std::vector unpackedVertices; 265 | std::vector indices; 266 | std::vector primitives; 267 | std::vector morphVertices; 268 | 269 | // Other resources 270 | std::vector materials; 271 | std::vector instances; 272 | std::vector meshes; 273 | std::vector meshInstances; 274 | std::vector animations; 275 | std::vector morphMeshes; 276 | float4x4 mSceneToWorld = float4x4::Identity(); 277 | cBoxf aabb; 278 | 279 | uint32_t totalInstancedPrimitivesNum = 0; 280 | uint32_t morphMeshTotalIndicesNum = 0; 281 | uint32_t morphedVerticesNum = 0; 282 | uint32_t morphedPrimitivesNum = 0; 283 | 284 | void Animate(float animationSpeed, float elapsedTime, float& animationProgress, uint32_t animationIndex); 285 | 286 | inline void UnloadTextureData() { 287 | for (auto texture : textures) 288 | delete texture; 289 | 290 | textures.resize(0); 291 | textures.shrink_to_fit(); 292 | } 293 | 294 | inline void UnloadGeometryData() { 295 | vertices.resize(0); 296 | vertices.shrink_to_fit(); 297 | 298 | unpackedVertices.resize(0); 299 | unpackedVertices.shrink_to_fit(); 300 | 301 | indices.resize(0); 302 | indices.shrink_to_fit(); 303 | 304 | primitives.resize(0); 305 | primitives.shrink_to_fit(); 306 | 307 | morphVertices.resize(0); 308 | morphVertices.shrink_to_fit(); 309 | } 310 | }; 311 | } // namespace utils 312 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NRI framework 2 | 3 | It's a simple sandbox for developement of sample applications based on [*NRI (NVIDIA Rendering Interface)*](https://github.com/NVIDIA-RTX/NRI) -------------------------------------------------------------------------------- /Source/Camera.cpp: -------------------------------------------------------------------------------- 1 | // © 2021 NVIDIA Corporation 2 | 3 | #include "NRIFramework.h" 4 | 5 | void Camera::Initialize(const float3& position, const float3& lookAt, bool isRelative) { 6 | float3 dir = normalize(lookAt - position); 7 | 8 | float3 rot; 9 | rot.x = atan2(dir.y, dir.x); 10 | rot.y = asin(dir.z); 11 | rot.z = 0.0f; 12 | 13 | state.globalPosition = double3(position); 14 | state.rotation = degrees(rot); 15 | m_IsRelative = isRelative; 16 | } 17 | 18 | void Camera::InitializeWithRotation(const float3& position, const float3& rotation, bool isRelative) { 19 | state.globalPosition = double3(position); 20 | state.rotation = rotation; 21 | m_IsRelative = isRelative; 22 | } 23 | 24 | void Camera::Update(const CameraDesc& desc, uint32_t frameIndex) { 25 | uint32_t projFlags = desc.isReversedZ ? PROJ_REVERSED_Z : 0; 26 | projFlags |= desc.isPositiveZ ? PROJ_LEFT_HANDED : 0; 27 | 28 | // Position 29 | const float3 vRight = state.mWorldToView.Row(0).xyz; 30 | const float3 vUp = state.mWorldToView.Row(1).xyz; 31 | const float3 vForward = state.mWorldToView.Row(2).xyz; 32 | 33 | float3 delta = desc.dLocal * desc.timeScale; 34 | delta.z *= desc.isPositiveZ ? 1.0f : -1.0f; 35 | 36 | state.globalPosition += double3(vRight * delta.x); 37 | state.globalPosition += double3(vUp * delta.y); 38 | state.globalPosition += double3(vForward * delta.z); 39 | state.globalPosition += double3(desc.dUser); 40 | 41 | if (desc.limits.IsValid()) 42 | state.globalPosition = clamp(state.globalPosition, double3(desc.limits.vMin), double3(desc.limits.vMax)); 43 | 44 | if (desc.isCustomMatrixSet) { 45 | const float3 vCustomRight = desc.customMatrix.Row(3).xyz; 46 | state.globalPosition = double3(vCustomRight); 47 | } 48 | 49 | if (m_IsRelative) { 50 | state.position = float3::Zero(); 51 | statePrev.position = float3(statePrev.globalPosition - state.globalPosition); 52 | statePrev.mWorldToView.PreTranslation(-statePrev.position); 53 | } else { 54 | state.position = float3(state.globalPosition); 55 | statePrev.position = float3(statePrev.globalPosition); 56 | } 57 | 58 | // Rotation 59 | float angularSpeed = 0.03f * saturate(desc.horizontalFov * 0.5f / 90.0f); 60 | 61 | state.rotation.x += desc.dYaw * angularSpeed; 62 | state.rotation.y += desc.dPitch * angularSpeed; 63 | 64 | state.rotation.x = fmodf(state.rotation.x, 360.0f); 65 | state.rotation.y = clamp(state.rotation.y, -90.0f, 90.0f); 66 | 67 | if (desc.isCustomMatrixSet) { 68 | state.mViewToWorld = desc.customMatrix; 69 | 70 | state.rotation = degrees(state.mViewToWorld.GetRotationYPR()); 71 | state.rotation.z = 0.0f; 72 | } else 73 | state.mViewToWorld.SetupByRotationYPR(radians(state.rotation.x), radians(state.rotation.y), radians(state.rotation.z)); 74 | 75 | state.mWorldToView = state.mViewToWorld; 76 | state.mWorldToView.PreTranslation(float3(state.mWorldToView.Row(2).xyz) * desc.backwardOffset); 77 | state.mWorldToView.WorldToView(projFlags); 78 | state.mWorldToView.PreTranslation(-state.position); 79 | 80 | // Projection 81 | if (desc.orthoRange > 0.0f) { 82 | float x = desc.orthoRange; 83 | float y = desc.orthoRange / desc.aspectRatio; 84 | state.mViewToClip.SetupByOrthoProjection(-x, x, -y, y, desc.nearZ, desc.farZ, projFlags); 85 | } else { 86 | if (desc.farZ == 0.0f) 87 | state.mViewToClip.SetupByHalfFovxInf(0.5f * radians(desc.horizontalFov), desc.aspectRatio, desc.nearZ, projFlags); 88 | else 89 | state.mViewToClip.SetupByHalfFovx(0.5f * radians(desc.horizontalFov), desc.aspectRatio, desc.nearZ, desc.farZ, projFlags); 90 | } 91 | 92 | // Other 93 | state.mWorldToClip = state.mViewToClip * state.mWorldToView; 94 | 95 | state.mViewToWorld = state.mWorldToView; 96 | state.mViewToWorld.InvertOrtho(); 97 | 98 | state.mClipToView = state.mViewToClip; 99 | state.mClipToView.Invert(); 100 | 101 | state.mClipToWorld = state.mWorldToClip; 102 | state.mClipToWorld.Invert(); 103 | 104 | state.viewportJitter = Sequence::Halton2D(frameIndex) - 0.5f; 105 | 106 | // Previous other 107 | statePrev.mWorldToClip = statePrev.mViewToClip * statePrev.mWorldToView; 108 | 109 | statePrev.mViewToWorld = statePrev.mWorldToView; 110 | statePrev.mViewToWorld.InvertOrtho(); 111 | 112 | statePrev.mClipToWorld = statePrev.mWorldToClip; 113 | statePrev.mClipToWorld.Invert(); 114 | } 115 | -------------------------------------------------------------------------------- /Source/DebugAllocator.cpp: -------------------------------------------------------------------------------- 1 | #if _WIN32 2 | # include 3 | #endif 4 | 5 | #include 6 | 7 | #include "NRIFramework.h" 8 | 9 | struct DebugAllocator { 10 | std::atomic_uint64_t allocationNum = 0; 11 | std::atomic_size_t allocatedSize = 0; 12 | }; 13 | 14 | struct DebugAllocatorHeader { 15 | size_t size; 16 | uint32_t alignment; 17 | uint32_t offset; 18 | }; 19 | 20 | inline void ReportAllocatorError(const char* message) { 21 | #if _WIN32 22 | OutputDebugStringA(message); 23 | #endif 24 | std::cout << message; 25 | std::abort(); 26 | } 27 | 28 | inline DebugAllocatorHeader* GetAllocationHeader(void* memory) { 29 | return (DebugAllocatorHeader*)memory - 1; 30 | } 31 | 32 | static void* DebugAlignedMalloc(void* userArg, size_t size, size_t alignment) { 33 | DebugAllocator* allocator = (DebugAllocator*)userArg; 34 | 35 | if (alignment == 0) 36 | ReportAllocatorError("DebugAlignedMalloc() failed: alignment can't be 0.\n"); 37 | 38 | const size_t alignedHeaderSize = helper::Align(sizeof(DebugAllocatorHeader), alignment); 39 | const size_t allocationSize = size + alignment - 1 + alignedHeaderSize; 40 | 41 | uint8_t* memory = (uint8_t*)malloc(allocationSize); 42 | 43 | if (memory == nullptr) 44 | return nullptr; 45 | 46 | uint8_t* alignedMemory = helper::Align(memory, alignment) + alignedHeaderSize; 47 | 48 | DebugAllocatorHeader* header = GetAllocationHeader(alignedMemory); 49 | *header = {}; 50 | header->size = allocationSize; 51 | header->alignment = (uint32_t)alignment; 52 | header->offset = (uint32_t)(alignedMemory - memory); 53 | 54 | allocator->allocatedSize.fetch_add(allocationSize, std::memory_order_relaxed); 55 | allocator->allocationNum.fetch_add(1, std::memory_order_relaxed); 56 | 57 | return alignedMemory; 58 | } 59 | 60 | static void* DebugAlignedRealloc(void* userArg, void* memory, size_t size, size_t alignment) { 61 | DebugAllocator* allocator = (DebugAllocator*)userArg; 62 | 63 | if (alignment == 0) 64 | ReportAllocatorError("DebugAlignedRealloc() failed: alignment can't be 0.\n"); 65 | 66 | if (memory == nullptr) 67 | return DebugAlignedMalloc(userArg, size, alignment); 68 | 69 | const DebugAllocatorHeader prevHeader = *GetAllocationHeader(memory); 70 | 71 | if (prevHeader.alignment != alignment) 72 | ReportAllocatorError("DebugAlignedRealloc() failed: memory alignment mismatch.\n"); 73 | 74 | const size_t alignedHeaderSize = helper::Align(sizeof(DebugAllocatorHeader), alignment); 75 | const size_t allocationSize = size + alignment - 1 + alignedHeaderSize; 76 | 77 | uint8_t* prevMemoryBegin = (uint8_t*)memory - prevHeader.offset; 78 | 79 | uint8_t* newMemory = (uint8_t*)realloc(prevMemoryBegin, allocationSize); 80 | 81 | if (newMemory == nullptr) 82 | return nullptr; 83 | 84 | uint8_t* alignedMemory = helper::Align(newMemory, alignment) + alignedHeaderSize; 85 | 86 | allocator->allocatedSize.fetch_add(allocationSize - prevHeader.size, std::memory_order_relaxed); 87 | 88 | DebugAllocatorHeader* newHeader = GetAllocationHeader(alignedMemory); 89 | *newHeader = {}; 90 | newHeader->size = allocationSize; 91 | newHeader->alignment = (uint32_t)alignment; 92 | newHeader->offset = (uint32_t)(alignedMemory - newMemory); 93 | 94 | return alignedMemory; 95 | } 96 | 97 | static void DebugAlignedFree(void* userArg, void* memory) { 98 | if (memory == nullptr) 99 | return; 100 | 101 | const DebugAllocatorHeader* header = GetAllocationHeader(memory); 102 | 103 | DebugAllocator* allocator = (DebugAllocator*)userArg; 104 | const size_t allocatedSize = allocator->allocatedSize.fetch_sub(header->size, std::memory_order_relaxed); 105 | const size_t allocationNum = allocator->allocationNum.fetch_sub(1, std::memory_order_relaxed); 106 | 107 | if (allocatedSize < header->size) 108 | ReportAllocatorError("DebugAlignedFree() failed: invalid allocated size.\n"); 109 | if (allocationNum == 0) 110 | ReportAllocatorError("DebugAlignedFree() failed: invalid allocation number.\n"); 111 | 112 | free((uint8_t*)memory - header->offset); 113 | } 114 | 115 | void CreateDebugAllocator(nri::AllocationCallbacks& allocationCallbacks) { 116 | allocationCallbacks = {}; 117 | allocationCallbacks.userArg = new DebugAllocator(); 118 | allocationCallbacks.Allocate = DebugAlignedMalloc; 119 | allocationCallbacks.Reallocate = DebugAlignedRealloc; 120 | allocationCallbacks.Free = DebugAlignedFree; 121 | } 122 | 123 | void DestroyDebugAllocator(nri::AllocationCallbacks& allocationCallbacks) { 124 | DebugAllocator* debugAllocator = (DebugAllocator*)allocationCallbacks.userArg; 125 | 126 | if (debugAllocator->allocatedSize.load(std::memory_order_relaxed) != 0) 127 | ReportAllocatorError("DestroyDebugAllocator() failed: allocatedSize is not 0.\n"); 128 | if (debugAllocator->allocationNum.load(std::memory_order_relaxed) != 0) 129 | ReportAllocatorError("DestroyDebugAllocator() failed: allocationNum is not 0.\n"); 130 | 131 | delete debugAllocator; 132 | } 133 | -------------------------------------------------------------------------------- /Source/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "Timer.h" 2 | 3 | #include 4 | 5 | #if defined(_WIN32) 6 | # include 7 | #elif defined(__linux__) || defined(__SCE__) || defined(__APPLE__) 8 | # include 9 | # ifdef USE_MONOTONIC_TIMER 10 | constexpr clockid_t CLOCKID = CLOCK_MONOTONIC; 11 | # else 12 | constexpr clockid_t CLOCKID = CLOCK_REALTIME; 13 | # endif 14 | #else 15 | # error "Undefined platform" 16 | #endif 17 | 18 | #define MY_MIN(a, b) (a < b ? a : b) 19 | #define MY_MAX(a, b) (a > b ? a : b) 20 | 21 | inline uint64_t _GetTicks() { 22 | #if defined(_WIN32) 23 | uint64_t ticks; 24 | QueryPerformanceCounter((LARGE_INTEGER*)&ticks); 25 | return ticks; 26 | #elif defined(__linux__) || defined(__SCE__) || defined(__APPLE__) 27 | struct timespec spec; 28 | clock_gettime(CLOCKID, &spec); 29 | return uint64_t(spec.tv_sec) * 1000000000ull + spec.tv_nsec; 30 | #endif 31 | } 32 | 33 | Timer::Timer() { 34 | #if defined(_WIN32) 35 | uint64_t ticksPerSecond = 1; 36 | QueryPerformanceFrequency((LARGE_INTEGER*)&ticksPerSecond); 37 | 38 | m_InvTicksPerMs = 1000.0 / ticksPerSecond; 39 | #elif defined(__linux__) || defined(__SCE__) || defined(__APPLE__) 40 | m_InvTicksPerMs = 1.0 / 1000000.0; 41 | #endif 42 | } 43 | 44 | void Timer::UpdateFrameTime() { 45 | if (m_Time != 0) { 46 | double ms = (_GetTicks() - m_Time) * m_InvTicksPerMs; 47 | m_Delta = float(ms); 48 | 49 | float relativeDelta = fabsf(m_Delta - m_SmoothedDelta) / (MY_MIN(m_Delta, m_SmoothedDelta) + 1e-7f); 50 | float f = relativeDelta / (1.0f + relativeDelta); 51 | 52 | m_SmoothedDelta = m_SmoothedDelta + (m_Delta - m_SmoothedDelta) * MY_MAX(f, 1.0f / 32.0f); 53 | m_VerySmoothedDelta = m_VerySmoothedDelta + (m_Delta - m_VerySmoothedDelta) * MY_MAX(f, 1.0f / 64.0f); 54 | } 55 | 56 | m_Time = _GetTicks(); 57 | } 58 | 59 | double Timer::GetTimeStamp() const { 60 | return _GetTicks() * m_InvTicksPerMs; 61 | } 62 | --------------------------------------------------------------------------------